Author

Josh Day

Published

November 4, 2021

Using JSON Web APIs from Julia

A common way to access data is through web APIs that return a JSON response. This article demonstrates implementing a user-friendly wrapper for the XKCD webcomic’s API using Julia.

using HTTP, JSON

Getting the Data

The xkcd service provides two API endpoints:

  • https://xkcd.com/info.0.json (most recent comic)
  • https://xkcd.com/{i}/info.0.json (specific comic by number)
res = HTTP.get("https://xkcd.com/552/info.0.json");

Parsing JSON Responses

The JSON.jl package handles JSON interpretation:

JSON.parse(String(res.body))
JSON.Object{String, Any} with 11 entries:
  "month"      => "3"
  "num"        => 552
  "link"       => ""
  "year"       => "2009"
  "news"       => ""
  "safe_title" => "Correlation"
  "transcript" => "[[A man is talking to a woman]]\nMan: I used to think correl…
  "alt"        => "Correlation doesn't imply causation, but it does waggle its …
  "img"        => "https://imgs.xkcd.com/comics/correlation.png"
  "title"      => "Correlation"
  "day"        => "6"

Creating a User-Friendly Interface

A custom struct simplifies access:

struct Comic
    json::Dict
end

Comic() = Comic(JSON.parse(String(HTTP.get("https://xkcd.com/info.0.json").body)))

Comic(i::Int) = Comic(JSON.parse(String(HTTP.get("https://xkcd.com/$i/info.0.json").body)))
Comic

Obtaining comic metadata becomes as simple as Comic(552):

Comic(552)
Comic(Dict{String, Any}("day" => "6", "alt" => "Correlation doesn't imply causation, but it does waggle its eyebrows suggestively and gesture furtively while mouthing 'look over there'.", "year" => "2009", "num" => 552, "link" => "", "safe_title" => "Correlation", "img" => "https://imgs.xkcd.com/comics/correlation.png", "news" => "", "month" => "3", "title" => "Correlation"…))

Handling API Authorization

For APIs requiring keys, use environment variables to avoid accidental version control commits:

function Comic(i::Int)
    apikey = ENV["MY_API_KEY"]
    url = "https://xkcd.com/$i/info.0.json?apikey=$apikey"
    data = JSON.parse(String(HTTP.get(url).body))
    Comic(data)
end

Enhanced Display Method

Create custom HTML rendering for notebooks and Pluto environments:

function Base.show(io::IO, ::MIME"text/html", c::Comic)
    show(io, MIME"text/html"(), HTML("""
       <div>
        <h2><code>XKCD.Comic</code> $(c.json["num"]): $(c.json["title"])</h2>
        <img src="$(c.json["img"])" alt="$(c.json["alt"])" title="$(c.json["alt"])">
        <div>
          <a href="https://xkcd.com/$(c.json["num"])">
            Link to Original
          </a>
        </div>
      </div>
    """))
end

Comic(552)

XKCD.Comic 552: Correlation

Correlation doesn't imply causation, but it does waggle its eyebrows suggestively and gesture furtively while mouthing 'look over there'.

This approach enables seamless comic visualization in interactive Julia environments.