Criando um servidor REST com GO
Tags: braziliandevs, go, todayilearned, beginners
Published: 2022-05-25 01:03:01

## Introdução
Hoje aprendi a criar servidores REST com o GO, e logo de cara fiquei impressionado pois não precisei instalar nenhuma lib externa para subir o servidor, o GO já vem por padrão com módulos responsáveis por isso

## Implementação
De inicio precisei declarar uma struct que recebe a seguinte função

```Go
func (w WebServer) Serve() {
	server := &http.Server{
		ReadHeaderTimeout: 10 * time.Second, // tempo de timeout para leitura
		WriteTimeout:      10 * time.Second, // tempo de timeout para escrita
		Addr:              ":8080", //porta da aplicação
		Handler:           nil, // handler da aplicação
		ErrorLog:          log.New(os.Stderr, "log: ", log.Lshortfile), // como será tratado o log da aplicação
	}

	err := server.ListenAndServe()
	if err != nil {
		log.Fatal(err) //caso tenha um erro na parte de servir paro a aplicação e coloco esse erro no log
	}
}
``` 

Depois disso precisei instalar a biblioteca `github.com/gorilla/mux` para fazer a parte das rotas que não vem com a biblioteca padrão do GO
e a biblioteca `github.com/codegangsta/negroni` para implementar middlewares, nesse caso o middleware de logs

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ttp1yohp3x7v6cdsygew.png)

E para fazer as rotas vai ser da seguinte forma

```Go
func MakeProductHandlers(r *mux.Router, n *negroni.Negroni, service application.ProductServiceInterface) {
	r.Handle("/product/{id}", n.With(
		negroni.Wrap(getProduct(service)),
	)).Methods("GET", "OPTIONS")
}
``` 

O handler vai servir como um controller para pegar as requisições para a rota e a função getProduct vai ficar assim 

```Go
func getProduct(service application.ProductServiceInterface) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		vars := mux.Vars(r)
		id := vars["id"]

		product, err := service.Get(id)
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			return
		}

		err = json.NewEncoder(w).Encode(product)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

	})
}
```

então quando o usuário chamar a rota `/product/{id}` o handler vai chamar a função getProducts e o negroni vai rodar junto pois usei o wrap ao redor da função getProducts, ai a função getProduct vai ter um request e um responseWritter o request usamos para pegar os dados que o cliente enviou na requisição e o responseWritter é para escrever a resposta e mandar de volta para o usuário, que é quando uso o `json.NewEncoder(w).Encode(product)`, para já mandar os dados formatados no formato de json

Para iniciar o servidor criei um novo commando com o cobra cli chamado de http e nesse comando fiz o seguinte 

```Go
		s := server.MakeNewWebServer()
		s.Service = &productService
		fmt.Println("Web server is running on port 8080")
		s.Serve()
```

Esse product service é apenas a conexão com o banco de dados não precisa se preocupar com ele, mas se quiser ver o [Código completo](https://github.com/Yansb/full-cycle-course/tree/master/hexagonal-architecture) ele está no meu Github. 

Agora temos um webServer completo