DEV Community

Andy Haskell
Andy Haskell

Posted on

Build a web API client in Go, Part 1: Connecting to the API

Web APIs are a really exciting part of web development. By communicating with another website, like Twitter, Instagram, Google, or dev.to, you can make web apps that users can use to work with content on those sites and do things like:
📸 Add custom filters to photos and then post them with the Instagram API
📝 Manage blog posts using the dev.to API
🐦 Time your social media posts with the Twitter API

And the open source community makes a whole lot of API clients, which are code packages that let you talk to those APIs using code in your favorite programming language.

Sometimes, though, you'll show up early to the party and you'll want to build a web app with an API before someone made a client for it in the language you're using. In that case, you can still roll your own client. For this tutorial, I'm going to show you how you might do that for the ClimaCell weather API using Go's standard library.

Go really excels with working on web APIs because of its big standard library for handling things like HTTP connections and JSON deserialization, and from its small but elegant object-oriented programming vocabulary. This helps you design API clients that are easy for developers to work with.

This tutorial assumes you know:

  • The fundamentals of Go, which you can learn about on sites like the official Go Tour, exercism.io, and Codecademy's Go course.
  • The fundamentals of HTTP, namely the idea of requests and responses, status codes, and headers and bodies of HTTP requests, which you can learn about here
  • Familiarity with JSON, which you can learn about here

Also knowing about cURL is optional, but helps too, since it lets you talk to HTTP APIs from the command line without a browser.

In the process of writing this tutorial, by the way, I ended up making a ClimaCell client, which is on my GitHub here. If you like API client development and want to contribute to open source, contributors are more than welcome!

🏗 Have something you want to build with the API

Technically you could just dive into an API's documentation to start building a client. However, if you have an app you want to build with the API, that helps a ton because that will have you thinking like the developers who will be building apps using your client as you're designing and documenting your code.

Additionally, since a lot of APIs get really complex, having something you're building will help you prioritize which functionalities to have our client support first. Chances are, at least some of those API functionalities you're working with are ones that a lot of other developers would want first as well!

For our app, the sloths of the Cambridge Fresh Pond (the ones from my webpack tutorial) want to build an app that lets them know what kind of hibiscus tea they should make at 5PM. If it's gonna be below 60°F out at 5, the go-to drink is a hot hibiscus tea, but when it's above 60°, there's nothing more refreshing than a cool glass of iced hibiscus tea!

We have something to build! So for our Go ClimaCell API app, we'll need to:

  • Make an HTTP connection to the API
  • Find which part of the API to talk to for local weather
  • Turn the API's data into Go structs so our code can work with the data

🔑 Authenticate and connect with the API from the command line

For almost every web API out there today, before you can connect with it and start using its data, you need to use the API's mechanism for authentication so the people managing the API know that the person accessing their API data is who they say they are.

For the ClimaCell API, authentication is done with an API key, a string you pass along with HTTP requests that serves kinda like an ID card; if I use my API key, it more or less tells ClimaCell's servers that I'm the registered user making the API call. They can then do stuff like limit my API access to only the features on the free tier, since I didn't sign up for a paid tier with more features.

How do we get an API key? First, go to https://www.climacell.co/weather-api/, and click "start now" to go to the pricing page. We don't need all the fancy features of paid-tier API access, so sign up for the free tier, and they'll email you an API key!

⚠️WARNING!⚠️ For any API you are working with, DO NOT share your API key or other forms of authentication with anyone; don't post it online or email it to your friends, and also don't commit it in your code! If someone else gets ahold of your API key, will be able to send requests as if they were you!

Great, now you've got an API key, so let's try it out in the command line! First, save your key to the environment variable CLIMACELL_API_KEY.

Now, if you have cURL, which is available on Windows, Mac, and Linux and comes standard on a lot of machines, you are able to send the request below from the command line to get some weather data from around Boston.

curl -X GET "https://api.climacell.co/v3/weather/forecast/hourly?lat=42.3826&lon=-71.1460&fields=temp" \
  -H "Accept: application/json" \
  -H "apikey: $CLIMACELL_API_KEY"

You should get back a whole lot of JSON data. If you pretty-print the JSON, it should look something like this:

[
  {
     "lon":              -71.146,
     "lat":              42.3826,
     "temp":             { "value": 5, "units": "C" },
     "observation_time": { "value":"2020-04-24T15:00:00.000Z" },
  }
  // more weather samples above and below
]

Awesome! You got some temperature data!

By the way, if you want the JSON you got in the command line to be formatted for you, a tool I highly recommend for formatting and exploring JSON data is jq, which has installation instructions here. To get back your JSON pretty-printed, you would pipe the cURL output to jq, like this:

curl -X GET "https://api.climacell.co/v3/weather/forecast/hourly?lat=42.3826&lon=-71.1460&fields=temp" \
  -H "Accept: application/json" \
  -H "apikey: $CLIMACELL_API_KEY" | jq

In addition to pretty-printing JSON, jq can also be used to select individual fields in the JSON data that you want to take a closer look at. cURL and jq are great tools to have in an API client developer's toolbelt for exploring the responses your client can work with!

🐹 Connect to the API in Go

We've connected to our API in cURL, so now let's put that API call in Go!

In your $GOPATH, make a folder src/github.com/{YOUR_GITHUB_USERNAME}/tea-temperature. Now, go to that directory and run go mod init to start a fresh Go project!

Then make a file titled main.go with this code:

package main

import (
    "log"
    "io/ioutil"
    "net/http"
    "os"
)

func main() {
    req, err := http.NewRequest(
        http.MethodGet,
        "https://api.climacell.co/v3/weather/forecast/hourly?lat=42.3826&lon=-71.1460&fields=temp",
        nil,
    )
    if err != nil {
        log.Fatalf("error creating HTTP request: %v", err)
    }

    req.Header.Add("Accept", "application/json")
    req.Header.Add("apikey", os.Getenv("CLIMACELL_API_KEY"))

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatalf("error sending HTTP request: %v", err)
    }
    responseBytes, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatalf("error reading HTTP response body: %v", err)
    }

    log.Println("We got the response:", string(responseBytes))
}

To run this, use go run main.go and you should get the JSON response you had gotten previously using cURL. Here's what's going on in the code:

  1. First, we use http.NewRequest to set up a Go http.Request, which is the Go type for the data we'll send in a request to ClimaCell's API.
    req, err := http.NewRequest(
        http.MethodGet,
        "https://api.climacell.co/v3/weather/forecast/hourly?lat=42.3826&lon=-71.1460&fields=temp",
        nil,
    )
  1. Then, in the calls to req.Header.Add, we add the headers from the -H flags on the cURL request to our http.Request.
    req.Header.Add("Accept": "application/json")
    req.Header.Add("apikey", os.Getenv("CLIMACELL_API_KEY"))
  1. Using http.DefaultClient.Do, Go sends the request and gets back the HTTP response in an http.Response struct.
    res, err := http.DefaultClient.Do(req)
  1. The JSON response data is on res.Body, but its type is io.ReadCloser. So to convert it to a byte slice, we pass res.Body into ioutil.ReadAll.
    responseBytes, err := ioutil.ReadAll(res.Body)

Awesome work, you got your Go code to send a request to an API endpoint and get back data as a byte slice! Our progress so far is in commit 1.

In the next tutorial, we will take this byte slice and convert it to a Go struct. And instead of using net/http clients directly for every time we want to talk to the ClimaCell API, we're going to build our own Go ClimaCell API package that will be specialized for ClimaCell API requests.

Until next time, 🦥 STAY SLOTHFUL! 🌺

Top comments (2)

Collapse
 
samirgandhi profile image
samirgandhi

This tutorial was fantastic. As noted in the other comment, the api has changed. This is actually beneficial for learning because it requires you to figure out how to build structs for use in deserialization.

If you're new to Go (like me) and looking at this tutorial I'd recommend spending some time understanding structs and deserialization. This site couples well with this tutorial: sohamkamani.com/golang/json/

Collapse
 
thetimhosking profile image
thetimhosking

Thanks for this very useful tutorial. Just a note for others who may have come to this late like me - the URL used here probably won't work. Use suggested URL when you register with climacell. They are now at v4, so the v3 here doesn't work. I guess it should, but I didn't have the time or motivation to figure it out. Just go with the URL when you get your apikey.
For me that was:
api.tomorrow.io/v4/timelines?locat...