API Explorer

Websites are often better than spreadsheets at presenting information.

Shiny
R
Author

Steven Villalon

Published

June 17, 2025


Question of Interest

How do I make this data set easier to digest?

Goal: Make a Shiny app that would display a summary of information for a given API.

1. Packages & Dependencies

Show Code
# Load packages
library(tidyverse)
library(tidytuesdayR)
library(here)
library(showtext)
library(ggtext)
library(scales)
library(shiny)

# Load helper functions
source(here::here("R/utils/tidy_tuesday_helpers.R"))

# Set project title
title <- "API Specs"
tt_date <- "2025-06-17"

2. Load Data

Show Code
# Load data from tidytuesdayR package
tuesdata <- tidytuesdayR::tt_load(tt_date)

# Extract elements from tuesdata
categories <- tuesdata$api_categories
info <- tuesdata$api_info
logos <- tuesdata$api_logos
origins <- tuesdata$api_origins
apisguru_apis <- tuesdata$apisguru_apis

# Remove tuesdata file
rm(tuesdata)

3. Examine Data

Show Code
# View data
head(categories)
# A tibble: 6 × 2
  name                          apisguru_category
  <chr>                         <chr>            
1 1forge.com                    financial        
2 1password.com:events          security         
3 1password.local:connect       security         
4 6-dot-authentiqio.appspot.com security         
5 ably.io:platform              cloud            
6 ably.net:control              cloud            
Show Code
head(info)
# A tibble: 6 × 10
  name     contact_name contact_url description title provider_name service_name
  <chr>    <chr>        <chr>       <chr>       <chr> <chr>         <chr>       
1 1forge.… 1Forge       http://1fo… "Stock and… 1For… 1forge.com    <NA>        
2 1passwo… <NA>         <NA>        "1Password… Even… 1password.com events      
3 1passwo… 1Password I… https://su… "REST API … 1Pas… 1password.lo… connect     
4 6-dot-a… Authentiq t… http://aut… "Strong au… Auth… 6-dot-authen… <NA>        
5 ably.io… Ably Support https://ww… "The [REST… Plat… ably.io       platform    
6 ably.ne… <NA>         <NA>        "Use the C… Cont… ably.net      control     
# ℹ 3 more variables: license_name <chr>, license_url <chr>,
#   terms_of_service <chr>
Show Code
head(logos)
# A tibble: 6 × 4
  name                          background_color url                    alt_text
  <chr>                         <chr>            <chr>                  <chr>   
1 1forge.com                    #24292e          https://api.apis.guru… <NA>    
2 1password.com:events          <NA>             https://api.apis.guru… <NA>    
3 1password.local:connect       <NA>             https://api.apis.guru… <NA>    
4 6-dot-authentiqio.appspot.com #F26641          https://api.apis.guru… <NA>    
5 ably.io:platform              <NA>             https://api.apis.guru… <NA>    
6 ably.net:control              <NA>             https://api.apis.guru… <NA>    
Show Code
head(origins)
# A tibble: 6 × 4
  name                          format  url                              version
  <chr>                         <chr>   <chr>                            <chr>  
1 1forge.com                    swagger http://1forge.com/openapi.json   2.0    
2 1password.com:events          openapi https://i.1password.com/media/1… 3.0    
3 1password.local:connect       openapi https://i.1password.com/media/1… 3.0    
4 6-dot-authentiqio.appspot.com openapi https://raw.githubusercontent.c… 3.0    
5 ably.io:platform              openapi https://raw.githubusercontent.c… 3.0    
6 ably.net:control              openapi https://raw.githubusercontent.c… 3.0    
Show Code
head(apisguru_apis)
# A tibble: 6 × 9
  name   version added               updated             swagger_url openapi_ver
  <chr>  <chr>   <dttm>              <dttm>              <chr>       <chr>      
1 1forg… 0.0.1   2017-05-30 08:34:14 2017-06-27 16:49:57 https://ap… 2.0        
2 1pass… 1.0.0   2021-07-19 10:17:09 2023-02-27 15:08:09 https://ap… 3.0.0      
3 1pass… 1.5.7   2021-04-16 15:56:45 2023-02-27 15:07:17 https://ap… 3.0.2      
4 6-dot… 6       2017-03-15 14:45:58 2021-06-21 12:16:53 https://ap… 3.0.0      
5 ably.… 1.1.0   2019-07-13 11:28:07 2021-07-26 09:42:14 https://ap… 3.0.1      
6 ably.… 1.0.14  2021-07-26 09:45:31 2021-07-26 09:47:48 https://ap… 3.0.1      
# ℹ 3 more variables: link <chr>, external_docs_description <chr>,
#   external_docs_url <chr>

4. Cleaning

Show Code
# Flatten categories
categories_clean <- categories |> 
  group_by(name)  |> 
  summarize(apisguru_category = str_flatten(apisguru_category, collapse = ", "), .groups = "drop")

str(categories_clean)
tibble [2,341 × 2] (S3: tbl_df/tbl/data.frame)
 $ name             : chr [1:2341] "1forge.com" "1password.com:events" "1password.local:connect" "6-dot-authentiqio.appspot.com" ...
 $ apisguru_category: chr [1:2341] "financial" "security" "security" "security" ...
Show Code
# Remove unnecessary columns
apisguru_apis_clean <- apisguru_apis |> 
  select(name, version, added, updated, openapi_ver) |> 
  rename(preferred_version = version)

str(apisguru_apis_clean)
tibble [2,529 × 5] (S3: tbl_df/tbl/data.frame)
 $ name             : chr [1:2529] "1forge.com" "1password.com:events" "1password.local:connect" "6-dot-authentiqio.appspot.com" ...
 $ preferred_version: chr [1:2529] "0.0.1" "1.0.0" "1.5.7" "6" ...
 $ added            : POSIXct[1:2529], format: "2017-05-30 08:34:14" "2021-07-19 10:17:09" ...
 $ updated          : POSIXct[1:2529], format: "2017-06-27 16:49:57" "2023-02-27 15:08:09" ...
 $ openapi_ver      : chr [1:2529] "2.0" "3.0.0" "3.0.2" "3.0.0" ...
Show Code
# Remove unnecessary columns
info_clean <- info |> 
  select(name, description, title, provider_name, service_name)

str(info_clean)
tibble [2,529 × 5] (S3: tbl_df/tbl/data.frame)
 $ name         : chr [1:2529] "1forge.com" "1password.com:events" "1password.local:connect" "6-dot-authentiqio.appspot.com" ...
 $ description  : chr [1:2529] "Stock and Forex Data and Realtime Quotes" "1Password Events API Specification." "REST API interface for 1Password Connect." "Strong authentication, without the passwords." ...
 $ title        : chr [1:2529] "1Forge Finance APIs" "Events API" "1Password Connect" "Authentiq API" ...
 $ provider_name: chr [1:2529] "1forge.com" "1password.com" "1password.local" "6-dot-authentiqio.appspot.com" ...
 $ service_name : chr [1:2529] NA "events" "connect" NA ...
Show Code
# Remove unnecessary columns
origins_clean <- origins |> 
  select(name, format, version) |> 
  rename(api_spec_version = version)

# Remove duplicate rows (multiple URLs)
origins_clean <- origins_clean |> 
    group_by(name) |> 
  mutate(row_is_min_or_na = if_else(
    n() > 1 & (is.na(api_spec_version) | api_spec_version == min(api_spec_version, na.rm = TRUE)),
    TRUE, FALSE
  )) |> 
  filter(!row_is_min_or_na | n() == 1) |> 
  select(-row_is_min_or_na) |> 
  ungroup()

str(origins_clean)
tibble [2,525 × 3] (S3: tbl_df/tbl/data.frame)
 $ name            : chr [1:2525] "1forge.com" "1password.com:events" "1password.local:connect" "6-dot-authentiqio.appspot.com" ...
 $ format          : chr [1:2525] "swagger" "openapi" "openapi" "openapi" ...
 $ api_spec_version: chr [1:2525] "2.0" "3.0" "3.0" "3.0" ...
Show Code
# Remove unnecessary columns
logos_clean <- logos |> 
  select(name, url)

str(logos_clean)
tibble [2,529 × 2] (S3: tbl_df/tbl/data.frame)
 $ name: chr [1:2529] "1forge.com" "1password.com:events" "1password.local:connect" "6-dot-authentiqio.appspot.com" ...
 $ url : chr [1:2529] "https://api.apis.guru/v2/cache/logo/https_1forge.com_assets_images_f-blue.svg" "https://api.apis.guru/v2/cache/logo/https_upload.wikimedia.org_wikipedia_commons_thumb_e_e3_1password-logo.svg_"| __truncated__ "https://api.apis.guru/v2/cache/logo/https_upload.wikimedia.org_wikipedia_commons_thumb_e_e3_1password-logo.svg_"| __truncated__ "https://api.apis.guru/v2/cache/logo/https_www.authentiq.com_theme_images_authentiq-logo-a-inverse.svg" ...
Show Code
# List tables to join
tables <- list(apisguru_apis_clean, categories_clean, info_clean, logos_clean, origins_clean)

# Inner join all 5 tables
df <- reduce(tables, inner_join, by = "name")

str(df)
tibble [2,337 × 13] (S3: tbl_df/tbl/data.frame)
 $ name             : chr [1:2337] "1forge.com" "1password.com:events" "1password.local:connect" "6-dot-authentiqio.appspot.com" ...
 $ preferred_version: chr [1:2337] "0.0.1" "1.0.0" "1.5.7" "6" ...
 $ added            : POSIXct[1:2337], format: "2017-05-30 08:34:14" "2021-07-19 10:17:09" ...
 $ updated          : POSIXct[1:2337], format: "2017-06-27 16:49:57" "2023-02-27 15:08:09" ...
 $ openapi_ver      : chr [1:2337] "2.0" "3.0.0" "3.0.2" "3.0.0" ...
 $ apisguru_category: chr [1:2337] "financial" "security" "security" "security" ...
 $ description      : chr [1:2337] "Stock and Forex Data and Realtime Quotes" "1Password Events API Specification." "REST API interface for 1Password Connect." "Strong authentication, without the passwords." ...
 $ title            : chr [1:2337] "1Forge Finance APIs" "Events API" "1Password Connect" "Authentiq API" ...
 $ provider_name    : chr [1:2337] "1forge.com" "1password.com" "1password.local" "6-dot-authentiqio.appspot.com" ...
 $ service_name     : chr [1:2337] NA "events" "connect" NA ...
 $ url              : chr [1:2337] "https://api.apis.guru/v2/cache/logo/https_1forge.com_assets_images_f-blue.svg" "https://api.apis.guru/v2/cache/logo/https_upload.wikimedia.org_wikipedia_commons_thumb_e_e3_1password-logo.svg_"| __truncated__ "https://api.apis.guru/v2/cache/logo/https_upload.wikimedia.org_wikipedia_commons_thumb_e_e3_1password-logo.svg_"| __truncated__ "https://api.apis.guru/v2/cache/logo/https_www.authentiq.com_theme_images_authentiq-logo-a-inverse.svg" ...
 $ format           : chr [1:2337] "swagger" "openapi" "openapi" "openapi" ...
 $ api_spec_version : chr [1:2337] "2.0" "3.0" "3.0" "3.0" ...
Show Code
# Fill NAs in service_name column
df <- df |> 
  mutate(service_name = coalesce(service_name, title))

5. Export to CSV

Show Code
# Create CSV file
write_csv(df, "data/data_for_api_app.csv")

6. Session Info

R version 4.4.1 (2024-06-14)
Platform: x86_64-apple-darwin20
Running under: macOS Ventura 13.7.6

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/New_York
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] shiny_1.10.0       scales_1.4.0       ggtext_0.1.2       showtext_0.9-7    
 [5] showtextdb_3.0     sysfonts_0.8.9     here_1.0.1         tidytuesdayR_1.2.1
 [9] lubridate_1.9.4    forcats_1.0.0      stringr_1.5.1      dplyr_1.1.4       
[13] purrr_1.0.4        readr_2.1.5        tidyr_1.3.1        tibble_3.2.1      
[17] ggplot2_3.5.2      tidyverse_2.0.0   

loaded via a namespace (and not attached):
 [1] utf8_1.2.5         rappdirs_0.3.3     generics_0.1.4     xml2_1.3.8        
 [5] stringi_1.8.7      hms_1.1.3          digest_0.6.37      magrittr_2.0.3    
 [9] evaluate_1.0.3     grid_4.4.1         timechange_0.3.0   RColorBrewer_1.1-3
[13] fastmap_1.2.0      rprojroot_2.0.4    jsonlite_2.0.0     promises_1.3.3    
[17] httr2_1.1.2        cli_3.6.5          crayon_1.5.3       rlang_1.1.6       
[21] gitcreds_0.1.2     bit64_4.6.0-1      withr_3.0.2        yaml_2.3.10       
[25] parallel_4.4.1     tools_4.4.1        tzdb_0.5.0         httpuv_1.6.16     
[29] curl_6.2.3         mime_0.13          vctrs_0.6.5        R6_2.6.1          
[33] lifecycle_1.0.4    bit_4.6.0          htmlwidgets_1.6.4  vroom_1.6.5       
[37] pkgconfig_2.0.3    pillar_1.10.2      later_1.4.2        gtable_0.3.6      
[41] gh_1.5.0           glue_1.8.0         Rcpp_1.0.14        xfun_0.52         
[45] tidyselect_1.2.1   knitr_1.50         xtable_1.8-4       farver_2.1.2      
[49] htmltools_0.5.8.1  rmarkdown_2.29     compiler_4.4.1     gridtext_0.1.5    
Back to top