Gowhere – http

I Go (went) a step further—http and other things to consume an API service. What would it take to call an API which returns a list of records in JSON? In .NET, it takes a few lines of code.

Scenario: Display a list of employees—Id, First Name, Last Name, and Joined Date—from a protected API—of a company. The returned value might contain more fields than necessary.

  1. Id: integer
  2. First Name and Last Name: string
  3. Joined Date: Date Time

First thing first, create a file http.go and write some code. To work with http, Go supplies the net/http package.

package main

import (
    "fmt"
    "net/http"
)

func main() {
    fmt.Println("Connecting to the API ...")
    const url = "https://xxxcompany.com/api/employees"

    const accessToken = "base64 access token"

    fmt.Println("Base Address: ", url)
    fmt.Println("Access Token: ", accessToken)

    // Issue a default request but will not work because of the missing access token
    resp, err := http.Get(url)
    if err != nil {
        fmt.Println("Cannot connect the API: ", err)
        return
    }

    // Close the body at the end of the execution
    defer resp.Body.Close()
}

Nothing’s fancy! I took them from the Go http package. When invoking a HTTP call, Go returns a response with an error if there is a connection problem. Go suggests that we must always check for error before usage—a good practice.

The above code will return a 401 status code—Not Authorized. I need to attach the access token to the request. To manipulate the request, I need to create it by myself and ask Go to send it. It is quite easy.

    // Create a custom request with custom headers
    resq, err := http.NewRequest(http.MethodGet, url, nil)
    resq.Header.Add("x-access-token", accessToken)
    // Send the request using the default client supplied by the http
    resp, err := http.DefaultClient.Do(resq)

    if err != nil {
        fmt.Println("Cannot connect the API: ", err)
        return
    }

What did I get from resp.Body? A binary stream.

binary, error:= ioutil.RealAll(resp.Body)

But I need a list of employees which is in JSON format. Go gives me the encoding/json package to decode from binary, represented data in JSON format, to object—struct in Go. So I define an Employee struct—custom data type—to hold the result. The Employee struct has JoinedDate which is a date time—time package is supplied to deal with time.

import (
    "encoding/json"
    "fmt"
    "net/http"
    "time"
)

// Existing code

// Employee
type Employee struct {
    Id         int
    FirstName  string
    LastName   string
    JoinedDate time.Time
}

And it’s time for gardening—decode the binary stream into list of employees

    // Create a decoder with passing the io reader from resp.Body
    decoder := json.NewDecoder(resp.Body)
    // Prepare an empty array of employees
    employees := make([]Employee, 0)
    // Decode, pass the pointer to the employees
    decoder.Decode(&employees)
    // Print the result
    fmt.Println(employees)

Put them all together, I have a working program. Run go run http.go and feel good.

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "time"
)

func main() {
    fmt.Println("Connecting to the API ...")
    const url = "https://xxxcompany.com/api/employees"

    const accessToken = "base64 access token"

    fmt.Println("Base Address: ", url)
    fmt.Println("Access Token: ", accessToken)

    // Create a custom request with custom headers
    resq, err := http.NewRequest(http.MethodGet, url, nil)
    resq.Header.Add("x-access-token", accessToken)
    // Send the request using the default client supplied by the http
    resp, err := http.DefaultClient.Do(resq)

    if err != nil {
        fmt.Println("Cannot connect the API: ", err)
        return
    }

    // Close the body at the end of the execution
    defer resp.Body.Close()

    // Create a decoder with passing the io reader from resp.Body
    decoder := json.NewDecoder(resp.Body)
    // Prepare an empty array of employees
    employees := make([]Employee, 0)
    // Decode, pass the pointer to the employees
    decoder.Decode(&employees)
    // Print the result
    fmt.Println(employees)
}

// Employee
type Employee struct {
    Id         int
    FirstName  string
    LastName   string
    JoinedDate time.Time
}

Go where? One step further.

  1. 3 new packages: net/http, encoding/json, time
  2. Create custom http requests
  3. Define a new type via struct—class in C#
  4. Decode from binary stream—JSON data—to an array of object
  5. Use make method to create an object from a type

It makes my day, especially for the weekend!

Write a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.