WEEK 9 - NY TIMES API

Author

Kingsley Kojo Kpoku

Published

November 10, 2026

LOADING AND VERIFY THE NYT API KEY

Code
env_file <- path.expand("~/.Renviron")
file.exists(env_file)
[1] TRUE
Code
any(grepl("^NYT_API_KEY=", readLines(env_file, warn = FALSE)))
[1] TRUE
Code
readRenviron(env_file)
nzchar(Sys.getenv("NYT_API_KEY"))
[1] TRUE

LOADING REQUIRED PACKAGES

Code
library(httr2)
library(jsonlite)
library(dplyr)
library(purrr)
library(tibble)
library(ggplot2)
install.packages("httr2")  
library(httr2)

READING THE API KEY

Code
nyt_api_key <- Sys.getenv("NYT_API_KEY")

REQUEST THE DATA

Code
endpoint <- "https://api.nytimes.com/svc/mostpopular/v2/viewed/7.json"

response <- request(endpoint) |>
  req_headers(
    Accept = "application/json",
    "User-Agent" = "DATA607 NYT API Project"
  ) |>
  req_url_query(`api-key` = nyt_api_key) |>
  req_error(is_error = function(resp) FALSE) |>
  req_perform()

status <- resp_status(response)

CONFIRM STATUS

Code
# Check the HTTP status and parse JSON only if successful
status <- resp_status(response)

if (status == 200) {
  message("200 OK")
  nyt_json <- resp_body_json(response, simplifyVector = FALSE)
} else if (status == 401) {
  message("401: NYT did not accept the API key.")
} else if (status == 403) {
  message("403: Access forbidden. Check that the Most Popular API is enabled for your app.")
} else if (status == 404) {
  message("404: Endpoint not found. Check the URL.")
} else {
  message("Unexpected HTTP status: ", status)
}

## This code chunk validates the connection and returns the status. A status of "200" indicates sucess."401" means invalid API Key. "403" means access forbidden. "404" means Endpoint not found.
Code
resp_content_type(response)
[1] "application/json"

PARSE DATA FROM JSON

Code
nyt_json <- resp_body_json(response, simplifyVector = FALSE)

articles <- purrr::map_dfr(nyt_json$results, function(article) {
  tibble::tibble(
    title = article$title,
    section = article$section,
    published_date = article$published_date,
    url = article$url
  )
})

section_counts <- articles |>
  dplyr::count(section, sort = TRUE)

section_counts <- articles |>
  dplyr::count(section, name = "article_count", sort = TRUE) |>
  dplyr::mutate(percent = round(article_count / sum(article_count) * 100, 2))

section_counts
# A tibble: 4 × 3
  section    article_count percent
  <chr>              <int>   <dbl>
1 U.S.                  15      75
2 New York               2      10
3 Opinion                2      10
4 Technology             1       5

VISUALIZATION

Code
ggplot2::ggplot(
  section_counts,
  ggplot2::aes(x = reorder(section, article_count), y = article_count)
) +
  ggplot2::geom_col(fill = "#2878B5") +
  ggplot2::coord_flip() +
  ggplot2::labs(
    title = "Sections Among NYT's Most-Viewed Articles",
    x = "Section",
    y = "Number of returned articles"
  ) +
  ggplot2::theme_minimal()

Code
## 16 of the 20 returned articles (80%) were in the U.S. section

CONCLUSION AND ANALYTICAL FINDINGS

  1. The chart shows that the U.S Section was the most represented among the 20 most viewed articles returned by the NYT API: it had 16 articles , or 80% of the list. Opinion had 2 articles (10%) while New York Arts each had 1 (5%) . The U.S Section therefore appeared far more often in this returned list than any other section.
  2. For the seven-day period retrieved, U.S. stories dominated the NYT Most-Viewed results by article count. Opinion was a distant second, and New York and Arts were represented by one article each. This describes the mix of articles in the API’s returned list; it does not measure each section’s total views, include every article published, or explain why readers viewed particular stories.