Building an API

API stands for Application Programming Interface, it is just an interface to the webapp. When we use a browser to access a web application, we interact in HTTP and get back HTML pages, which the browser will render for us. Let’s say we want to interact with our web app to get some data out of it using a host programming language like Go or Python. We’d have to maintain cookies in Python, or write a python module as an extension of a browser to handle this scenario.

There is a simple way out of this, we equip our web application itself to interact with any host language which can talk in HTTP. This way developers can easily get access to our system, using valid credentials, of course.

Browser:

  1. We send the username,password and get a cookie stored on our machine.
  2. We use the token in the cookie until it is valid to send HTTP requests.
  3. The browser is responsible for rendering the HTML pages sent by the server.

API:

  1. We send the username, password and get a token.
  2. We send this token in each of our request to the server

Typically we send the token in a custom HTTP header called token.

When we use a browser, the server stores our information as a session, when we send it a request, it is aware of our session. A web app typically uses cookies to store the session ID, which is used to identify the user. Such a server is called a stateful server.

When we write APIs, they are stateless servers, they do not store sessions information anywhere on the server. To it, each request is unique. Which is why, we need to pass along the authentication token in each request.

Note: Don’t mess around with tokens

There are apps where “single sign in” feature is available, the user has to log in only once and they are logged in forever, this is very dangerous. Because if a malicious person gets their hands on the security token, they can send malicious requests for data which look genuine and are impossible to clasify as malicious. Don’t do this, always have some expiration time for security tokens, depends on your application really, two hours, six hours, but never infinite hours.

JWT

JSON Web Tokens is a standard for generating tokens. We will use the jwt-go library.

Lets start by defining our routes

 1 http.HandleFunc("/api/get-task/", views.GetTasksFuncAPI)
 2 http.HandleFunc("/api/get-deleted-task/", views.GetDeletedTaskFuncAPI)
 3 http.HandleFunc("/api/add-task/", views.AddTaskFuncAPI)
 4 http.HandleFunc("/api/update-task/", views.UpdateTaskFuncAPI)
 5 http.HandleFunc("/api/delete-task/", views.DeleteTaskFuncAPI)
 6 
 7 http.HandleFunc("/api/get-token/", views.GetTokenHandler)
 8 http.HandleFunc("/api/get-category/", views.GetCategoryFuncAPI)
 9 http.HandleFunc("/api/add-category/", views.AddCategoryFuncAPI)
10 http.HandleFunc("/api/update-category/", views.UpdateCategoryFuncAPI)
11 http.HandleFunc("/api/delete-category/", views.DeleteCategoryFuncAPI)

file: $GOPATH/src/github.com/thewhitetulip/Tasks/main.go

We will have the same URLs for the API, but it’ll start with /api/

Our logic is that we will send the username and password in a POST request to /api/get-token/ that will return the token for us.

We are using jwt-go version 3. We have to define a custom claims struct which we will use in token generation and token verification. It’ll contain the StandardClaims class and whichever extra fields we require.

1 type MyCustomClaims struct {
2     Username string `json:"username"`
3     jwt.StandardClaims
4 }

file: $GOPATH/src/github.com/thewhitetulip/Tasks/views/api.go

 1 import "github.com/dgrijalva/jwt-go"
 2 var mySigningKey = []byte("secret")
 3 
 4 
 5 //GetTokenHandler will get a token for the username and password
 6 func GetTokenHandler(w http.ResponseWriter, r *http.Request) {
 7     if r.Method != "POST" {
 8         w.Write([]byte("Method not allowed"))
 9         return
10     }
11 
12     r.ParseForm()
13     username := r.Form.Get("username")
14     password := r.Form.Get("password")
15     log.Println(username, " ", password)
16     if username == "" || password == "" {
17         w.Write([]byte("Invalid Username or password"))
18         return
19     }
20     if db.ValidUser(username, password) {
21         /* Set token claims */
22 
23         // Create the Claims
24         claims := MyCustomClaims{
25             username,
26             jwt.StandardClaims{
27                 ExpiresAt: time.Now().Add(time.Hour * 5).Unix(),
28             },
29         }
30 
31         token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
32 
33         /* Sign the token with our secret */
34         tokenString, err := token.SignedString(mySigningKey)
35         if err != nil {
36             log.Println("Something went wrong with signing token")
37             w.Write([]byte("Authentication failed"))
38             return
39         }
40 
41         /* Finally, write the token to the browser window */
42         w.Write([]byte(tokenString))
43     } else {
44         w.Write([]byte("Authentication failed"))
45     }
46 }

We need to send a POST request to /api/get-token/ with the username and password in the Form data.

If the HTTP method is anything other than POST, we throw an error, if the username and password is wrong we throw an error, otherwise, we generate a token and send it to the client.

The client will now use this token for future requests, the ValidateToken function will validate the token.

 1 //ValidateToken will validate the token
 2 func ValidateToken(myToken string) (bool, string) {
 3     token, err := jwt.ParseWithClaims(myToken, &MyCustomClaims{}, func(token *jwt.To\
 4 ken) (interface{}, error) {
 5         return []byte(mySigningKey), nil
 6     })
 7 
 8     if err != nil {
 9         return false, ""
10     }
11 
12     claims := token.Claims.(*MyCustomClaims)
13     return token.Valid, claims.Username
14 }

We’ll call the Parse method on the token which we receive as a parameter in the function call. The token.Valid field is a boolen variable which is true if the token is valid and false otherwise.

Making an API call

Making an API call is analogous to our normal view.

 1 //GetCategoryFuncAPI will return the categories for the user
 2 //depends on the ID that we get, if we get all, then return all 
 3 //categories of the user
 4 func GetCategoryFuncAPI(w http.ResponseWriter, r *http.Request) {
 5     if r.Method == "GET" {
 6         var err error
 7         var message string
 8         var status types.Status
 9         //get the custom HTTP header called Token
10         token := r.Header["Token"][0]
11 
12         w.Header().Set("Content-Type", "application/json; charset=UTF-8")
13 
14         IsTokenValid, username := ValidateToken(token)
15         //When the token is not valid show the 
16         //default error JSON document
17         if !IsTokenValid {
18             status = types.Status
19             {
20                 StatusCode: http.StatusInternalServerError, 
21                 Message: message
22             }
23             w.WriteHeader(http.StatusInternalServerError)
24             //the following statement will write the JSON document to
25             //the HTTP ResponseWriter object.
26             err = json.NewEncoder(w).Encode(status)
27 
28             if err != nil {
29                 panic(err)
30             }
31             return
32         }
33 
34         log.Println("token is valid " + username + " is logged in")
35         categories := db.GetCategories(username)
36         w.Header().Set("Content-Type", "application/json; charset=UTF-8")
37 
38         w.WriteHeader(http.StatusOK)
39 
40         err = json.NewEncoder(w).Encode(categories)
41         if err != nil {
42             panic(err)
43         }
44     }
45 }

During an API call, we send data in JSON format, for that, we need to set our content-type as application/json, by doing this, even a web browser will detect that it is getting a JSON document. When we need to write a JSON document to the response writer object, we use the json.NewEncoder(w).Encode(categories) method, where categories is our JSON document.

Formatting a JSON document

This, below, is our Tasks struct, which will be populated as a JSON document when we run our server. As you might know, we can’t use Capital letter as the first letter in a JSON title, by convention they should all be small letters. Go has a special way of letting us do that. The example is below, when we write json:"id", we are telling Go that the name of this field in a JSON rendering should be id and not Id. There is another special syntax called omitempty, in some JSON documents you might want some field to not be displayed. It so happens that there are fields which you would want to disappear when their values aren’t present, they may not be important or it’d be too clunky to have them as NULL in all JSON documents.

 1 type Task struct {
 2     Id        int       `json:"id"`
 3     Title     string    `json:"title"`
 4     Content   string    `json:"content"`
 5     Created   string    `json:"created"`
 6     Priority  string    `json:"priority"`
 7     Category  string    `json:"category"`
 8     Referer   string    `json:"referer,omitempty"`
 9     Comments  []Comment `json:"comments,omitempty"`
10     IsOverdue bool      `json:"isoverdue, omitempty"`
11 }

Testing API

We’ll use Firefox and RestClient extension to test our API. RestClient allows us to send various requests to our API server, if you are on Chrome, POSTman is the best alternative.

For RestClient to send Form data, set a custom header

Name: Content-Type

Value: application/x-www-form-urlencoded

Otherwise you’ll be sending blank POST requests all the time. The server needs to understand the content type of the data it is getting form the client.

To send the actual form data, example: we have three fields, username, password and name. Then we write it in the body section like this:

username=thewhitetulip&password=password

Also set a custom HTTP header by the Name: token Value: the token which you get in /api/get-token/ call