library(tidyverse)
## ── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
## ✔ ggplot2 3.3.1     ✔ purrr   0.3.4
## ✔ tibble  3.0.6     ✔ dplyr   1.0.4
## ✔ tidyr   1.1.0     ✔ stringr 1.4.0
## ✔ readr   1.3.1     ✔ forcats 0.5.0
## ── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(jsonlite)
## 
## Attaching package: 'jsonlite'
## The following object is masked from 'package:purrr':
## 
##     flatten
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union

Web API (Application Programming Interface)

This section lists some examples of public HTTP APIs that publish data in JSON format. These are great to get a sense of the complex structures that are encountered in real world JSON data.

See also https://github.com/public-apis/public-apis for a list of public APIs.

APIs that do not require authentication

CitiBike NYC

A single public API that shows location, status and current availability for all stations in the New York City bike sharing imitative. https://www.citibikenyc.com/system-data

citibike <- fromJSON("https://gbfs.citibikenyc.com/gbfs/en/station_status.json")
citibike$data$stations
##    num_bikes_disabled is_returning last_reported is_renting station_id
## 1                   3            1    1614231603          1         72
## 2                   0            1    1614222616          1         79
## 3                   2            1    1614234378          1         82
## 4                   0            1    1614234376          1         83
## 5                   3            1    1614233781          1        116
## 6                   1            1    1614234375          1        119
## 7                   0            1    1614234375          1        120
## 8                   1            1    1614235584          1        127
## 9                   3            1    1614235583          1        128
## 10                  2            1    1614234376          1        143
## 11                  0            1    1614233120          1        144
## 12                  1            1    1614234376          1        146
## 13                  1            1    1614232473          1        150
## 14                  3            1    1614236349          1        151
## 15                  1            1    1614222888          1        152
##    station_status num_docks_disabled is_installed num_ebikes_available
## 1          active                  0            1                    2
## 2          active                  0            1                    0
## 3          active                  0            1                    2
## 4          active                  0            1                    1
## 5          active                  0            1                    0
## 6          active                  0            1                    4
## 7          active                  0            1                    1
## 8          active                  0            1                    2
## 9          active                  0            1                    0
## 10         active                  0            1                    1
## 11         active                  0            1                    4
## 12         active                  0            1                    2
## 13         active                  0            1                    5
## 14         active                  0            1                    1
## 15         active                  0            1                    0
##    num_bikes_available num_docks_available eightd_has_available_keys legacy_id
## 1                   17                  35                     FALSE        72
## 2                    5                  28                     FALSE        79
## 3                   18                   7                     FALSE        82
## 4                   31                  31                     FALSE        83
## 5                    6                  41                     FALSE       116
## 6                   18                  34                     FALSE       119
## 7                    3                  16                     FALSE       120
## 8                   14                  16                     FALSE       127
## 9                   15                  38                     FALSE       128
## 10                   3                  19                     FALSE       143
## 11                  51                   7                     FALSE       144
## 12                  16                  22                     FALSE       146
## 13                  25                  30                     FALSE       150
## 14                   5                  25                     FALSE       151
## 15                   9                  39                     FALSE       152
##  [ reached 'max' / getOption("max.print") -- omitted 1350 rows ]
with_tz(as_datetime(citibike$last_updated), "US/Pacific")
## [1] "2021-02-24 23:03:55 PST"
citibike %>% glimpse()
## List of 3
##  $ data        :List of 1
##   ..$ stations:'data.frame': 1365 obs. of  13 variables:
##   .. ..$ num_bikes_disabled       : int [1:1365] 3 0 2 0 3 1 0 1 3 2 ...
##   .. ..$ is_returning             : int [1:1365] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ last_reported            : int [1:1365] 1614231603 1614222616 1614234378 1614234376 1614233781 1614234375 1614234375 1614235584 1614235583 1614234376 ...
##   .. ..$ is_renting               : int [1:1365] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ station_id               : chr [1:1365] "72" "79" "82" "83" ...
##   .. ..$ station_status           : chr [1:1365] "active" "active" "active" "active" ...
##   .. ..$ num_docks_disabled       : int [1:1365] 0 0 0 0 0 0 0 0 0 0 ...
##   .. ..$ is_installed             : int [1:1365] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ num_ebikes_available     : int [1:1365] 2 0 2 1 0 4 1 2 0 1 ...
##   .. ..$ num_bikes_available      : int [1:1365] 17 5 18 31 6 18 3 14 15 3 ...
##   .. ..$ num_docks_available      : int [1:1365] 35 28 7 31 41 34 16 16 38 19 ...
##   .. ..$ eightd_has_available_keys: logi [1:1365] FALSE FALSE FALSE FALSE FALSE FALSE ...
##   .. ..$ legacy_id                : chr [1:1365] "72" "79" "82" "83" ...
##  $ last_updated: int 1614236635
##  $ ttl         : int 5
stations <- citibike$data$stations
good_stations <- stations %>%
  filter(num_bikes_available > 0) %>% 
  select(station_id, num_bikes_available)
nrow(good_stations)
## [1] 1274
station_info <- fromJSON("https://gbfs.citibikenyc.com/gbfs/en/station_information.json")
station_info$data$stations %>% 
  inner_join(good_stations, by = "station_id") %>% 
  select(station_id, name, num_bikes_available)
##    station_id                              name num_bikes_available
## 1          72                  W 52 St & 11 Ave                  17
## 2          79          Franklin St & W Broadway                   5
## 3          82            St James Pl & Pearl St                  18
## 4          83     Atlantic Ave & Fort Greene Pl                  31
## 5         116                   W 17 St & 8 Ave                   6
## 6         119          Park Ave & St Edwards St                  18
## 7         120       Lexington Ave & Classon Ave                   3
## 8         127             Barrow St & Hudson St                  14
## 9         128          MacDougal St & Prince St                  15
## 10        143         Clinton St & Joralemon St                   3
## 11        144               Nassau St & Navy St                  51
## 12        146              Hudson St & Reade St                  16
## 13        150                 E 2 St & Avenue C                  25
## 14        151          Cleveland Pl & Spring St                   5
## 15        152            Warren St & W Broadway                   9
## 16        153                   E 40 St & 5 Ave                  29
## 17        157           Henry St & Atlantic Ave                  12
## 18        161             LaGuardia Pl & W 3 St                  22
## 19        164                   E 47 St & 2 Ave                  10
## 20        168                   W 18 St & 6 Ave                  29
## 21        173                Broadway & W 49 St                  24
## 22        174                   E 25 St & 1 Ave                   5
## 23        212           W 16 St & The High Line                  30
## 24        216   Columbia Heights & Cranberry St                   2
## 25        217                     Old Fulton St                  31
## 26        223                   W 13 St & 7 Ave                  22
## 27        224             Spruce St & Nassau St                   4
## 28        228                   E 48 St & 3 Ave                  34
## 29        229                    Great Jones St                   1
## 30        232       Cadman Plaza E & Tillary St                  10
## 31        236               St Marks Pl & 2 Ave                  21
## 32        237                   E 11 St & 2 Ave                  21
## 33        238           Bank St & Washington St                  10
## 34        239          Willoughby St & Fleet St                   7
## 35        241       DeKalb Ave & S Portland Ave                   1
## 36        244          Willoughby Ave & Hall St                   4
## 37        245        Myrtle Ave & St Edwards St                  13
## 38        247            Perry St & Bleecker St                  52
## 39        248             Laight St & Hudson St                  12
## 40        249           Harrison St & Hudson St                   5
## 41        250          Lafayette St & Jersey St                  18
## 42        251               Mott St & Prince St                   8
## 43        252      MacDougal St & Washington Sq                  19
## 44        254                   W 11 St & 6 Ave                   4
## 45        257           Lispenard St & Broadway                  43
## 46        258       DeKalb Ave & Vanderbilt Ave                   4
## 47        259           South St & Whitehall St                  24
## 48        260              Broad St & Bridge St                  21
## 49        261              Johnson St & Gold St                  19
## 50        262                   Washington Park                   7
## 51        264              Maiden Ln & Pearl St                  22
## 52        265          Stanton St & Chrystie St                  21
## 53        267                Broadway & W 36 St                  32
## 54        268             Howard St & Centre St                   2
## 55        270           Adelphi St & Myrtle Ave                  15
## 56        274    Lafayette Ave & Fort Greene Pl                  15
## 57        275       Washington Ave & Greene Ave                   7
## 58        276           Duane St & Greenwich St                   6
## 59        278            Concord St & Bridge St                   7
## 60        281 Grand Army Plaza & Central Park S                  38
## 61        282                Kent Ave & S 11 St                  11
## 62        284             Greenwich Ave & 8 Ave                  20
## 63        285                Broadway & E 14 St                  27
## 64        289           Monroe St & Classon Ave                   4
## 65        291        Madison St & Montgomery St                  17
## 66        293             Lafayette St & E 8 St                   7
##  [ reached 'max' / getOption("max.print") -- omitted 1208 rows ]

OnWater https://onwater.io/

# davis
url <- str_glue(
  "https://api.onwater.io/api/v1/results/{lat},{long}", 
  lat = 38.54491, 
  long = -121.74052)
fromJSON(url)
## $query
## [1] "38.54491,-121.74052"
## 
## $request_id
## [1] "1ac43377-7f18-4c6a-9dba-88be85bad6c4"
## 
## $lat
## [1] 38.54491
## 
## $lon
## [1] -121.7405
## 
## $water
## [1] FALSE
# lake tahoe
url <- str_glue(
  "https://api.onwater.io/api/v1/results/{lat},{long}", 
  lat = 39.0968, 
  long = -120.0324)
fromJSON(url)
## $query
## [1] "39.0968,-120.0324"
## 
## $request_id
## [1] "ff2cfeef-0c16-4262-a1fc-061a613a252e"
## 
## $lat
## [1] 39.0968
## 
## $lon
## [1] -120.0324
## 
## $water
## [1] TRUE

Deck of Cards https://deckofcardsapi.com/

It is a very simple API which suffles cards.

# get a deck
deck <- fromJSON("https://deckofcardsapi.com/api/deck/new/shuffle/?deck_count=1")
# draw two cards
cards <- fromJSON(
  str_glue("https://deckofcardsapi.com/api/deck/{deck_id}/draw/?count={count}",
    deck_id = deck$deck_id, count = 2
  ),
  flatten = TRUE
)
knitr::include_graphics(cards$cards$images.svg)

# reshuffle deck
fromJSON(
  str_glue("https://deckofcardsapi.com/api/deck/{deck_id}/shuffle/",
    deck_id = deck$deck_id
  )
)
## $success
## [1] TRUE
## 
## $deck_id
## [1] "qqhkt1wmn8ku"
## 
## $remaining
## [1] 52
## 
## $shuffled
## [1] TRUE

The parameters after ? are called GET parameters. A more formal way to handle GET parameters is to use the httr package.

library(httr)
endpoint <- str_glue("https://deckofcardsapi.com/api/deck/{deck_id}/draw/", deck_id = deck$deck_id)
r <- GET(endpoint, query = list(count = 2))
stop_for_status(r)

cards <- fromJSON(content(r, as = "text", encoding = "UTF-8"), flatten = TRUE)
cards
## $success
## [1] TRUE
## 
## $deck_id
## [1] "qqhkt1wmn8ku"
## 
## $cards
##   code                                        image value     suit
## 1   5D https://deckofcardsapi.com/static/img/5D.png     5 DIAMONDS
## 2   6D https://deckofcardsapi.com/static/img/6D.png     6 DIAMONDS
##                                     images.svg
## 1 https://deckofcardsapi.com/static/img/5D.svg
## 2 https://deckofcardsapi.com/static/img/6D.svg
##                                     images.png
## 1 https://deckofcardsapi.com/static/img/5D.png
## 2 https://deckofcardsapi.com/static/img/6D.png
## 
## $remaining
## [1] 50
knitr::include_graphics(cards$cards$images.svg)

APIs that require key/token

GeoDataSource https://www.geodatasource.com/

In this section, we are going to show you how we use an API which requires an API key. API key allows you to use the services the API provides on behalf of yourself.

r <- GET(
  "https://api.geodatasource.com/cities",
  query = list(
    key = "YOUR PRIVATE API KEY",
    lat = 38.5449,
    lng = -121.741
  )
)

# check if the status is ok
stop_for_status(r)

json <- content(r, as = "text")
fromJSON(json)

How to store your secrets

There are multiple ways to protect your API key.

  • Make use of environment variables. Environment variables are stored in .Renviron. In the file .Renviron, put
GEODATA_KEY="YOUR API KEY"
  • You could put this file in various places.

    • Project home directory

      • usethis::edit_r_environ("project")

      • The file .Renviron is loaded automatically every time when R restarts.

    • Under the same directory as the Rscript

      • Create a file called .Renviron in the same directory as your script and put your API key into it.
      • You might need to import the keys manually by
readRenviron(".Renviron")
# you might need to change your working directory and restart R session to make it work
r <- GET(
  "https://api.geodatasource.com/cities",
  query = list(
    key = Sys.getenv("GEODATA_KEY"),
    lat = 38.5449,
    lng = -121.741
  )
)
stop_for_status(r)
fromJSON(content(r, as = "text"))
##    country     region                                  city latitude longitude
## 1       US California                                 Davis  38.5449  -121.741
## 2       US California                  Davis Mobile Estates  38.5422  -121.738
## 3       US California Royal Oak Manufactured Home Community  38.5447   -121.73
## 4       US California                             Briggston  38.5313  -121.749
## 5       US California          Rancho Yolo Mobile Home Park  38.5522  -121.724
## 6       US California                             El Macero  38.5468  -121.694
## 7       US California                               Swingle  38.5582  -121.676
## 8       US California                            Plainfield  38.5907  -121.797
## 9       US California                               Webster  38.5621  -121.655
## 10      US California                               Merritt  38.6141  -121.761
## 11      US California                                 Sucro  38.4696  -121.805
## 12      US California                                 Saxon  38.4666  -121.656
## 13      US California                                 Dixon  38.4455  -121.823
##    currency_code        currency_name currency_symbol sunrise sunset time_zone
## 1            USD United States Dollar               $   06:43  17:56    -08:00
## 2            USD United States Dollar               $   06:43  17:56    -08:00
## 3            USD United States Dollar               $   06:43  17:56    -08:00
## 4            USD United States Dollar               $   06:43  17:56    -08:00
## 5            USD United States Dollar               $   06:43  17:56    -08:00
## 6            USD United States Dollar               $   06:43  17:55    -08:00
## 7            USD United States Dollar               $   06:43  17:55    -08:00
## 8            USD United States Dollar               $   06:43  17:56    -08:00
## 9            USD United States Dollar               $   06:43  17:55    -08:00
## 10           USD United States Dollar               $   06:43  17:56    -08:00
## 11           USD United States Dollar               $   06:43  17:56    -08:00
## 12           USD United States Dollar               $   06:43  17:55    -08:00
## 13           USD United States Dollar               $   06:43  17:56    -08:00
##    distance_km
## 1       0.0003
## 2       0.3980
## 3       0.9566
## 4       1.6647
## 5       1.6867
## 6       4.0929
## 7       5.8425
## 8       7.0452
## 9       7.7191
## 10      7.8888
## 11     10.0557
## 12     11.4243
## 13     13.1563
  • The other approach is to make use of the package keyring. (PS: this method doesn’t work for shiny app)
# to set a secret, use
# only need to do it once, you will be prompted for the API key
# the password is stored in your system password manager
keyring::key_set("GEODATA_KEY")
r <- GET(
  "https://api.geodatasource.com/cities",
  query = list(
    key = keyring::key_get("GEODATA_KEY"),
    lat = 38.5449,
    lng = -121.741
  )
)
stop_for_status(r)
json <- content(r, as = "text")
fromJSON(json)
keyring::key_delete("GEODATA_KEY")

The Guardian News https://open-platform.theguardian.com/

r <- GET(
  "https://content.guardianapis.com/search",
  query = list(
    `api-key` = Sys.getenv("GUARDIAN_KEY"),
    q = 'coronavirus',
    `page-size` = 10
  )
)
stop_for_status(r)
result <- fromJSON(content(r, as = "text", encoding = "UTF-8"))
result$response$results
##                                                                                                  id
## 1                           artanddesign/2020/dec/21/inside-oxfords-coronavirus-vaccine-development
## 2                              world/2021/jan/29/catastrophic-errors-in-the-handling-of-coronavirus
## 3                                      world/2021/jan/07/us-suffers-record-daily-coronavirus-deaths
## 4                       uk-news/2021/feb/23/scotlands-stages-how-coronavirus-lockdown-will-be-eased
## 5                        world/2021/feb/24/covid-uk-coronavirus-cases-deaths-and-vaccinations-today
## 6  australia-news/2021/feb/16/astrazeneca-coronavirus-vaccine-approved-by-australias-drug-regulator
## 7                                   football/2021/jan/15/crystal-palace-play-it-safe-on-coronavirus
## 8                                          world/2020/dec/01/uk-coronavirus-death-toll-passes-75000
## 9                            us-news/2020/dec/29/coronavirus-sharpens-economic-inequalities-america
## 10                              world/2021/feb/03/israel-opens-coronavirus-vaccines-to-all-over-16s
##       type      sectionId    sectionName   webPublicationDate
## 1  article   artanddesign Art and design 2020-12-21T07:00:40Z
## 2  article          world     World news 2021-01-29T17:57:19Z
## 3  article          world     World news 2021-01-07T06:38:06Z
## 4  article        uk-news        UK news 2021-02-23T18:09:24Z
## 5  article          world     World news 2021-02-24T09:54:37Z
## 6  article australia-news Australia news 2021-02-16T03:46:48Z
## 7  article       football       Football 2021-01-15T18:21:23Z
## 8  article          world     World news 2020-12-01T17:01:59Z
## 9  article        us-news        US news 2020-12-29T11:00:40Z
## 10 article          world     World news 2021-02-03T13:05:40Z
##                                                                    webTitle
## 1                           Inside Oxford’s coronavirus vaccine development
## 2              Catastrophic errors in the handling of coronavirus | Letters
## 3                                US suffers record daily coronavirus deaths
## 4                Scotland's stages: how coronavirus lockdown will be eased 
## 5                Covid: UK Coronavirus cases, deaths and vaccinations today
## 6  AstraZeneca coronavirus vaccine approved by Australia's drug regulator  
## 7                Crystal Palace play it safe on coronavirus | Brief letters
## 8                                   UK coronavirus death toll passes 75,000
## 9        Coronavirus sharpens America's already stark economic inequalities
## 10                        Israel opens coronavirus vaccines to all over-16s
##                                                                                                                          webUrl
## 1                           https://www.theguardian.com/artanddesign/2020/dec/21/inside-oxfords-coronavirus-vaccine-development
## 2                              https://www.theguardian.com/world/2021/jan/29/catastrophic-errors-in-the-handling-of-coronavirus
## 3                                      https://www.theguardian.com/world/2021/jan/07/us-suffers-record-daily-coronavirus-deaths
## 4                       https://www.theguardian.com/uk-news/2021/feb/23/scotlands-stages-how-coronavirus-lockdown-will-be-eased
## 5                        https://www.theguardian.com/world/2021/feb/24/covid-uk-coronavirus-cases-deaths-and-vaccinations-today
## 6  https://www.theguardian.com/australia-news/2021/feb/16/astrazeneca-coronavirus-vaccine-approved-by-australias-drug-regulator
## 7                                   https://www.theguardian.com/football/2021/jan/15/crystal-palace-play-it-safe-on-coronavirus
## 8                                          https://www.theguardian.com/world/2020/dec/01/uk-coronavirus-death-toll-passes-75000
## 9                            https://www.theguardian.com/us-news/2020/dec/29/coronavirus-sharpens-economic-inequalities-america
## 10                              https://www.theguardian.com/world/2021/feb/03/israel-opens-coronavirus-vaccines-to-all-over-16s
##                                                                                                                               apiUrl
## 1                           https://content.guardianapis.com/artanddesign/2020/dec/21/inside-oxfords-coronavirus-vaccine-development
## 2                              https://content.guardianapis.com/world/2021/jan/29/catastrophic-errors-in-the-handling-of-coronavirus
## 3                                      https://content.guardianapis.com/world/2021/jan/07/us-suffers-record-daily-coronavirus-deaths
## 4                       https://content.guardianapis.com/uk-news/2021/feb/23/scotlands-stages-how-coronavirus-lockdown-will-be-eased
## 5                        https://content.guardianapis.com/world/2021/feb/24/covid-uk-coronavirus-cases-deaths-and-vaccinations-today
## 6  https://content.guardianapis.com/australia-news/2021/feb/16/astrazeneca-coronavirus-vaccine-approved-by-australias-drug-regulator
## 7                                   https://content.guardianapis.com/football/2021/jan/15/crystal-palace-play-it-safe-on-coronavirus
## 8                                          https://content.guardianapis.com/world/2020/dec/01/uk-coronavirus-death-toll-passes-75000
## 9                            https://content.guardianapis.com/us-news/2020/dec/29/coronavirus-sharpens-economic-inequalities-america
## 10                              https://content.guardianapis.com/world/2021/feb/03/israel-opens-coronavirus-vaccines-to-all-over-16s
##    isHosted     pillarId pillarName
## 1     FALSE  pillar/arts       Arts
## 2     FALSE  pillar/news       News
## 3     FALSE  pillar/news       News
## 4     FALSE  pillar/news       News
## 5     FALSE  pillar/news       News
## 6     FALSE  pillar/news       News
## 7     FALSE pillar/sport      Sport
## 8     FALSE  pillar/news       News
## 9     FALSE  pillar/news       News
## 10    FALSE  pillar/news       News

Only 10 results?

result$response$pages
## [1] 3132

There are many more pages! How to get the second page?

r <- GET(
  "https://content.guardianapis.com/search",
  query = list(
    `api-key` = Sys.getenv("GUARDIAN_KEY"),
    q = "coronavirus",
    `page-size` = 10,
    page = 2
  )
)
stop_for_status(r)
json <- content(r, as = "text", encoding = "UTF-8")
result <- fromJSON(json)
result$response$results
##                                                                                                                                                     id
## 1                                                                                world/2020/nov/25/smarter-ways-tips-navigate-christmas-coronavirus-uk
## 2                                                                               us-news/2020/dec/29/coronavirus-sharpens-economic-inequalities-america
## 3                                                                                   society/2020/dec/02/beware-fake-coronavirus-vaccines-says-interpol
## 4  australia-news/2021/feb/17/coronavirus-victoria-covid-melbourne-lockdown-restrictions-rules-covid19-explained-mask-exercising-what-you-need-to-know
## 5                                                            lifeandstyle/2021/feb/09/share-your-experiences-of-dating-during-the-coronavirus-pandemic
## 6                                                                                           world/2020/nov/18/us-passes-250000-deaths-from-coronavirus
## 7                                                                                      world/2021/jan/08/california-hospitals-coronavirus-cases-deaths
## 8                                                                             world/2021/jan/15/global-coronavirus-death-toll-reaches-2-million-people
## 9                                                               world/2021/jan/31/captain-sir-tom-moore-tests-positive-for-covid-19-and-is-in-hospital
## 10                                               world/ng-interactive/2020/dec/16/covid-chaos-a-timeline-of-the-uks-handling-of-the-coronavirus-crisis
##           type      sectionId    sectionName   webPublicationDate
## 1      article          world     World news 2020-11-25T18:49:56Z
## 2      article        us-news        US news 2020-12-29T11:00:40Z
## 3      article        society        Society 2020-12-02T11:25:26Z
## 4      article australia-news Australia news 2021-02-17T01:36:28Z
## 5      article   lifeandstyle Life and style 2021-02-09T11:37:01Z
## 6      article          world     World news 2020-11-18T22:49:04Z
## 7      article          world     World news 2021-01-08T20:54:12Z
## 8      article          world     World news 2021-01-16T05:21:24Z
## 9      article          world     World news 2021-01-31T17:31:48Z
## 10 interactive          world     World news 2021-02-03T15:48:25Z
##                                                                     webTitle
## 1                                    Coronavirus: tips for a safer Christmas
## 2         Coronavirus sharpens America's already stark economic inequalities
## 3                            Beware fake coronavirus vaccines, says Interpol
## 4  Coronavirus Victoria: Covid lockdown rules and Vic restrictions explained
## 5           Share your experiences of dating during the coronavirus pandemic
## 6                                  US passes 250,000 deaths from coronavirus
## 7             California struggles under a staggering 2.5m coronavirus cases
## 8                    Global report: coronavirus death toll reaches 2 million
## 9                Captain Sir Tom Moore admitted to hospital with coronavirus
## 10                    Covid chaos: how the UK handled the coronavirus crisis
##                                                                                                                                                                             webUrl
## 1                                                                                https://www.theguardian.com/world/2020/nov/25/smarter-ways-tips-navigate-christmas-coronavirus-uk
## 2                                                                               https://www.theguardian.com/us-news/2020/dec/29/coronavirus-sharpens-economic-inequalities-america
## 3                                                                                   https://www.theguardian.com/society/2020/dec/02/beware-fake-coronavirus-vaccines-says-interpol
## 4  https://www.theguardian.com/australia-news/2021/feb/17/coronavirus-victoria-covid-melbourne-lockdown-restrictions-rules-covid19-explained-mask-exercising-what-you-need-to-know
## 5                                                            https://www.theguardian.com/lifeandstyle/2021/feb/09/share-your-experiences-of-dating-during-the-coronavirus-pandemic
## 6                                                                                           https://www.theguardian.com/world/2020/nov/18/us-passes-250000-deaths-from-coronavirus
## 7                                                                                      https://www.theguardian.com/world/2021/jan/08/california-hospitals-coronavirus-cases-deaths
## 8                                                                             https://www.theguardian.com/world/2021/jan/15/global-coronavirus-death-toll-reaches-2-million-people
## 9                                                               https://www.theguardian.com/world/2021/jan/31/captain-sir-tom-moore-tests-positive-for-covid-19-and-is-in-hospital
## 10                                               https://www.theguardian.com/world/ng-interactive/2020/dec/16/covid-chaos-a-timeline-of-the-uks-handling-of-the-coronavirus-crisis
##                                                                                                                                                                                  apiUrl
## 1                                                                                https://content.guardianapis.com/world/2020/nov/25/smarter-ways-tips-navigate-christmas-coronavirus-uk
## 2                                                                               https://content.guardianapis.com/us-news/2020/dec/29/coronavirus-sharpens-economic-inequalities-america
## 3                                                                                   https://content.guardianapis.com/society/2020/dec/02/beware-fake-coronavirus-vaccines-says-interpol
## 4  https://content.guardianapis.com/australia-news/2021/feb/17/coronavirus-victoria-covid-melbourne-lockdown-restrictions-rules-covid19-explained-mask-exercising-what-you-need-to-know
## 5                                                            https://content.guardianapis.com/lifeandstyle/2021/feb/09/share-your-experiences-of-dating-during-the-coronavirus-pandemic
## 6                                                                                           https://content.guardianapis.com/world/2020/nov/18/us-passes-250000-deaths-from-coronavirus
## 7                                                                                      https://content.guardianapis.com/world/2021/jan/08/california-hospitals-coronavirus-cases-deaths
## 8                                                                             https://content.guardianapis.com/world/2021/jan/15/global-coronavirus-death-toll-reaches-2-million-people
## 9                                                               https://content.guardianapis.com/world/2021/jan/31/captain-sir-tom-moore-tests-positive-for-covid-19-and-is-in-hospital
## 10                                               https://content.guardianapis.com/world/ng-interactive/2020/dec/16/covid-chaos-a-timeline-of-the-uks-handling-of-the-coronavirus-crisis
##    isHosted         pillarId pillarName
## 1     FALSE      pillar/news       News
## 2     FALSE      pillar/news       News
## 3     FALSE      pillar/news       News
## 4     FALSE      pillar/news       News
## 5     FALSE pillar/lifestyle  Lifestyle
## 6     FALSE      pillar/news       News
## 7     FALSE      pillar/news       News
## 8     FALSE      pillar/news       News
## 9     FALSE      pillar/news       News
## 10    FALSE      pillar/news       News

Wolfram alpha

r <- GET(
  "https://api.wolframalpha.com/v2/query",
  query = list(
    appid = Sys.getenv("WOLFRAM_ALPHA_KEY"),
    input = "integrate x^3",
    format = "plaintext",
    output = "json"
  )
)
stop_for_status(r)
json <- content(r, as = "text", encoding = "UTF-8")
fromJSON(json, flatten = TRUE)$queryresult$pods %>%
  hoist(subpods, text = "plaintext") %>%
  select(title, text) %>%
  unnest(text)
## # A tibble: 2 x 2
##   title                text                                
##   <chr>                <chr>                               
## 1 Indefinite integral  "integral x^3 dx = x^4/4 + constant"
## 2 Plot of the integral ""

Google map

You will need to register a google clould platfram account with $300 credit first. THen following the instruction here to generate an api key. https://developers.google.com/places/web-service/get-api-key

r <- GET(
  "https://maps.googleapis.com/maps/api/place/nearbysearch/json",
  query = list(
    key = Sys.getenv("GOOGLE_API_KEY"),
    location = "38.5449,-121.741",
    radius = 500,
    types = "food",
    name = "in-n-out"
  )
)
stop_for_status(r)
json <- content(r, as = "text", encoding = "UTF-8")
fromJSON(json, flatten = TRUE)$results %>% pull(vicinity)
## [1] "1020 Olive Dr, Davis"

GitHub API

GitHub requires API token instead of an API key.

r <- GET(
  str_glue("https://api.github.com/users/{username}/repos", username = "randy3k"),
  add_headers(Authorization = paste("token", Sys.getenv("GITHUB_PAT")))
)
stop_for_status(r)
json <- content(r, as = "text")
fromJSON(json)
##          id                          node_id     name        full_name private
## 1 222521499 MDEwOlJlcG9zaXRvcnkyMjI1MjE0OTk=  actions  randy3k/actions   FALSE
## 2   7086462     MDEwOlJlcG9zaXRvcnk3MDg2NDYy AlignTab randy3k/AlignTab   FALSE
##   owner.login owner.id        owner.node_id
## 1     randy3k  1690993 MDQ6VXNlcjE2OTA5OTM=
## 2     randy3k  1690993 MDQ6VXNlcjE2OTA5OTM=
##                                      owner.avatar_url owner.gravatar_id
## 1 https://avatars.githubusercontent.com/u/1690993?v=4                  
## 2 https://avatars.githubusercontent.com/u/1690993?v=4                  
##                              owner.url             owner.html_url
## 1 https://api.github.com/users/randy3k https://github.com/randy3k
## 2 https://api.github.com/users/randy3k https://github.com/randy3k
##                              owner.followers_url
## 1 https://api.github.com/users/randy3k/followers
## 2 https://api.github.com/users/randy3k/followers
##                                           owner.following_url
## 1 https://api.github.com/users/randy3k/following{/other_user}
## 2 https://api.github.com/users/randy3k/following{/other_user}
##                                        owner.gists_url
## 1 https://api.github.com/users/randy3k/gists{/gist_id}
## 2 https://api.github.com/users/randy3k/gists{/gist_id}
##                                             owner.starred_url
## 1 https://api.github.com/users/randy3k/starred{/owner}{/repo}
## 2 https://api.github.com/users/randy3k/starred{/owner}{/repo}
##                              owner.subscriptions_url
## 1 https://api.github.com/users/randy3k/subscriptions
## 2 https://api.github.com/users/randy3k/subscriptions
##                     owner.organizations_url
## 1 https://api.github.com/users/randy3k/orgs
## 2 https://api.github.com/users/randy3k/orgs
##                              owner.repos_url
## 1 https://api.github.com/users/randy3k/repos
## 2 https://api.github.com/users/randy3k/repos
##                                        owner.events_url
## 1 https://api.github.com/users/randy3k/events{/privacy}
## 2 https://api.github.com/users/randy3k/events{/privacy}
##                              owner.received_events_url owner.type
## 1 https://api.github.com/users/randy3k/received_events       User
## 2 https://api.github.com/users/randy3k/received_events       User
##   owner.site_admin                            html_url
## 1            FALSE  https://github.com/randy3k/actions
## 2            FALSE https://github.com/randy3k/AlignTab
##                                                     description  fork
## 1                            GitHub Actions for the R community  TRUE
## 2 An alignment plugin for Sublime Text using regular expression FALSE
##                                             url
## 1  https://api.github.com/repos/randy3k/actions
## 2 https://api.github.com/repos/randy3k/AlignTab
##                                             forks_url
## 1  https://api.github.com/repos/randy3k/actions/forks
## 2 https://api.github.com/repos/randy3k/AlignTab/forks
##                                                      keys_url
## 1  https://api.github.com/repos/randy3k/actions/keys{/key_id}
## 2 https://api.github.com/repos/randy3k/AlignTab/keys{/key_id}
##                                                            collaborators_url
## 1  https://api.github.com/repos/randy3k/actions/collaborators{/collaborator}
## 2 https://api.github.com/repos/randy3k/AlignTab/collaborators{/collaborator}
##                                             teams_url
## 1  https://api.github.com/repos/randy3k/actions/teams
## 2 https://api.github.com/repos/randy3k/AlignTab/teams
##                                             hooks_url
## 1  https://api.github.com/repos/randy3k/actions/hooks
## 2 https://api.github.com/repos/randy3k/AlignTab/hooks
##                                                       issue_events_url
## 1  https://api.github.com/repos/randy3k/actions/issues/events{/number}
## 2 https://api.github.com/repos/randy3k/AlignTab/issues/events{/number}
##                                             events_url
## 1  https://api.github.com/repos/randy3k/actions/events
## 2 https://api.github.com/repos/randy3k/AlignTab/events
##                                                    assignees_url
## 1  https://api.github.com/repos/randy3k/actions/assignees{/user}
## 2 https://api.github.com/repos/randy3k/AlignTab/assignees{/user}
##                                                      branches_url
## 1  https://api.github.com/repos/randy3k/actions/branches{/branch}
## 2 https://api.github.com/repos/randy3k/AlignTab/branches{/branch}
##                                             tags_url
## 1  https://api.github.com/repos/randy3k/actions/tags
## 2 https://api.github.com/repos/randy3k/AlignTab/tags
##                                                       blobs_url
## 1  https://api.github.com/repos/randy3k/actions/git/blobs{/sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/git/blobs{/sha}
##                                                   git_tags_url
## 1  https://api.github.com/repos/randy3k/actions/git/tags{/sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/git/tags{/sha}
##                                                   git_refs_url
## 1  https://api.github.com/repos/randy3k/actions/git/refs{/sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/git/refs{/sha}
##                                                       trees_url
## 1  https://api.github.com/repos/randy3k/actions/git/trees{/sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/git/trees{/sha}
##                                                   statuses_url
## 1  https://api.github.com/repos/randy3k/actions/statuses/{sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/statuses/{sha}
##                                             languages_url
## 1  https://api.github.com/repos/randy3k/actions/languages
## 2 https://api.github.com/repos/randy3k/AlignTab/languages
##                                             stargazers_url
## 1  https://api.github.com/repos/randy3k/actions/stargazers
## 2 https://api.github.com/repos/randy3k/AlignTab/stargazers
##                                             contributors_url
## 1  https://api.github.com/repos/randy3k/actions/contributors
## 2 https://api.github.com/repos/randy3k/AlignTab/contributors
##                                             subscribers_url
## 1  https://api.github.com/repos/randy3k/actions/subscribers
## 2 https://api.github.com/repos/randy3k/AlignTab/subscribers
##                                             subscription_url
## 1  https://api.github.com/repos/randy3k/actions/subscription
## 2 https://api.github.com/repos/randy3k/AlignTab/subscription
##                                                   commits_url
## 1  https://api.github.com/repos/randy3k/actions/commits{/sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/commits{/sha}
##                                                   git_commits_url
## 1  https://api.github.com/repos/randy3k/actions/git/commits{/sha}
## 2 https://api.github.com/repos/randy3k/AlignTab/git/commits{/sha}
##                                                      comments_url
## 1  https://api.github.com/repos/randy3k/actions/comments{/number}
## 2 https://api.github.com/repos/randy3k/AlignTab/comments{/number}
##                                                        issue_comment_url
## 1  https://api.github.com/repos/randy3k/actions/issues/comments{/number}
## 2 https://api.github.com/repos/randy3k/AlignTab/issues/comments{/number}
##                                                     contents_url
## 1  https://api.github.com/repos/randy3k/actions/contents/{+path}
## 2 https://api.github.com/repos/randy3k/AlignTab/contents/{+path}
##                                                             compare_url
## 1  https://api.github.com/repos/randy3k/actions/compare/{base}...{head}
## 2 https://api.github.com/repos/randy3k/AlignTab/compare/{base}...{head}
##                                             merges_url
## 1  https://api.github.com/repos/randy3k/actions/merges
## 2 https://api.github.com/repos/randy3k/AlignTab/merges
##                                                            archive_url
## 1  https://api.github.com/repos/randy3k/actions/{archive_format}{/ref}
## 2 https://api.github.com/repos/randy3k/AlignTab/{archive_format}{/ref}
##                                             downloads_url
## 1  https://api.github.com/repos/randy3k/actions/downloads
## 2 https://api.github.com/repos/randy3k/AlignTab/downloads
##                                                      issues_url
## 1  https://api.github.com/repos/randy3k/actions/issues{/number}
## 2 https://api.github.com/repos/randy3k/AlignTab/issues{/number}
##                                                      pulls_url
## 1  https://api.github.com/repos/randy3k/actions/pulls{/number}
## 2 https://api.github.com/repos/randy3k/AlignTab/pulls{/number}
##                                                      milestones_url
## 1  https://api.github.com/repos/randy3k/actions/milestones{/number}
## 2 https://api.github.com/repos/randy3k/AlignTab/milestones{/number}
##                                                                       notifications_url
## 1  https://api.github.com/repos/randy3k/actions/notifications{?since,all,participating}
## 2 https://api.github.com/repos/randy3k/AlignTab/notifications{?since,all,participating}
##                                                    labels_url
## 1  https://api.github.com/repos/randy3k/actions/labels{/name}
## 2 https://api.github.com/repos/randy3k/AlignTab/labels{/name}
##                                                  releases_url
## 1  https://api.github.com/repos/randy3k/actions/releases{/id}
## 2 https://api.github.com/repos/randy3k/AlignTab/releases{/id}
##                                             deployments_url
## 1  https://api.github.com/repos/randy3k/actions/deployments
## 2 https://api.github.com/repos/randy3k/AlignTab/deployments
##             created_at           updated_at            pushed_at
## 1 2019-11-18T18:56:00Z 2020-02-06T02:36:25Z 2020-05-25T18:00:31Z
## 2 2012-12-10T02:25:22Z 2021-02-17T11:44:21Z 2020-10-15T18:18:34Z
##                                 git_url                             ssh_url
## 1  git://github.com/randy3k/actions.git  git@github.com:randy3k/actions.git
## 2 git://github.com/randy3k/AlignTab.git git@github.com:randy3k/AlignTab.git
##                                 clone_url                             svn_url
## 1  https://github.com/randy3k/actions.git  https://github.com/randy3k/actions
## 2 https://github.com/randy3k/AlignTab.git https://github.com/randy3k/AlignTab
##   homepage size stargazers_count watchers_count   language has_issues
## 1           777                0              0 JavaScript      FALSE
## 2          1462              610            610     Python       TRUE
##   has_projects has_downloads has_wiki has_pages forks_count mirror_url archived
## 1         TRUE          TRUE     TRUE     FALSE           0         NA    FALSE
## 2         TRUE          TRUE     TRUE     FALSE          27         NA    FALSE
##   disabled open_issues_count license.key                         license.name
## 1    FALSE                 0     cc0-1.0 Creative Commons Zero v1.0 Universal
## 2    FALSE                16         mit                          MIT License
##   license.spdx_id                             license.url  license.node_id
## 1         CC0-1.0 https://api.github.com/licenses/cc0-1.0 MDc6TGljZW5zZTY=
## 2             MIT     https://api.github.com/licenses/mit MDc6TGljZW5zZTEz
##   forks open_issues watchers default_branch permissions.admin permissions.push
## 1     0           0        0         master              TRUE             TRUE
## 2    27          16      610         master              TRUE             TRUE
##   permissions.pull
## 1             TRUE
## 2             TRUE
##  [ reached 'max' / getOption("max.print") -- omitted 28 rows ]

Only 30 repos? How to go to next page?

r$headers$link
## [1] "<https://api.github.com/user/1690993/repos?page=2>; rel=\"next\", <https://api.github.com/user/1690993/repos?page=5>; rel=\"last\""
r2 <- GET("https://api.github.com/user/1690993/repos?page=2",
         add_headers(Authorization = paste("token", Sys.getenv("GITHUB_PAT"))))
stop_for_status(r2)
json <- content(r2, as = "text")
fromJSON(json)
##          id                          node_id             name
## 1  60392032 MDEwOlJlcG9zaXRvcnk2MDM5MjAzMg==       homebrew-r
## 2 115029972 MDEwOlJlcG9zaXRvcnkxMTUwMjk5NzI= homebrew-science
##                  full_name private owner.login owner.id        owner.node_id
## 1       randy3k/homebrew-r   FALSE     randy3k  1690993 MDQ6VXNlcjE2OTA5OTM=
## 2 randy3k/homebrew-science   FALSE     randy3k  1690993 MDQ6VXNlcjE2OTA5OTM=
##                                      owner.avatar_url owner.gravatar_id
## 1 https://avatars.githubusercontent.com/u/1690993?v=4                  
## 2 https://avatars.githubusercontent.com/u/1690993?v=4                  
##                              owner.url             owner.html_url
## 1 https://api.github.com/users/randy3k https://github.com/randy3k
## 2 https://api.github.com/users/randy3k https://github.com/randy3k
##                              owner.followers_url
## 1 https://api.github.com/users/randy3k/followers
## 2 https://api.github.com/users/randy3k/followers
##                                           owner.following_url
## 1 https://api.github.com/users/randy3k/following{/other_user}
## 2 https://api.github.com/users/randy3k/following{/other_user}
##                                        owner.gists_url
## 1 https://api.github.com/users/randy3k/gists{/gist_id}
## 2 https://api.github.com/users/randy3k/gists{/gist_id}
##                                             owner.starred_url
## 1 https://api.github.com/users/randy3k/starred{/owner}{/repo}
## 2 https://api.github.com/users/randy3k/starred{/owner}{/repo}
##                              owner.subscriptions_url
## 1 https://api.github.com/users/randy3k/subscriptions
## 2 https://api.github.com/users/randy3k/subscriptions
##                     owner.organizations_url
## 1 https://api.github.com/users/randy3k/orgs
## 2 https://api.github.com/users/randy3k/orgs
##                              owner.repos_url
## 1 https://api.github.com/users/randy3k/repos
## 2 https://api.github.com/users/randy3k/repos
##                                        owner.events_url
## 1 https://api.github.com/users/randy3k/events{/privacy}
## 2 https://api.github.com/users/randy3k/events{/privacy}
##                              owner.received_events_url owner.type
## 1 https://api.github.com/users/randy3k/received_events       User
## 2 https://api.github.com/users/randy3k/received_events       User
##   owner.site_admin                                    html_url
## 1            FALSE       https://github.com/randy3k/homebrew-r
## 2            FALSE https://github.com/randy3k/homebrew-science
##                                                               description  fork
## 1                               Homebrew formulas for R and related tools FALSE
## 2 :beer::microscope: Scientific formulae for the Homebrew package manager  TRUE
##                                                     url
## 1       https://api.github.com/repos/randy3k/homebrew-r
## 2 https://api.github.com/repos/randy3k/homebrew-science
##                                                     forks_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/forks
## 2 https://api.github.com/repos/randy3k/homebrew-science/forks
##                                                              keys_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/keys{/key_id}
## 2 https://api.github.com/repos/randy3k/homebrew-science/keys{/key_id}
##                                                                    collaborators_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/collaborators{/collaborator}
## 2 https://api.github.com/repos/randy3k/homebrew-science/collaborators{/collaborator}
##                                                     teams_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/teams
## 2 https://api.github.com/repos/randy3k/homebrew-science/teams
##                                                     hooks_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/hooks
## 2 https://api.github.com/repos/randy3k/homebrew-science/hooks
##                                                               issue_events_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/issues/events{/number}
## 2 https://api.github.com/repos/randy3k/homebrew-science/issues/events{/number}
##                                                     events_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/events
## 2 https://api.github.com/repos/randy3k/homebrew-science/events
##                                                            assignees_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/assignees{/user}
## 2 https://api.github.com/repos/randy3k/homebrew-science/assignees{/user}
##                                                              branches_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/branches{/branch}
## 2 https://api.github.com/repos/randy3k/homebrew-science/branches{/branch}
##                                                     tags_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/tags
## 2 https://api.github.com/repos/randy3k/homebrew-science/tags
##                                                               blobs_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/git/blobs{/sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/git/blobs{/sha}
##                                                           git_tags_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/git/tags{/sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/git/tags{/sha}
##                                                           git_refs_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/git/refs{/sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/git/refs{/sha}
##                                                               trees_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/git/trees{/sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/git/trees{/sha}
##                                                           statuses_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/statuses/{sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/statuses/{sha}
##                                                     languages_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/languages
## 2 https://api.github.com/repos/randy3k/homebrew-science/languages
##                                                     stargazers_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/stargazers
## 2 https://api.github.com/repos/randy3k/homebrew-science/stargazers
##                                                     contributors_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/contributors
## 2 https://api.github.com/repos/randy3k/homebrew-science/contributors
##                                                     subscribers_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/subscribers
## 2 https://api.github.com/repos/randy3k/homebrew-science/subscribers
##                                                     subscription_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/subscription
## 2 https://api.github.com/repos/randy3k/homebrew-science/subscription
##                                                           commits_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/commits{/sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/commits{/sha}
##                                                           git_commits_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/git/commits{/sha}
## 2 https://api.github.com/repos/randy3k/homebrew-science/git/commits{/sha}
##                                                              comments_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/comments{/number}
## 2 https://api.github.com/repos/randy3k/homebrew-science/comments{/number}
##                                                                issue_comment_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/issues/comments{/number}
## 2 https://api.github.com/repos/randy3k/homebrew-science/issues/comments{/number}
##                                                             contents_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/contents/{+path}
## 2 https://api.github.com/repos/randy3k/homebrew-science/contents/{+path}
##                                                                     compare_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/compare/{base}...{head}
## 2 https://api.github.com/repos/randy3k/homebrew-science/compare/{base}...{head}
##                                                     merges_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/merges
## 2 https://api.github.com/repos/randy3k/homebrew-science/merges
##                                                                    archive_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/{archive_format}{/ref}
## 2 https://api.github.com/repos/randy3k/homebrew-science/{archive_format}{/ref}
##                                                     downloads_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/downloads
## 2 https://api.github.com/repos/randy3k/homebrew-science/downloads
##                                                              issues_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/issues{/number}
## 2 https://api.github.com/repos/randy3k/homebrew-science/issues{/number}
##                                                              pulls_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/pulls{/number}
## 2 https://api.github.com/repos/randy3k/homebrew-science/pulls{/number}
##                                                              milestones_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/milestones{/number}
## 2 https://api.github.com/repos/randy3k/homebrew-science/milestones{/number}
##                                                                               notifications_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/notifications{?since,all,participating}
## 2 https://api.github.com/repos/randy3k/homebrew-science/notifications{?since,all,participating}
##                                                            labels_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/labels{/name}
## 2 https://api.github.com/repos/randy3k/homebrew-science/labels{/name}
##                                                          releases_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/releases{/id}
## 2 https://api.github.com/repos/randy3k/homebrew-science/releases{/id}
##                                                     deployments_url
## 1       https://api.github.com/repos/randy3k/homebrew-r/deployments
## 2 https://api.github.com/repos/randy3k/homebrew-science/deployments
##             created_at           updated_at            pushed_at
## 1 2016-06-04T03:50:10Z 2021-02-24T21:43:21Z 2020-12-31T23:33:52Z
## 2 2017-12-21T17:20:18Z 2017-12-21T17:20:22Z 2017-12-21T17:56:51Z
##                                         git_url
## 1       git://github.com/randy3k/homebrew-r.git
## 2 git://github.com/randy3k/homebrew-science.git
##                                       ssh_url
## 1       git@github.com:randy3k/homebrew-r.git
## 2 git@github.com:randy3k/homebrew-science.git
##                                         clone_url
## 1       https://github.com/randy3k/homebrew-r.git
## 2 https://github.com/randy3k/homebrew-science.git
##                                       svn_url
## 1       https://github.com/randy3k/homebrew-r
## 2 https://github.com/randy3k/homebrew-science
##                                                           homepage size
## 1                                                                   145
## 2 http://formulae.brew.sh/repos/Homebrew/homebrew-science/browse/a 9976
##   stargazers_count watchers_count language has_issues has_projects
## 1               25             25     Ruby       TRUE         TRUE
## 2                0              0     Ruby      FALSE         TRUE
##   has_downloads has_wiki has_pages forks_count mirror_url archived disabled
## 1          TRUE     TRUE     FALSE           7         NA    FALSE    FALSE
## 2          TRUE     TRUE     FALSE           0         NA    FALSE    FALSE
##   open_issues_count license.key license.name license.spdx_id license.url
## 1                 1        <NA>         <NA>            <NA>        <NA>
## 2                 0       other        Other     NOASSERTION        <NA>
##    license.node_id forks open_issues watchers default_branch permissions.admin
## 1             <NA>     7           1       25         master              TRUE
## 2 MDc6TGljZW5zZTA=     0           0        0         master              TRUE
##   permissions.push permissions.pull
## 1             TRUE             TRUE
## 2             TRUE             TRUE
##  [ reached 'max' / getOption("max.print") -- omitted 28 rows ]
r2$headers$link
## [1] "<https://api.github.com/user/1690993/repos?page=1>; rel=\"prev\", <https://api.github.com/user/1690993/repos?page=3>; rel=\"next\", <https://api.github.com/user/1690993/repos?page=5>; rel=\"last\", <https://api.github.com/user/1690993/repos?page=1>; rel=\"first\""

Yelp

Yelp requires Bearer token directory instead of an API key.

First, you will need to register an app on yelp: https://www.yelp.com/developers

r <- GET(
  "https://api.yelp.com/v3/businesses/search",
  add_headers(Authorization = paste("Bearer", Sys.getenv("YELP_TOKEN"))),
  query = list(
    location = "Davis"
  )
)
stop_for_status(r)
json <- content(r, as = "text")
## No encoding supplied: defaulting to UTF-8.
fromJSON(json, flatten = TRUE)$businesses %>% select(name)
##                                        name
## 1               Sam's Mediterranean Cuisine
## 2                          Burgers and Brew
## 3                         Dutch Bros Coffee
## 4   Four Seasons Gourmet Chinese Restaurant
## 5                            Taqueria Davis
## 6                            Nugget Markets
## 7                       Zumapoke & Lush Ice
## 8  Mikuni Japanese Restaurant and Sushi Bar
## 9                         Sweet and Shavery
## 10                     Taqueria Guadalajara
## 11                  Woodstock's Pizza Davis
## 12                   Temple Coffee Roasters
## 13                               Crepeville
## 14                              Blaze Pizza
## 15                             Thai Canteen
## 16               Tommy J's Grill & Catering
## 17                           Raja's Tandoor
## 18                                 Tea List
## 19                 Fish's Wild Island Grill
## 20                          In-N-Out Burger

OAuth

NOTE: this kind of APIs is not recomended for the final project (as it is going to be a shiny application).

OAuth is a technique to allow developers to access the API on behalf on themselves or other users.

There are two versions of OAuth, 1.0 and 2.0. You should not think that 2.0 is better than 1.0. They are simply different implementations.

OAuth is complex but fun to learn about. Read this https://oauth.net/2/ if you are interested.

In OAuth protocol, there are two important pieces of strings

To put is simple, there are three cases - one legged OAuth: developer directly use the key and secret to access the API - two legged OAuth (aka: client credential flow in OAuth 2.0): developer use the key and secret to obtain an access token, and the access token will allow the developer to access the API on behalf of themself - three legged OAuth (aka: authorization code flow in OAuth 2.0): it is usually used to access the API on behalf of another user.

(Imagine that Bob is writing an email app so that Alice could read her own emails on the app.) The process is roughly the followings

  1. Bob tells Alice the client key and secret
  2. Alice uses the client key and secret to generate an authorization code from the server
  3. Alice sends the authorization code to Bob
  4. Bob uses to authorization code to generate an access token from the server
  5. Bob uses the access token to access emails for Alice and displays them in the app
library(httr)

Noun Project https://thenounproject.com/ (one legged)

The Noun Project uses one-legged OAuth protocol to authenticate users.

noun_app <- oauth_app(
  "nounproject",
  key = "ed652bdcd50a4496bbc2253a603b9e9b",
  secret = Sys.getenv("NOUN_SECRET")
)
endpoint <- str_glue(
  "https://api.thenounproject.com/icons/{term}", 
  term = "statistics")
signature <- oauth_signature(endpoint, app = noun_app)
r <- GET(endpoint, oauth_header(signature))

stop_for_status(r)
json <- content(r, as = "text", encoding = "UTF-8")
icons <- fromJSON(json)$icons %>% pull(preview_url)
knitr::include_graphics(icons[1:10])

Twitter (two legged)

First, create an app at https://developer.twitter.com/. You will need to register a twitter developer account first.

Twitter allows an app to access information publicly available on Twitter via two legged OAuth protocol.

twitter_app <- oauth_app("twitter",
  key = "1vqbnsftUcNLucoVxQiWYnD2d",
  secret = Sys.getenv("TWITTER_SECRET")
)

twitter_token <- oauth2.0_token(
  oauth_endpoint(
    authorize = NULL,
    access = "https://api.twitter.com/oauth2/token"
  ),
  twitter_app,
  client_credentials = TRUE
)
# Where On Earth IDentifier
get_woeid <- function(city, country) {
  r <- GET(
    "https://api.twitter.com/1.1/trends/available.json",
    config(token = twitter_token)
  )

  stop_for_status(r)
  json <- content(r, as = "text")
  fromJSON(json) %>%
    filter(name == !!city , country == !!country ) %>%
    pull(woeid)
}

get_trends <- function(woeid) {
  r <- GET(
    "https://api.twitter.com/1.1/trends/place.json",
    config(token = twitter_token),
    query = list(id = woeid)
  )

  stop_for_status(r)
  json <- content(r, as = "text")
  fromJSON(json)$trends[[1]]
}

woeid <- get_woeid("Sacramento", "United States")
get_trends(woeid) %>% arrange(tweet_volume) %>%  select(name)
##                      name
## 1                  LaMelo
## 2                  Pacers
## 3                  Skully
## 4                   Ducks
## 5                   Halle
## 6          Juergen Teller
## 7                Arkansas
## 8                   Paige
## 9                   Hawks
## 10           #EqualityAct
## 11                Rugrats
## 12                 Teresa
## 13                  Glenn
## 14                  Blade
## 15                   Suns
## 16                   Soda
## 17                   KCON
## 18                 Miller
## 19                   F-35
## 20                   jype
## 21                Celtics
## 22               Franklin
## 23                   Jazz
## 24            Nickelodeon
## 25                  LGBTQ
## 26            #SnowfallFX
## 27 Marjorie Taylor Greene
## 28                 Lakers
## 29                 seulgi
## 30                  Saint
## 31                  Trans
## 32               #lakings
## 33         Brian Williams
## 34                 Eakins
## 35           #FlyTogether
## 36                 Yelich
## 37                 Zegras
## 38                  Marge
## 39                  hader
## 40            Mike Conley
## 41         CBS All Access
## 42                #RHOSLC
## 43                 Manboy
## 44                   Bama
## 45           Jared dudley
## 46                  Gasol
## 47           Mark Jackson
## 48             Pastor Cal
## 49               Schroder

Google sheets API (three legged)

An API key of google cannot be used to access personal data on google, we will perform a three-legged OAuth dance.

gooogle_app <- oauth_app(
  "google",
  key = "801676816155-un6m8s99ab1b56lida2gpd9rau9g10nj.apps.googleusercontent.com",
  secret = "9fdIQ-0MVvgpFYtLdnbiEYp1"  # the secret is three legged OAUTH is not really a secret
)

In OAuth, developer needs to specify that information they need from the user

google_token <- oauth2.0_token(
  oauth_endpoints("google"),
  gooogle_app,
  scope = c(
    "profile", 
    "email",
    "https://www.googleapis.com/auth/spreadsheets"
  ),
  cache = TRUE
)

A cache file .httr-oauth will be created to cache the user token so the user don’t have to login everytime. However, treat it carefully, anyone could access your account with the cache.

endpoint <- str_glue(
  "https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{range}",
  spreadsheetId = "1JvqP6R44Rx96kAtEYszDezgUs2hCMp8xPvdZwUIsw-g",
  range = "A:B"
  )
r <- GET(endpoint, config(token = google_token))
## Auto-refreshing stale OAuth token.
stop_for_status(r)
fromJSON(content(r, as = "text"))$values
##      [,1]     [,2]   
## [1,] "item"   "price"
## [2,] "apple"  "2"    
## [3,] "orange" "4"    
## [4,] "grape"  "5"