REST-API with Golang and Mux.

Introduction

Today we are building a simple REST-API with Golang a router package called Mux. We are not going to integrate with a database as this article is meant to teach you the basics but I may write another article soon, with database integration.

Creating our project

We are going to start by creating our project which is only going to contain one file.

mkdir rest-api && cd rest-api && touch main.go
go get -u github.com/gorilla/mux

Our first lines of code

Before we write any code related to the REST-API we need to write som mandatory code to make the program run.

package mainimport (
"fmt"
)
func main() {
fmt.Println("It works!")
}
go build && ./rest-api

Initialising the router

We are going to remove the line that prints out “It works!” as well as the “fmt” package, instead we will add the Mux package and initialise the router.

package mainimport (
"github.com/gorilla/mux"
)
func main() {
router := mux.NewRouter()
}

Creating our endpoints

Now we are going to establish the endpoints of our API, the way we will set this up is to create all of our endpoints in the main function, every endpoint needs a function to handle the request and we will define those below the main function.

router.HandleFunc("/<your-url>", <function-name>).Methods("<method>")
package mainimport (
"github.com/gorilla/mux"
"net/http"
)
func main() {
router := mux.NewRouter()
router.HandleFunc("/posts", getPosts).Methods("GET")
router.HandleFunc("/posts", createPost).Methods("POST")
router.HandleFunc("/posts/{id}", getPost).Methods("GET")
router.HandleFunc("/posts/{id}", updatePost).Methods("PUT")
router.HandleFunc("/posts/{id}", deletePost).Methods("DELETE")
}
http.ListenAndServe(":8000", router)

Defining our models (structs)

A struct in Golang is very similar to a ES6 or Java class. We will use a struct to represent a post, I encourage you to change up some things to make it your own, this way you will learn more. Even changing “posts” to “users” helps much in my experience.

package mainimport (
"github.com/gorilla/mux"
"net/http"
)
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
var posts []Postfunc main() {
router := mux.NewRouter()
router.HandleFunc("/posts", getPosts).Methods("GET")
router.HandleFunc("/posts", createPost).Methods("POST")
router.HandleFunc("/posts/{id}", getPost).Methods("GET")
router.HandleFunc("/posts/{id}", updatePost).Methods("PUT")
router.HandleFunc("/posts/{id}", deletePost).Methods("DELETE")
http.ListenAndServe(":8000", router)
}

Route handlers

Now we just need to define the functions that will handle the requests. You also need to import the package “encoding/json”.

import (
"github.com/gorilla/mux"
"net/http"
"encoding/json"
)
func <your-function-name>(w http.ResponseWriter, r *http.Request) {

}
func getPosts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(posts)
}
func getPost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for _, item := range posts {
if item.ID == params["id"] {
json.NewEncoder(w).Encode(item)
break
}
return
}
json.NewEncoder(w).Encode(&Post{})
}
params := mux.Vars(r)
params["<param-name>"]
import (
"github.com/gorilla/mux"
"net/http"
"encoding/json"
"math/rand"
"strconv"
)
func createPost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var post Post
_ = json.NewDecoder(r.Body).Decode(post)
post.ID = strconv.Itoa(rand.Intn(1000000))
posts = append(posts, post)
json.NewEncoder(w).Encode(&post)
}
func updatePost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range posts {
if item.ID == params["id"] {
posts = append(posts[:index], posts[index+1:]...)
var post Post
_ = json.NewDecoder(r.Body).Decode(post)
post.ID = params["id"]
posts = append(posts, post)
json.NewEncoder(w).Encode(&post)
return
}
}
json.NewEncoder(w).Encode(posts)
}
func deletePost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for _, item := range posts {
if item.ID == params["id"] {
posts= append(posts[:index], posts[index+1]...)
break
}
}
json.NewEncoder(w).Encode(books)
}
posts = append(posts[:index], posts[index+1]...)
func main() {
router := mux.NewRouter()
posts = append(posts, Post{ID: "1", Title: "My first post", Body: "This is the content of my first post"})
posts = append(posts, Post{ID: "2", Title: "My second post", Body: "This is the content of my second post"})
router.HandleFunc("/posts", getPosts).Methods("GET")
router.HandleFunc("/posts", createPost).Methods("POST")
router.HandleFunc("/posts/{id}", getPost).Methods("GET")
router.HandleFunc("/posts/{id}", updatePost).Methods("PUT")
router.HandleFunc("/posts/{id}", deletePost).Methods("DELETE")
http.ListenAndServe(":8000", router)
}
package mainimport (
"github.com/gorilla/mux"
"net/http"
"encoding/json"
"math/rand"
"strconv"
)
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
var posts []Postfunc getPosts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(posts)
}
func createPost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var post Post
_ = json.NewDecoder(r.Body).Decode(&post)
post.ID = strconv.Itoa(rand.Intn(1000000))
posts = append(posts, post)
json.NewEncoder(w).Encode(&post)
}
func getPost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for _, item := range posts {
if item.ID == params["id"] {
json.NewEncoder(w).Encode(item)
return
}
}
json.NewEncoder(w).Encode(&Post{})
}
func updatePost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range posts {
if item.ID == params["id"] {
posts = append(posts[:index], posts[index+1:]...)
var post Post
_ = json.NewDecoder(r.Body).Decode(&post)
post.ID = params["id"]
posts = append(posts, post)
json.NewEncoder(w).Encode(&post)
return
}
}
json.NewEncoder(w).Encode(posts)
}
func deletePost(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range posts {
if item.ID == params["id"] {
posts = append(posts[:index], posts[index+1:]...)
break
}
}
json.NewEncoder(w).Encode(posts)
}
func main() {
router := mux.NewRouter()
posts = append(posts, Post{ID: "1", Title: "My first post", Body: "This is the content of my first post"}) router.HandleFunc("/posts", getPosts).Methods("GET")
router.HandleFunc("/posts", createPost).Methods("POST")
router.HandleFunc("/posts/{id}", getPost).Methods("GET")
router.HandleFunc("/posts/{id}", updatePost).Methods("PUT")
router.HandleFunc("/posts/{id}", deletePost).Methods("DELETE")
http.ListenAndServe(":8000", router)
}

Testing our API

I’m going to use Postman to test the API but curl is also a good option, but I like Postman’s graphical interface. You can get Postman here: https://www.getpostman.com

go build && ./rest-api

Thank you so much for reading!

I hope you found this article helpful, I really hope I helped at least one person get familiar with the basics of building REST-APIs with Golang and Mux. If you didn’t follow along and built it with me I encourage you to do so, you learn so much faster when you actually type the code:)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store