https://medium.com/@petrousov/how-to-build-a-restful-api-in-go-for-phonebook-app-d55f7234a10
----------------------------------------
TL;DR
github.
Disclaimer
- This is a project to learn Go myself
- The storage of data (database) and file structure is out of the scope of this tutorial and was not implemented
Phonebook API
A phonebook application stores records of peoples contact information.
The models
In our context, a person’s record includes the first and last names and contact details such as the city, the zipcode and the phone number. To model this in Go we are going to write the following structs and create a slice where we are going to store our records.
package main
import (
"encoding/json"
)
type Person struct {
ID string `json:"id,omitempty"`
Firstname string `json:"firstname,omitempty"`
Lastname string `json:"lastname,omitempty"`
Contactinfo `json:"contactinfo,omitempty"`
}
type Contactinfo struct {
City string `json:"city,omitempty"`
Zipcode string `json:"Zipcode,omitempty"`
Phone string `json:"phone,omitempty"`
}
var people []Person
https://blog.golang.org/json-and-go for more details.
https://golang.org/pkg/encoding/json/#Marshal.
The handlers
Our backend needs to be able to perform the following 5 operations on our records.
- retrieve the records of all the people
- retrieve the record of a specific person
- create a new person record in the catalog
- update a person’s record information
- delete a person’s record from the catalog
id, will update the record.
func UpdatePersonEndpoint(w http.ResponseWriter, r *http.Request) {
var person Person
_ = json.NewDecoder(r.Body).Decode(&person)
params := mux.Vars(r)
for i, p := range people {
if p.ID == params["id"] {
people[i] = person
json.NewEncoder(w).Encode(person)
break
}
}
}
main). This is only possible if we have them exported.
https://golang.org/pkg/net/http/#ResponseWriter
json.NewEncoder(). These functions allow us to send and receive our data.
Decode() function so it can store the values in it.
person variable into JSON and send it back to the responder.
https://golang.org/pkg/encoding/json/#NewDecoder
mux.Vars() function, which returns a map, and reference them using their keys.
The rest of the handlers use the same components to implement our API’s functionality.
func GetPeopleEndpoint(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(people)
}
func GetPersonEndpoint(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
for _, p := range people {
if p.ID == params["id"] {
json.NewEncoder(w).Encode(p)
return
}
}
json.NewEncoder(w).Encode("Person not found")
}
func CreatePersonEndpoint(w http.ResponseWriter, r *http.Request) {
var person Person
_ = json.NewDecoder(r.Body).Decode(&person)
people = append(people, person)
json.NewEncoder(w).Encode(person)
}
func DeletePersonEndpoint(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
for i, p := range people {
if p.ID == params["id"] {
copy(people[i:], people[i+1:])
people = people[:len(people)-1]
break
}
}
json.NewEncoder(w).Encode(people)
}
The router
We now have our models and handlers which are able to receive and respond to HTTP requests and convert the data from JSON into our models and back. The next thing we need to implement is the mapping which shows the correspondence of a URL and HTTP request type to our handlers.
- GetPeopleEndpoint()
- GetPersonEndpoint()
- CreatePersonEndpoint()
- UpdatePersonEndpoint()
- DeletePersonEndpoint()
UpdatePersonEndpoint() handler so on and so forth.
For the implementation of the router, we are going to use the gorilla/mux package and write the following code.
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/people", GetPeopleEndpoint).Methods("GET")
router.HandleFunc("/people/{id}", GetPersonEndpoint).Methods("GET")
router.HandleFunc("/people", CreatePersonEndpoint).Methods("POST")
router.HandleFunc("/people/{id}", DeletePersonEndpoint).Methods("DELETE")
router.HandleFunc("/people/{id}", UpdatePersonEndpoint).Methods("PUT")
}
Methods() function.
http://www.gorillatoolkit.org/pkg/mux
Populating with dummy data
people. So, in order to populate our API with some dummy data, we are going to create a couple of entries.
people = append(people, Person{ID: "1", Firstname: "Bruce", Lastname: "Wayne", Contactinfo: Contactinfo{City: "Gotham", Zipcode: "735", Phone: "012345678"}})
people = append(people, Person{ID: "2", Firstname: "Clark", Lastname: "Kent", Contactinfo: Contactinfo{City: "Metropolis", Zipcode: "62960", Phone: "9876543210"}})
}
The server
http package which starts a HTTP server.
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
fmt.Println("Starting server on port 8000...")
log.Fatal(http.ListenAndServe(":8000", router))
}
https://golang.org/pkg/log/#Fatal
Testing
go run command.
go run main.go
Starting server on port 8000...
For our tests, we are going to use Postman and fire up all the HTTP requests to confirm the functionality of our handlers.
- Retrieve the records of all the people (GET)
2. Retrieve the record of a specific person (GET)
3. Create a new person record in the catalog (POST)
4. Update a person’s record information (PUT)
5. Delete a person’s record from the catalog (DELETE)
Delete a person’s record using it’s id
Conclusion
In this post I showed you how you can build a simple API in Go which can respond to HTTP requests. Following along you should be able to modify the phonebook API to serve your purpose and follow the documentation if necessary to clear some clouds.
References
- Building a RESTful API with Go
- How to use the JSON package with useful examples
- package mux