Class 607, Assignment 6 (week 9)

Author

Troy Tournat

Published

October 28, 2026


Introduction

I selected the most popular emailed articles on NYT’s website for the past 30 days. My question is what was the most popular emailed article types on NYT’s website for the past 30 days?

Tackling the problem: First I’ll need to review NYT’s API instructions to use their public APIs. After authenticating the API Key and getting the HTTP request I’ll create an r environment to store the key. Then I’ll use the HTTP request and API key to make the request to the end point. I’ll begin parsing the JSON response using the httr2 package and reference Prof Gomez’s week9 slide deck. Then I’ll bring everything into a dataframe with some cleaned variables.

Anticipated data challenges: I anticipate I will run into the most issues successfully making the API request, and parsing the JSON file.

Citations:

Analysis

API key (not shown)

Packages

Code
#Install packages needed 
pacman::p_load(
  # Package Install and Management
  pacman,           # package install/load
  janitor,          #clean up data names 
  
  # Project and File Management
  readr,            # import data
  httr,             #github passkey 
  usethis,          #r environment
  RPostgres,        #SQL 
  DBI,              #SQL 
  jsonlite,         #working with json
  rvest,           #html files
  rstuioapi,        #api
  knitr,            #displaying data in quarto
  
  # General Data Management
  dplyr,            # data management
  tidyr,            # data management
  skimr,            # data management 
  lubridate,        # work with dates
  zoo,              # work with dates
  tidyverse,        # work with dates
  scales,           # ggplot 
  gmodels,          # freq tables SAS 
  patchwork        #data visualization, side by side 

)

#API specific
library(tibble)
library(httr2)
library(RSQLite)

Make a request to the endpoint

Code
# The endpoint returns records for most popular NYT articles
api_url <- paste0(
  "https://api.nytimes.com/svc/mostpopular/v2/emailed/30.json")

# request() starts an HTTP request with the API URL.
req <- request(api_url) |> 
  req_url_query(`api-key` = nyt_key_pop)
# req_headers() adds information the server expects from our client.

# req_dry_run() previews the request without sending it.
req_dry_run(req)
GET /svc/mostpopular/v2/emailed/30.json HTTP/1.1
accept: */*
accept-encoding: deflate, gzip
host: api.nytimes.com
user-agent: httr2/1.3.0 r-curl/8.1.0 libcurl/8.14.1-DEV
Code
# req_perform() sends the request and keeps the server response.
resp <- req |> req_perform()

# Confirm that the server accepted the request.
resp_status(resp) #200
[1] 200
Code
resp_status_desc(resp)
[1] "OK"
Code
resp_content_type(resp)
[1] "application/json"

Parse the JSON response

Code
## Read the JSON body 
# Parse the JSON response into an R list.
pop_json <- resp |>
  resp_body_json(simplifyVector = TRUE)

# Inspect the top-level fields before extracting data.
names(pop_json)
[1] "status"      "copyright"   "num_results" "results"    

Transform the result into a clean R data frame, dropped nested, and add retrieval time

Only data cleaning ID variables in order to see the whole number (it was in scientific notation). Not cleaning up date variables since saving to SQL file, and as.date format doesn’t work.

Code
## Create a data frame from results (will say data.frame)
# Keep the match details 
df <- pop_json$results%>% 
  mutate(id = as.character(id), 
         asset_id = as.character(asset_id))%>% 
  select(-where(is.list)) # need to drop any other nested columns 
#sapply(matches_snapshot, class) 
#names(matches_snapshot)[sapply(matches_snapshot, is.list)]


#An API can change between requests. Save the retrieval time and source URL with the values you used.
# Use UTC so each timestamp has one unambiguous time zone.
retrieved_at <- format(Sys.time(), tz = "UTC", usetz = TRUE)

matches_snapshot <- df |>
  mutate(
    retrieved_at = retrieved_at,
    request_url = api_url,
    .before = 1)

Most popular emailed article types on NYT’s website for the past 30 days?

4 (20%) popular opinion pieces made up the most types of popular emailed articles the past month.

Code
#which type of article was popular this last month? 
counts <- matches_snapshot %>%
  count(nytdsection, name = "n") %>%
  mutate(pct_total = n / sum(n)) %>%
  arrange(desc(n))

#graph
counts |>
  ggplot(aes(x = fct_reorder(nytdsection, n, .desc = TRUE), y = n)) +
  geom_col(fill = "#1f77b4") +
  geom_text(
    aes(label = paste0(comma(n), " (", percent(pct_total, accuracy = 0.1), ")")),
    position = position_stack(vjust = 0.8),
    color = "white",
    size = 2.5,
    fontface = "bold"
  ) +
  labs(
    title = "Most popular emailed article types on NYT's website for the past 30 days?"
  ) +
  scale_y_continuous(labels = label_comma()) +
  labs(x = NULL, y = "Count")

Store data in .sqlite

Code
# Connect to a local SQLite file in the Week 9 folder.
con <- dbConnect(SQLite(), "nyt_df.sqlite", extended_types = TRUE)

# Append this retrieval without deleting earlier snapshots.
dbWriteTable(con, "df", matches_snapshot, overwrite = TRUE)

# Always close the connection when finished.
dbDisconnect(con)

Use saved data rather than opening API connection

For reproducible work, save the request URL, retrieval time, and source documentation with every API snapshot.

Code
# Reconnect and read saved rows from the local database.
con <- dbConnect(SQLite(), "nyt_df.sqlite", extended_types = TRUE)

saved_matches <- dbGetQuery(
  con,
  "SELECT *
   FROM df
   ORDER BY retrieved_at DESC, published_date DESC"
)

dbDisconnect(con)

skim(saved_matches)
Data summary
Name saved_matches
Number of rows 20
Number of columns 19
_______________________
Column type frequency:
character 17
numeric 2
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
retrieved_at 0 1 23 23 0 1 0
request_url 0 1 58 58 0 1 0
uri 0 1 50 54 0 20 0
url 0 1 72 105 0 20 0
id 0 1 15 15 0 20 0
asset_id 0 1 15 15 0 20 0
source 0 1 14 14 0 1 0
published_date 0 1 10 10 0 13 0
updated 0 1 19 19 0 20 0
section 0 1 4 11 0 11 0
subsection 0 1 0 11 13 6 0
nytdsection 0 1 4 11 0 11 0
adx_keywords 0 1 65 284 0 20 0
byline 0 1 13 39 0 20 0
type 0 1 7 11 0 2 0
title 0 1 27 78 0 20 0
abstract 0 1 48 172 0 20 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
column 20 0 NaN NA NA NA NA NA NA
eta_id 0 1 0 0 0 0 0 0 0 ▁▁▇▁▁

Conclusion

After many trials and errors I successfully accessed the NYT public API’s, authenticated the correct key I needed, added it to my .renviroment script, and made the request to the end point.

I followed the outline of the week 8 and 9 slide deck to parse the JSON script and flatten it to a dataframe in order to answer my original question “what was the most popular emailed article types on NYT’s website for the past 30 days?”

I saved the data frame as a sqlite file and was able to successfully re-connect.

Next, I would want to set up automatic data collection so I could do further data analysis more than 30 days of data.