Creating an API Client in Go
When consuming a REST API it's a good practice to write an API Client (API Wrapper) for yourself or your own REST API, so other users could more easily access it.
Fortunately, Go provides everything we need out of the box. The net/http library combined with other Go base libraries is all we need to write our own API Clients.
The Basics
Let's start with the basics. The package should be the named after the API that is being wrapped (such as twitter, slack or scaledrone). We'll call it myservice
in this example.
One of the most popular methods of REST API authentication is Basic Authentication. We'll ask the user for a username and password.
package myservice
const baseURL string = "https://www.myservice.com/v1"
type Client struct {
Username string
Password string
}
func NewBasicAuthClient(username, password string) *Client {
return &Client{
Username: username,
Password: password,
}
}
POST request
Myservice has an imaginary endpoint POST /:username/todos
for creating todos.
Since Go doesn't have template strings can use fmt.Sprintf
instead. Next, let's create the request and use the doRequest
function to execute it.
type Todo struct {
ID int `json:"id"`
Content string `json:"content"`
Done bool `json:"done"`
}
func (s *Client) AddTodo(todo *Todo) error {
url := fmt.Sprintf(baseURL+"/%s/todos", s.Username)
fmt.Println(url)
j, err := json.Marshal(todo)
if err != nil {
return err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(j))
if err != nil {
return err
}
_, err = s.doRequest(req)
return err
}
Sending the request
The doRequest
function will take a http.Request
object, set the Authentication header and then run the HTTP request.
func (s *Client) doRequest(req *http.Request) ([]byte, error) {
req.SetBasicAuth(s.Username, s.Password)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if 200 != resp.StatusCode {
return nil, fmt.Errorf("%s", body)
}
return body, nil
}
GET request
The GET request works similarly to the POST request, but now we also need to Unmarshal the response into a struct.
func (s *Client) GetTodo(id int) (*Todo, error) {
url := fmt.Sprintf(baseURL+"/%s/todos/%d", s.Username, id)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
bytes, err := s.doRequest(req)
if err != nil {
return nil, err
}
var data Todo
err = json.Unmarshal(bytes, &data)
if err != nil {
return nil, err
}
return &data, nil
}
You are done 🎉. Let's try the API Client out in action!
Putting the API Client to use
After you have published your API Client to git you can import and use it like so.
package main
import "github.com/username/myservice"
func main() {
client := myservice.NewBasicAuthClient("username", "password")
todo := Todo{
Content: "New Todo",
Done: true,
}
// Add a todo
_ := client.AddTodo(&todo)
// Fetch a todo
t, _ := client.GetTodo(1)
}
If you have any questions or feedback, please get in touch.