Simple Web API Server in Golang (1)

獨木發表於2014-10-26

To be an better Gopher, get your hands dirty. Topcoder offered a serials of challenges for learning Golang.

In this blog, I tried to implement "Go Learning Challenge - Simple Web-API Server"[1].

What's used in this challenge ? Following aspects and packages will be covered in this challenge

  • How to create a HTTP server: net/http
  • How to create routers (handlers for different URLs): regex + url
  • How to write HTTP responses: net/http
  • How to load JSON config: json + io/ioutil
  • How to parse URL query string: url
  • How to encode data in sha256/base64: sha256/base64  + strings
  • How to write tests in Golang: testing
  • How to parse command line arguments: flag
  • How to log: log

Configuration File example:

[
    {
        "domain": "topcoder.com",
        "users": [
            {
                "username": "takumi",
                "password": "ilovego"
            },
            {
                "username": "teru",
                "password": "ilovejava"
            },
            {
                "username": "toshi",
                "password": "iloveapex"
            }
        ]
    },
    {
        "domain": "appirio.com",
        "users": [
            {
                "username": "jun",
                "password": "ilovetopcoder"
            },
            {
                "username": "narinder",
                "password": "ilovesamurai"
            },
            {
                "username": "chris",
                "password": "ilovesushi"
            }
        ]
    }
]

config.go

package SimpleWebAPIServer

import (
    "io/ioutil"
    "encoding/json"
    "errors"
)

type User struct {
    UserName string `json:"username"`
    Password string `json:"password"`
}

type Domain struct {
    Name string `json:"domain"`
    Users UserList `json:"users"`
}

type DomainWarehouse []Domain
type UserList []User

func ReadConfig(fn string) (DomainWarehouse, error) {
    data, err := ioutil.ReadFile(fn)
    if err != nil {
        return nil, err
    }
    //fmt.Println(string(data))

    var m DomainWarehouse
    json.Unmarshal(data, &m)
    return m, nil
}


func (dw DomainWarehouse) GetDomain(name string) (*Domain, error) {
    for _, domain := range dw {
        if domain.Name == name {
            return &domain, nil
        }
    }
    return nil, errors.New("Failed to find domain")
}

func (ul UserList) GetUser(username string) (*User, error) {
    for _, user := range ul {
        if user.UserName == username {
            return &user, nil
        }
    }
    return nil, errors.New("Failed to find user")
}

 

tests for config.go

package SimpleWebAPIServer

import (
    "testing"
    "fmt"
)

func TestReadConfig(t *testing.T) {
    dw, err := ReadConfig("./users.json")
    if err != nil {
        fmt.Println(err)
        t.Error("Failed to read config")
    }
    if dw == nil || len(dw) != 2 {
        t.Error("Failed to unmarshal json objects")
    }

    if dw[0].Name != "topcoder.com" || len(dw[0].Users) != 3 {
        t.Error("Incorrect value")
    }
}

func TestGetDomain(t *testing.T) {
    dw, err := ReadConfig("./users.json")
    if err != nil {
        fmt.Println(err)
        t.Error("Failed to read config")
    }
    domain, err := dw.GetDomain("topcoder.com")
    if err != nil {
        fmt.Println(err)
        t.Error("Failed to get domain")
    }
    if domain.Name != "topcoder.com" || len(domain.Users) != 3 {
        t.Error("Incorrect value")
    }
}

func TestGetUser(t *testing.T) {
    dw, err := ReadConfig("./users.json")
    if err != nil {
        fmt.Println(err)
        t.Error("Failed to read config")
    }
    domain, err := dw.GetDomain("topcoder.com")
    if err != nil {
        fmt.Println(err)
        t.Error("Failed to get domain")
    }
    if domain.Name != "topcoder.com" || len(domain.Users) != 3 {
        t.Error("Incorrect value")
    }

    ul := domain.Users
    u, err := ul.GetUser("takumi")
    if err != nil {
        t.Error("Failed to get user")
    }
    if u.UserName != "takumi" || u.Password != "ilovego" {
        t.Error("Invalid user values")
    }
}

 

 

After implementing this simple web api server, I got better understanding of Golang syntax and Web API stuffs. For more Web API server challenges, go to [3] about OAuth2.

 

[1] topcoder : http://www.topcoder.com/challenge-details/30046011/?type=develop&noncache=true

[2] git : https://coding.net/u/huys03/p/SimpleWebAPIServer/git

[3] next challenge: http://www.topcoder.com/challenge-details/30046224/?type=develop

 

相關文章