Write APIs in Go using go-chi
Tags: api, go, backend
Published: 2023-09-01 09:30:20

In this blog post you'll learn how to write REST APIs in Go using go-chi.

### Intro

[go-chi](https://go-chi.io/#/) is a lightweight, idiomatic and composable router for building Go HTTP services (copied directly from the webiste).

### PreRequisites

`Go 1.1x` or higher should be install in your machine.

### Code

So, we will start of with writing all of our code in one single file `main.go`, as there is no need to follow a folder structure pattern for such simple example.

```
└── go-api
    ├── go.mod
    ├── go.sum
    ├── main.go
    └── Makefile
```

Lets write a basic run command in our

`Makefile`

```makefile
run:
    @go run main.go
```

`main.go`

```go
package main

import "fmt"

func main() {
    fmt.Println("Hello, go-chi!!")
}

```

Now, run the command to install go-chi <br>

```
go get -u github.com/go-chi/chi/v5
```

Lets start of with creating a server struct that will hold the Router provided by go-chi.

```go
package main

import (
	"fmt"
	"net/http"

	"github.com/go-chi/chi/v5"
)

type Server struct {
	Router *chi.Mux
}

func CreateServer() *Server {
	server := &Server{
		Router: chi.NewRouter(),
	}
	return server
}

func main() {
	server := CreateServer()
	fmt.Println("server running on port:5000")
	http.ListenAndServe(":5000", server.Router)
}
```

Run the command `make run` in your terminal and you see the server running

```js
➜  go-api git:(main) ✗ make run
server running on port:5000

```

But we can't hit any endpoints as we haven't create any. So, lets create a basic `GET /greet` endpoint

```go
func Greet(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello, World!!"))
}

func (server *Server) MountHandlers() {
	server.Router.Get("/greet", Greet)
}

func main() {
	server := CreateServer()
	server.MountHandlers()

	fmt.Println("server running on port:5000")
	http.ListenAndServe(":5000", server.Router)
}
```

As you can see, we created a basic Greet handler which will return `"Hello, World!!"` when you hit `http://localhost:5000/greet`

```js
➜  go-api git:(main) ✗ curl -X GET 'http://localhost:5000/greet'
Hello, World!!
```

Now, lets create CRUD endpoints for a basic Todos app.

```go
func (server *Server) MountHandlers() {
	server.Router.Get("/greet", Greet)

	todosRouter := chi.NewRouter()
	todosRouter.Group(func(r chi.Router) {
		r.Get("/", GetTodos)
		r.Post("/", AddTodo)
	})

	server.Router.Mount("/todos", todosRouter)
}

type Todo struct {
	Task      string `json:"task"`
	Completed bool   `json:"completed"`
}

var Todos []*Todo

func AddTodo(w http.ResponseWriter, r *http.Request) {
	todo := new(Todo)
	if err := json.NewDecoder(r.Body).Decode(todo); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Please enter a correct Todo!!"))
		return
	}
	Todos = append(Todos, todo)
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Todo added!!"))
}

func GetTodos(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(Todos)
}

```

We can create different Group of endpoints and then we can mount them to our main Router with their own context path.

In the above code, we created a two endpoints `GET /todos` (returns todos), `POST /todos` (adds todos to Todos array). We store these Todos in an in-memory array, the code written in `AddTodo` function, we first decode request body in `Todo` struct, if there an error, we return Bad request, else we add the destructed todo into our array.

Hit the below endpoints using `curl`

```js
➜  go-api git:(main) ✗ curl -X POST 'http://localhost:5000/todos' -d '{"task": "Learn Go", "completed": false}'
Todo added!!

➜  go-api git:(main) ✗ curl -X GET 'http://localhost:5000/todos'
[{"task":"Learn Go","completed":false}]
```

I encourage you to write `PUT /todos`, `DELETE /todos` endpoint on your own.

### Conclusion

That's it, this was starter program more like an introduction, but in the upcomming blogs, we'll cover multiple topics like

- Connecting to databases like `MySQL`, `MongoDB` etc
- User `Authentication` and `Authorization`, Protected Routes etc
- In-memory Caching, using `Redis` cache etc
- Logging and many more!!

**Github**: https://github.com/the-arcade-01/go-api

Thanks for reading till the end, really appreciate it!!