Restful API with Golang practical approach
Tags: go, tutorial, microservices, devops
Published: 2022-10-17 08:42:07

In this tutorial, we would be creating a Restful API with a practical approach of clean architecture and native Golang without any frameworks.

There are lots of tutorials out there, for Restful API but the issue they are facing is they don't have a clear structure and use various frameworks.

Those tutorials depend on the existence of some frameworks of Golang. With every external framework being used in the project, it comes with great responsibility. I don't have anything against these frameworks, but rather I prefer to minimize the use of external frameworks and stick with standard packages of Golang.

When a beginner starts learning Golang, most of them jump straight away to the famous external frameworks, such as Gin, Beego, Fiber and many more. Frameworks are good to implement something fast, but the main issue is here that beginners are using frameworks without understanding the native approach that Golang provides out of the box. This approach leads to the developer being dependent on the specific framework. If you are sticking with frameworks, what would you do if these frameworks are being deprecated, have bugs or are not being supported anymore? 

All of these frameworks use the native Golang codes behind them with an extra layer which makes them frameworks. 

So my two cents here is to try to learn standard Golang packages this way you will not get lost in the world of frameworks, as Golang provides most of the required things out of the box.

The initial requirement before we start our tutorial is to make sure that you have the following installed setup on your computer:
1) Golang (https://go.dev/doc/install)
2) IDE of your choice VSCode or GoLand JetBrains.
3) Postgresql (https://www.postgresql.org/download/)
4) Insomnia (https://insomnia.rest/)
5) Golang-Migrate (https://github.com/golang-migrate/migrate/blob/master/cmd/migrate/README.md)

For the purpose of this tutorial, we will not be using Docker as explaining Docker and it is function is out of the context of this tutorial.


##Initial setup
Create your folder and initialize the app:

```shell
mkdir rest-api
cd rest-api
git init
```

Golang has a package manager which is handled by `go.mod` file. To generate this file, you must run the following command:
`go mod init {Name Of Remote Repository}`. 

The convention to create a `go.mod` is to use the name of the remote repository of your app, in my case, it will be `go mod init github.com/fir1/rest-api`.

It is important to name it as a repository name because that is how Go manages dependencies when you execute the following command `go get {PackageName}`.

First, we need to create a project structure, before starting the actual implementation of Restful API.

I have already written a full blog regarding structuring a Golang application, you can read it in full by clicking here. (https://dev.to/firdavs_kasymov/a-practical-approach-to-structuring-golang-applications-1cc2)

So in this project, we would be following the same structure as it is explained in the previous blog.


##Architecture
The architecture of our program will be looking like the following diagram:


![Rest API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z30d69cs6swd6emzp2ik.jpeg)

As is clear from the diagram we have isolation, between Repository, Model, Service and Delivery layers.

This approach has been taken by the rules of the clean architecture of Uncle Bob more info at https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

With this pattern we can have a clean and easy-to-follow logic, independent of any layer, so your business rules simply don't know anything at all about the outside world.  The below flow explains how the layers access each other.

Delivery (REST, gRPC) -> Business Service -> Repository -> Model.

As you can see that we are not exposing the repository directly to the Delivery layer, instead only our business service has access to it. And once we have received an API call we just expose the business service to the delivery layer, which I think is quite logical to do and easier to follow.


##Creating Restful endpoints


For the purpose of this tutorial we will be creating a simple REST API for the TO-DO list application which has a business logic of Creating, Reading, Updating and Deleting the todo item, known as (CRUD).

We will be using some essential libraries to make the REST API so please execute the following commands:

```go
go get github.com/gorilla/mux

go get github.com/sirupsen/logrus

go get github.com/jmoiron/sqlx

go get github.com/lib/pq

go get github.com/asaskevich/govalidator

go get github.com/joho/godotenv

go get github.com/kelseyhightower/envconfig
```

Briefly, we will be explaining what each library does:

**mux:** 
Package gorilla/mux implements a request router and dispatcher for matching incoming requests to their respective handler. Read in full from here (https://github.com/gorilla/mux)

**logrus:** 
Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger. (https://github.com/sirupsen/logrus)

**sqlx:**
sqlx is a library which provides a set of extensions on go's standard database/sql library. (https://github.com/jmoiron/sqlx)

**pq:**
A pure Go postgres driver for Go's database/sql package (https://github.com/lib/pq)

**govalidator:**
A package of validators and sanitisers for strings, structs and collections (https://github.com/asaskevich/govalidator)

**godotenv:**
A library for loading `.env` config files


**envconfig:**
Library for managing configuration data from environment variables (https://github.com/joho/godotenv)

###Config
In this project, we are going to use dependencies such as Postgres, as Postgres requires the client connection to provide credentials to be able to connect to the database.
So we have decided to create `.env` file in the root of project with the credentials for the database we are going to use:

```yaml
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=password
DATABASE_NAME=rest
SERVER_PORT=80
```

The above credentials for Database might be different in your local computer, so make sure to adjust it accordingly.


Create a file in directory `configs/config.go` with the content:

```go
package configs

import (
	"github.com/joho/godotenv"
	"github.com/kelseyhightower/envconfig"
)

type Config struct {
	Database   Database
	ServerPort int `envconfig:"SERVER_PORT" default:"80"`
}

type Database struct {
	Host     string `envconfig:"DATABASE_HOST" required:"true"`
	Port     int    `envconfig:"DATABASE_PORT" required:"true"`
	User     string `envconfig:"DATABASE_USER" required:"true"`
	Password string `envconfig:"DATABASE_PASSWORD" required:"true"`
	Name     string `envconfig:"DATABASE_NAME" required:"true"`
}

func NewParsedConfig() (Config, error) {
	_ = godotenv.Load(".env")
	cnf := Config{}
	err := envconfig.Process("", &cnf)
	return cnf, err
}
```

This code will be responsible for parsing `.env` files content to the struct `Config`.


###Helper packages
In this section, we would be creating a helper package, which can be used within our project or can be imported to external projects.

**Package: db**
This package will have methods linked to the Database, such as connecting to the database, and error handling.

Create a folder in `pkg/db` which will include the files of `db` package.


Create the following associated files.

`pkg/db/db.go`

```go
package db

import (
	"fmt"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
)

type ConfingDB struct {
	Host     string
	Port     int
	User     string
	Password string
	Name     string
}

func Connect(cnf ConfingDB) (*sqlx.DB, error) {
	dsn := fmt.Sprintf(
		"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
		cnf.Host,
		cnf.Port,
		cnf.User,
		cnf.Password,
		cnf.Name,
	)
	db, err := sqlx.Connect("postgres", dsn)
	return db, err
}
```

And the following file for error handling

`pkg/db/error.go`

```go
package db

import (
	"database/sql"
	"errors"
	"fmt"
)

func HandleError(err error) error {
	if errors.Is(err, sql.ErrNoRows) {
		return ErrObjectNotFound{}
	}
	return err
}

// ErrObjectNotFound is used to indicate that selecting an individual object
// yielded no result. Declared as type, not value, for consistency reasons.
type ErrObjectNotFound struct{}

func (ErrObjectNotFound) Error() string {
	return "object not found"
}
func (ErrObjectNotFound) Unwrap() error {
	return fmt.Errorf("object not found")
}
```






###Database migration
If you have followed the initial setup, you should have already "golang-migrate" installed locally.

So we use migration files all together to keep the track of database scheme changes.

For the purpose of this tutorial, we must create a table named `todo` for our database so for that we would be using `golang-migrate` tool.
First, create a folder `migrations` in the root directory.

Next, execute the following command from the root working directory of the project 
```shell
migrate create -ext sql -dir migrations -seq create_todo_table
```

The command will automatically create two files inside `migrations` folder.

So we have now two files:

- **`migrations/000001_create_todo_table.up.sql`**


We need to put all the changes which we would like to do in a database on this file, such as the creation of a new table or any changes related to the database.

Please put the following content into this file:

```sql
CREATE TABLE todo
(
    id SERIAL,
    name TEXT NOT NULL,
    description TEXT NOT NULL,
    status SMALLINT NOT NULL,
    created_on TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
    updated_on TIMESTAMP(0) WITHOUT TIME ZONE,
    deleted_on  TIMESTAMP(0) WITHOUT TIME ZONE,

    PRIMARY KEY (id)
);
```

When using Migrate CLI we need to pass to database URL. Let's export it to a variable for convenience:

```shell
export POSTGRESQL_URL='postgres://postgres:password@localhost:5432/rest?sslmode=disable'
```

Then run migration files by executing the command:
```shell
migrate -database ${POSTGRESQL_URL} -path migrations up
```

<br>
<br>

- **`000001_create_todo_table.down.sql`**

In case of if you would like to roll back migrations, we will use `.down.sql` files, so in this tutorial rollback of migration would be to delete a created table.

So please put the following content into this file:
```sql
DROP TABLE IF EXISTS todo;
```

To rollback the previously executed migration run the following command:

```shell
migrate -database ${POSTGRESQL_URL} -path migrations down
```


###Creating Layers

**Model**

We would be creating a separate folder for the model layer in the directory `internal/todo/model/model.go` inside the file please have the following content:

```go
package model

import "time"

type Status int

const (
	StatusPending Status = iota + 1
	StatusInProgress
	StatusDone
)

func (s Status) IsValid() bool {
	switch s {
	case StatusPending:
		return true
	case StatusInProgress:
		return true
	case StatusDone:
		return true
	}
	return false
}

type ToDo struct {
	ID          int        `db:"id"`
	Name        string     `db:"name"`
	Description string     `db:"description"`
	Status      Status     `db:"status"`
	CreatedOn   time.Time  `db:"created_on"`
	UpdatedOn   *time.Time `db:"updated_on"`
	DeletedOn   *time.Time `db:"deleted_on"`
}

```

We would be using `model` purely to interact with the Database, to get the object from it and parse it to our model.


**Repository**

Let's create our repository which will be responsible for handling all the database interactions for the ToDo model.

Create a separate directory for the repository `internal/todo/repository`
and have file `repository.go` within:

```go
package repository

import (
	"context"
	"fmt"
	"github.com/fir1/rest-api/internal/todo/model"
	"github.com/fir1/rest-api/pkg/db"
	"github.com/jmoiron/sqlx"
)

type Repository struct {
	Db *sqlx.DB
}

func NewRepository(db *sqlx.DB) Repository {
	return Repository{Db: db}
}

func (r Repository) Find(ctx context.Context, id int) (model.ToDo, error) {
	entity := model.ToDo{}
	query := fmt.Sprintf(
		"SELECT * FROM todo WHERE id = $1 AND deleted_on IS NULL",
	)
	err := r.Db.GetContext(ctx, &entity, query, id)
	return entity, db.HandleError(err)
}

func (r Repository) Create(ctx context.Context, entity *model.ToDo) error {
	query := `INSERT INTO todo (name, description, status, created_on, updated_on)
				VALUES (:name, :description, :status, :created_on, :updated_on) RETURNING id;`
	rows, err := r.Db.NamedQueryContext(ctx, query, entity)
	if err != nil {
		return db.HandleError(err)
	}

	for rows.Next() {
		err = rows.StructScan(entity)
		if err != nil {
			return db.HandleError(err)
		}
	}
	return db.HandleError(err)
}

func (r Repository) Update(ctx context.Context, entity model.ToDo) error {
	query := `UPDATE todo
    		  	SET name = :name, 
    		  	    description = :description, 
    		  	    status = :status, 
    		  	    created_on = :created_on, 
    		  	    updated_on = :updated_on, 
    		  	    deleted_on = :deleted_on
				WHERE id = :id;`
	_, err := r.Db.NamedExecContext(ctx, query, entity)
	return db.HandleError(err)
}

func (r Repository) FindAll(ctx context.Context) ([]model.ToDo, error) {
	var entities []model.ToDo
	query := fmt.Sprintf(
		"SELECT * FROM todo WHERE deleted_on IS NULL",
	)
	err := r.Db.SelectContext(ctx, &entities, query)
	return entities, db.HandleError(err)
}
```

The repository layer has only one purpose, it will make a SQL query to the Database. So in this case it provides the base CRUD operations for the ToDo model.


Create a separate directory for the service layer, so you can write the business logic here, so we would be creating a directory ``internal/todo/service`` and the files `internal/todo/service/service.go` and `internal/todo/service/get.go` within it:

Please have the following content on the file `internal/todo/service/service.go`



###Service
We would be implementing the business logic for the CRUD operations. Please create the following folder in directory `internal/todo/service` and all the following files within the created directory


`internal/todo/service/service.go`
```go
package service

import (
	"github.com/fir1/rest-api/internal/todo/repository"
)

type Service struct {
	repo repository.Repository
}

func NewService(r repository.Repository) Service {
	return Service{
		repo: r,
	}
}

```

It returns an instance of service, and this instance would be having all methods of our business logic.

So in this tutorial, the Delivery Layer, can only call the Service layer to get access to the business logic.

**Create**
The business logic will validate the parameters of the function and save the ToDo in the database.


`internal/todo/service/create.go`

```go
package service

import (
	"context"
	"github.com/asaskevich/govalidator"
	"github.com/fir1/rest-api/internal/todo/model"
	"github.com/fir1/rest-api/pkg/erru"
	"time"
)

type CreateParams struct {
	Name        string       `valid:"required"`
	Description string       `valid:"required"`
	Status      model.Status `valid:"required"`
}

func (s Service) Create(ctx context.Context, params CreateParams) (int, error) {
	if _, err := govalidator.ValidateStruct(params); err != nil {
		return 0, erru.ErrArgument{Wrapped: err}
	}

	tx, err := s.repo.Db.BeginTxx(ctx, nil)
	if err != nil {
		return 0, err
	}
	// Defer a rollback in case anything fails.
	defer tx.Rollback()

	entity := model.ToDo{
		Name:        params.Name,
		Description: params.Description,
		Status:      params.Status,
		CreatedOn:   time.Now().UTC(),
	}
	err = s.repo.Create(ctx, &entity)
	if err != nil {
		return 0, err
	}

	err = tx.Commit()
	return entity.ID, err
}

```

It returns an instance of service, and this instance would be having all methods of our business logic. Please note that here we have a separate type `CreateParams` for taking arguments to function rather than using `model.go`. Because we would like to have clear isolation between each layer, so this way we would not clutter the tags of types and mandatory arguments to the function. 

If we have used type `ToDo` from `model.go`  as an argument to the function.

```go
type ToDo struct {
	ID          int        `db:"id"`
	Name        string     `db:"name"`
	Description string     `db:"description"`
	Status      Status     `db:"status"`
	CreatedOn   time.Time  `db:"created_on"`
	UpdatedOn   *time.Time `db:"updated_on"`
	DeletedOn   *time.Time `db:"deleted_on"`
}
```

Which fields from `ToDo` model would be mandatory for the business logic? 

As it is clear that it will mess up our architecture if we use the `model.go` types as arguments to the business layer. That is one of the reasons why I like to isolate the layers, so we have a clear understanding of mandatory fields for the functions.


**Get**

The business logic here is quite straightforward, we will have a function which will take `id` as a mandatory parameter then we would be looking up the database.

`internal/todo/service/get.go`

```go

package service

import (
	"context"
	"errors"
	"github.com/fir1/rest-api/internal/todo/model"
	"github.com/fir1/rest-api/pkg/db"
	"github.com/fir1/rest-api/pkg/erru"
)

func (s Service) Get(ctx context.Context, id int) (model.ToDo, error) {
	todo, err := s.repo.Find(ctx, id)
	switch {
	case err == nil:
	case errors.As(err, &db.ErrObjectNotFound{}):
		return model.ToDo{}, erru.ErrArgument{errors.New("todo object not found")}
	default:
		return model.ToDo{}, err
	}
	return todo, nil
}

```

**Update**

The business logic here is that we will be taking `id` as a mandatory field, so we can look up the `ToDo` entity from the Database, then update the fields `name, description, status` optionally if it is provided.

`internal/todo/service/update.go`

```go

package service

import (
	"context"
	"errors"
	"github.com/asaskevich/govalidator"
	"github.com/fir1/rest-api/internal/todo/model"
	"github.com/fir1/rest-api/pkg/erru"
)

type UpdateParams struct {
	ID          int `valid:"required"`
	Name        *string
	Description *string
	Status      *model.Status
}

func (s Service) Update(ctx context.Context, params UpdateParams) error {
	if _, err := govalidator.ValidateStruct(params); err != nil {
		return erru.ErrArgument{Wrapped: err}
	}

	// find todo object
	todo, err := s.Get(ctx, params.ID)
	if err != nil {
		return err
	}

	if params.Name != nil {
		todo.Name = *params.Name
	}
	if params.Description != nil {
		todo.Description = *params.Description
	}
	if params.Status != nil {
		if !params.Status.IsValid() {
			return erru.ErrArgument{Wrapped: errors.New("given status not valid")}
		}
		todo.Status = *params.Status
	}

	tx, err := s.repo.Db.BeginTxx(ctx, nil)
	if err != nil {
		return err
	}
	// Defer a rollback in case anything fails.
	defer tx.Rollback()

	err = s.repo.Update(ctx, todo)
	if err != nil {
		return err
	}

	err = tx.Commit()
	return err
}

```

**Delete**

Here we would be finding the `ToDo` entity from the database, if it is found then we soft deleted it by putting the current time for the field `DeletedOn`.
I choose to soft delete the records compared to hard delete from the database table, because this way we would be having records which we can use for various purposes, such as auditing and etc.


`internal/todo/service/delete.go`

```go
package service

import (
	"context"
	"time"
)

func (s Service) Delete(ctx context.Context, id int) error {
	todo, err := s.Get(ctx, id)
	if err != nil {
		return err
	}

	tx, err := s.repo.Db.BeginTxx(ctx, nil)
	if err != nil {
		return err
	}
	// Defer a rollback in case anything fails.
	defer tx.Rollback()

	now := time.Now().UTC()
	todo.DeletedOn = &now
	err = s.repo.Update(ctx, todo)
	if err != nil {
		return err
	}

	err = tx.Commit()
	return err
}

```

###Delivery
Here we would be finding the `ToDo` entity from the database, if it is found then we soft deleted it by putting the current time for the field `DeletedOn`.
I choose to soft delete the records compared to hard delete from the database table, because this way we would be having records which we can use for various purposes, such as auditing and etc. In this section, we would be implementing the delivery layer, with the Restful server.

So please create a folder in the directory `http/rest`.

As we have described CRUD, so for each functionality of CRUD we would be having a separate handler which will receive external API calls, and then each handler will call it is relevant business service. We would be creating a separate handler and explaining the logic.


### Initiate handler service
First we must initiate a handler service, so please create a file in `http/rest/handlers/handler.go` and put the following content:

```go
package handlers

import (
	toDoRepo "github.com/fir1/rest-api/internal/todo/repository"
	toDoService "github.com/fir1/rest-api/internal/todo/service"
	"github.com/gorilla/mux"
	"github.com/jmoiron/sqlx"
	"github.com/sirupsen/logrus"
)

type service struct {
	logger      *logrus.Logger
	router      *mux.Router
	toDoService toDoService.Service
}

func newHandler(lg *logrus.Logger, db *sqlx.DB) service {
	return service{
		logger:      lg,
		toDoService: toDoService.NewService(toDoRepo.NewRepository(db)),
	}
}

```


The handler service will take business service as a dependency argument in our case the dependency is `toDoService` which is our internal business service layer.

### Helpers
There is common logic which is being used by every handler, so I have decided to put that logic in a separate helper function, so we can reuse it rather than duplicate it.

Create a file in `http/rest/handlers/helper.go` and put the following content.

```go
package handlers

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/fir1/rest-api/pkg/erru"
	"io"
	"net/http"
)

/*
Don’t have to repeat yourself every time you respond to user, instead you can use some helper functions.
*/
func (s service) respond(w http.ResponseWriter, data interface{}, status int) {
	var respData interface{}
	switch v := data.(type) {
	case nil:
	case erru.ErrArgument:
		status = http.StatusBadRequest
		respData = ErrorResponse{ErrorMessage: v.Unwrap().Error()}
	case error:
		if http.StatusText(status) == "" {
			status = http.StatusInternalServerError
		} else {
			respData = ErrorResponse{ErrorMessage: v.Error()}
		}
	default:
		respData = data
	}

	w.WriteHeader(status)
	w.Header().Set("Content-Type", "application/json")
	if data != nil {
		err := json.NewEncoder(w).Encode(respData)
		if err != nil {
			http.Error(w, "Could not encode in json", http.StatusBadRequest)
			return
		}
	}
}

// it does not read to the memory, instead it will read it to the given 'v' interface.
func (s service) decode(r *http.Request, v interface{}) error {
	return json.NewDecoder(r.Body).Decode(v)
}

// it reads to the memory.
func (s service) readRequestBody(r *http.Request) ([]byte, error) {
	// Read the content
	var bodyBytes []byte
	var err error
	if r.Body != nil {
		bodyBytes, err = io.ReadAll(r.Body)
		if err != nil {
			err := errors.New("could not read request body")
			return nil, err
		}
	}
	return bodyBytes, nil
}

// will place the body bytes back to the request body which could be read in subsequent calls on Handlers
// for example, you have more than 1 middleware and each of them need to read the body. If the first middleware read the body
// the second one won't be able to read it, unless you put the request body back.
func (s service) restoreRequestBody(r *http.Request, bodyBytes []byte) {
	// Restore the io.ReadCloser to its original state
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}

```


**Create**
We will be creating handlers and the practical approach would be to have a struct for the `request, response` within the relevant handler, this way we have clear isolation between the data which is being required from the API call, and the data which is being inserted into the business layer, rather than using `model` everywhere within our application. 

Some of you might not agree with me but I prefer clean code over a complicated one.
The main important thing for developers is to write the code clean, so the fellow developers can understand easily.


`http/rest/handlers/create.go`

```go
package handlers

import (
	"github.com/fir1/rest-api/internal/todo/model"
	toDoService "github.com/fir1/rest-api/internal/todo/service"
	"net/http"
)
 
func (s service) Create() http.HandlerFunc {
	type request struct {
		Name        string       `json:"name"`
		Description string       `json:"description"`
		Status      model.Status `json:"status"`
	}

	type response struct {
		ID int `json:"id"`
	}

	return func(w http.ResponseWriter, r *http.Request) {
		req := request{}
		// Try to decode the request body into the struct. If there is an error,
		// respond to the client with the error message and a 400 status code.
		err := s.decode(r, &req)
		if err != nil {
			s.respond(w, err, 0)
			return
		}

		id, err := s.toDoService.Create(r.Context(), toDoService.CreateParams{
			Name:        req.Name,
			Description: req.Description,
			Status:      req.Status,
		})
		if err != nil {
			s.respond(w, err, 0)
			return
		}
		s.respond(w, response{ID: id}, http.StatusOK)
	}
}

```

As you can see the job of our handler is to receive an API call, and then call the relevant business service layer, to handle the rest of the logic (s.toDoService.Create - this is our business service layer).

It is a clean approach, as our handler knows only about the business service layer, and the handler does not know anything about the underlying logic of the business. 

This approach is practical because imagine if you would like to expose your API with gRPC protocol, with the current approach we just add an additional delivery layer in the directory `http/grpc` then call our business service layer, without the need to write any business logic.



**Get**

Please create a file in `http/rest/handlers/get.go` and have the following content:

```go
package handlers

import (
	"errors"
	"github.com/fir1/rest-api/internal/todo/model"
	"github.com/fir1/rest-api/pkg/erru"
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
	"time"
)

func (s service) Get() http.HandlerFunc {
	type response struct {
		ID          int          `json:"id"`
		Name        string       `json:"name"`
		Description string       `json:"description"`
		Status      model.Status `json:"status"`
		CreatedOn   time.Time    `json:"created_on"`
		UpdatedOn   *time.Time   `json:"updated_on,omitempty"`
	}
	return func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)

		id, err := strconv.Atoi(vars["id"])
		if err != nil {
			s.respond(w, erru.ErrArgument{
				Wrapped: errors.New("valid id must provide in path"),
			}, 0)
			return
		}

		getResponse, err := s.toDoService.Get(r.Context(), id)
		if err != nil {
			s.respond(w, err, 0)
			return
		}
		s.respond(w, response{
			ID:          getResponse.ID,
			Name:        getResponse.Name,
			Description: getResponse.Description,
			Status:      getResponse.Status,
			CreatedOn:   getResponse.CreatedOn,
			UpdatedOn:   getResponse.UpdatedOn,
		}, http.StatusOK)
	}
}
```

**Update**

Please create a file in `http/rest/handlers/update.go` and have the following content:

```go
package handlers

import (
	"errors"
	"github.com/fir1/rest-api/internal/todo/model"
	toDoService "github.com/fir1/rest-api/internal/todo/service"
	"github.com/fir1/rest-api/pkg/erru"
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
)

func (s service) Update() http.HandlerFunc {
	type request struct {
		Name        *string       `json:"name"`
		Description *string       `json:"description"`
		Status      *model.Status `json:"status"`
	}

	type response struct {
		ID int `json:"id"`
	}

	return func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, err := strconv.Atoi(vars["id"])
		if err != nil {
			s.respond(w, erru.ErrArgument{
				Wrapped: errors.New("valid id must provide in path"),
			}, 0)
			return
		}

		req := request{}
		// Try to decode the request body into the struct. If there is an error,
		// respond to the client with the error message and a 400 status code.
		err = s.decode(r, &req)
		if err != nil {
			s.respond(w, err, 0)
			return
		}

		err = s.toDoService.Update(r.Context(), toDoService.UpdateParams{
			ID:          id,
			Name:        req.Name,
			Description: req.Description,
			Status:      req.Status,
		})
		if err != nil {
			s.respond(w, err, 0)
			return
		}
		s.respond(w, response{ID: id}, http.StatusOK)
	}
}

```

**Delete**
Please create a file in `http/rest/handlers/delete.go` and have the following content:

```go
package handlers

import (
	"github.com/gorilla/mux"
	"net/http"
	"strconv"
)

func (s service) Delete() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)

		id, err := strconv.Atoi(vars["id"])
		if err != nil {
			s.respond(w, err, 0)
			return
		}

		err = s.toDoService.Delete(r.Context(), id)
		if err != nil {
			s.respond(w, err, 0)
			return
		}
		s.respond(w, nil, http.StatusOK)
	}
}
```

**Middleware**
As you might have noticed by this time that one of the most important parts of every application is being able to log, request and response to API calls. 
Disclaimer, when you log requests and responses you must be careful not to log sensitive information such as credentials, usernames, passwords and any other data which violates privacy.

Please create a file in `http/rest/middleware_logger.go` and put the following content inside it:

```go
package handlers

import (
	"fmt"
	"net/http"
	"time"
)

// responseWriter is a minimal wrapper for http.ResponseWriter that allows the
// written HTTP status code to be captured for logging. This type will implement http.ResponseWriter.
type responseWriter struct {
	http.ResponseWriter
	status      int
	body        []byte
	wroteHeader bool
	wroteBody   bool
}

func wrapResponseWriter(w http.ResponseWriter) *responseWriter {
	return &responseWriter{ResponseWriter: w}
}

func (rw *responseWriter) Status() int {
	return rw.status
}

func (rw *responseWriter) WriteHeader(code int) {
	if rw.wroteBody {
		return
	}
	rw.status = code
	rw.ResponseWriter.WriteHeader(code)
	rw.wroteHeader = true
}

func (rw *responseWriter) Write(body []byte) (int, error) {
	if rw.wroteBody {
		return 0, nil
	}
	i, err := rw.ResponseWriter.Write(body)
	if err != nil {
		return 0, err
	}
	rw.body = body
	return i, err
}

func (rw *responseWriter) Body() []byte {
	return rw.body
}

// middlewarMiddlewareLoggereLogger logs the incoming HTTP request and response. Enable it only for debug purpose disable it on production.
func (s service) MiddlewareLogger() func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path == "/healthz" {
				// Call the next handler don't log if it is internal request from health check of Kubernetes
				next.ServeHTTP(w, r)
				return
			}

			defer func() {
				if err := recover(); err != nil {
					w.WriteHeader(http.StatusInternalServerError)
				}
			}()

			requestBody, err := s.readRequestBody(r)
			if err != nil {
				s.respond(w, err, 0)
				return
			}
			s.restoreRequestBody(r, requestBody)

			logMessage := fmt.Sprintf("path:%s, method: %s, requestBody: %v", r.URL.EscapedPath(), r.Method, string(requestBody))

			start := time.Now()
			wrapped := wrapResponseWriter(w)
			next.ServeHTTP(wrapped, r)

			logMessage = fmt.Sprintf("%s, responseStatus: %d, responseBody: %s", logMessage, wrapped.Status(), string(wrapped.Body()))
			s.logger.Infof("%s, duration: %v", logMessage, time.Since(start))
		}
		return http.HandlerFunc(fn)
	}
}
```

###Register Handlers
As of now, we have all the handlers with the relevant handlers, but we need to register those handlers to the router with the customized Path.
We would be creating a file in `http/rest/handlers/routes.go` and have the following content:

```go
package handlers

import (
	"github.com/gorilla/mux"
	"github.com/jmoiron/sqlx"
	"github.com/sirupsen/logrus"
	"net/http"
)

func Register(r *mux.Router, lg *logrus.Logger, db *sqlx.DB) {
	handler := newHandler(lg, db)
	// adding logger middleware
	r.Use(handler.MiddlewareLogger())
	r.HandleFunc("/healthz", handler.Health())
	r.HandleFunc("/todo", handler.Create()).Methods(http.MethodPost)
	r.HandleFunc("/todo/{id}", handler.Get()).Methods(http.MethodGet)
	r.HandleFunc("/todo/{id}", handler.Update()).Methods(http.MethodPut)
	r.HandleFunc("/todo/{id}", handler.Delete()).Methods(http.MethodDelete)
}
```

###Creating Server

In this stage, we need to create an instance of an actual server which can receive API calls and handle those calls.


Please create a file in `http/rest/logger.go` and have the following content inside it:

```go
package rest

import (
	"github.com/sirupsen/logrus"
	"os"
)

func NewLogger() *logrus.Logger {
	log := logrus.New()
	log.SetOutput(os.Stdout)
	log.SetLevel(logrus.InfoLevel)
	log.SetFormatter(&logrus.TextFormatter{
		ForceColors:     true,
		TimestampFormat: "2006-01-02 15:04:05.999999999",
		FullTimestamp:   true,
	})
	return log
}

```

Create a file in `http/rest/server.go` and have the following content inside it:

```go
package rest

import (
	"context"
	"fmt"
	"github.com/fir1/rest-api/configs"
	"github.com/fir1/rest-api/http/rest/handlers"
	"github.com/fir1/rest-api/pkg/db"
	"github.com/gorilla/mux"
	"github.com/rs/cors"
	"github.com/sirupsen/logrus"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"syscall"
)

type Server struct {
	logger *logrus.Logger
	router *mux.Router
	config configs.Config
}

func NewServer() (*Server, error) {
	cnf, err := configs.NewParsedConfig()
	if err != nil {
		return nil, err
	}

	database, err := db.Connect(db.ConfingDB{
		Host:     cnf.Database.Host,
		Port:     cnf.Database.Port,
		User:     cnf.Database.User,
		Password: cnf.Database.Password,
		Name:     cnf.Database.Name,
	})
	if err != nil {
		return nil, err
	}

	log := NewLogger()
	router := mux.NewRouter()
	handlers.Register(router, log, database)

	s := Server{
		logger: log,
		config: cnf,
		router: router,
	}
	return &s, nil
}

func (s *Server) Run(ctx context.Context) error {
	server := http.Server{
		Addr:    fmt.Sprintf(":%d", s.config.ServerPort),
		Handler: cors.Default().Handler(s.router),
	}

	stopServer := make(chan os.Signal, 1)
	signal.Notify(stopServer, syscall.SIGINT, syscall.SIGTERM)

	defer signal.Stop(stopServer)

	// channel to listen for errors coming from the listener.
	serverErrors := make(chan error, 1)
	var wg sync.WaitGroup
	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		defer wg.Done()
		s.logger.Printf("REST API listening on port %d", s.config.ServerPort)
		serverErrors <- server.ListenAndServe()
	}(&wg)

	// blocking run and waiting for shutdown.
	select {
	case err := <-serverErrors:
		return fmt.Errorf("error: starting REST API server: %w", err)
	case <-stopServer:
		s.logger.Warn("server received STOP signal")
		// asking listener to shutdown
		err := server.Shutdown(ctx)
		if err != nil {
			return fmt.Errorf("graceful shutdown did not complete: %w", err)
		}
		wg.Wait()
		s.logger.Info("server was shut down gracefully")
	}
	return nil
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.router.ServeHTTP(w, r)
}
```

###Run Server

At this point now we can run a Restful server, and test all our integrations.

Please create a file in `cmd/app/main.go` and have the following content inside it:

```go
package main

import (
	"context"
	"github.com/fir1/rest-api/http/rest"
	"log"
)

func main() {
	if err := run(context.Background()); err != nil {
		log.Fatalf("%+v", err)
	}
}

func run(ctx context.Context) error {
	server, err := rest.NewServer()
	if err != nil {
		return err
	}
	err = server.Run(ctx)
	return err
}

```

Our `main` package has a few lines of code, which is an entry point to our application. I think the `main` package should be clean and must be used to start `servers` without any extra logic.

###Tests
In this section, we are going to test our API server manually by making a Restful API call with the help of the Insomnia Tool.

Make sure that you are in the root directory and run the following command from the terminal `go run cmd/app/*.go`


**Create**

Make an API call to the 
```json
POST localhost:80/todo

Request Body

{
  "name": "Tutorial Restful pending",
  "description": "Still we are testing Restful api so not finished",
  "status": 1
}

```


![Rest API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7objgk6s0pgwx92li05x.jpg)


**Get**

Make an API call to the 
```
GET localhost:80/todo/4 (id of todo - 4 might be different in your case)

```


![Rest API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ojz5u2bw0ugasixc8pg7.png)

**Update**

Make an API call to the 
```json
PUT localhost:80/todo/4 (id of todo - 4 might be different in your case)

Request Body
{
  "name": "Tutorial Restful finished",
  "description": "Restful api testing finished",
  "status": 2
}

```

![Rest API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zda3ig38akjd9ippb78o.jpg)

**Get Updated ToDo**

Make an API call to the 
```
GET localhost:80/todo/4 (id of todo - 4 might be different in your case)
```


![Rest API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2x39wtuxzps3p1zze4a4.jpg)

From the above screenshot, it is clear that the entity `ToDo` was updated.

**Delete**

Make an API call to the 
```
DELETE localhost:80/todo/4 (id of todo - 4 might be different in your case)
```

![Rest API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmgafpjydocg6ufer83y.jpg)

The entity was deleted, so when we do `GET` request we will be getting an error, as the object does not exist anymore.

### Enhancements
You can even enhance this project by adding more functionalities, such as:
- Add todo list endpoint, that will return all existing ToDo's entity.
- Extra functionalities, such as filtering the ToDo by status and keywords.
- Add authentication

Once you have done these enhancements you can create a PR towards my repository github.com/fir1/rest-api

##The end
Hopefully, this tutorial was useful and I would be more than happy to receive questions or suggestions about it.


The source code for this tutorial can be found [here](https://github.com/fir1/rest-api)

That’s it for this blog. Please feel free to comment with your views on this blog. Thanks for your time reading this blog and hope it was useful.

Happy learning and sharing.