Começando com Go - parte 2 - Estruturando a API
Tags: go, api, backend
Published: 2021-03-17 09:29:45

Fala meus consagrados e consagradas, beleza?

Bom, como eu havia dito ontem, hoje vamos criar nosso primeiro endpoint dentro da estrutura de clean architecture que estamos utilizando. Bora lá?

## Rápida explicação sobre camadas de apresentação
Dentro da pasta `api` que havia sido criada, vamos criar uma outra pasta que vai guardar a implementação das nossas rotas. Seria o que chamamos da camada de apresentação. 

No clean architecture, podemos ter várias camadas de apresentação diferentes (por exemplo, API, Mensageria e Linha de comando), e o *tchan* é que, neste caso, todas elas, caso tenham o mesmo propósito, implementam o mesmo **caso de uso** que é onde realmente mora nossa lógica de negócio. 

Isso aumenta o aproveitamento de código, facilita o teste e ajuda o projeto a crescer de forma orgânica, sem bagunçar. Fique tranquilo se isso soa grego ainda, muito em breve nós vamos ver exemplos práticos do que eu to falando. Por enquanto, vamos nos ater aos detalhes de implementação.

## Criando a estrutura
Como já explicado, dentro da pasta `api`, crie um outro diretório chamado `handler`, que é o diretório que vai guardar os nossos arquivos de rotas de api e **lidar** com a implementação delas (por isso o nome `handler`)
```bash
cd management_api/api
mkdir handler
```

Agora nós vamos dividir o que a nossa api tem que servir por domínio. E um domínio óbvio é o de empresas. Estamos escrevendo um Saas (software as a service, ou software como serviço, se você quiser saber mais, o link é este: https://neilpatel.com/br/blog/saas/) para ajudar empresas a se comunicarem melhor e mais efetivamente com seus clientes. Logo, uma empresa precisa conseguir se cadastrar no nosso sistema para, depois, poder cadastrar seus clientes, envios, e todo o resto em que vamos chegar. Dito isto, vamos criar o arquivo que vai lidar com todos os endpoints relacionados a empresa.

Dentro da pasta `handler`, crie um arquivo chamado `company.go`. E vamos começar a implementar nossa primeira rota. Vou fazer no mesmo modelo da parte 1, onde eu coloco o código comentado e explico o que cada linha faz.

```go
//Especificamos que estas funções pertencem ao pacote handler.
//É dessa forma que vamos importar o que precisamos depois
package handler

import (
	"io"
	"net/http"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Especificamos a função "createCompany()" e o tipo de retorno dela é http.Handler (vou explicar mais abaixo)
func createCompany() http.Handler {
        //Crio um handler http que responde uma string com o valor "teste"
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "Teste")
	})
}

//Crio uma função para especificar minhas rotas e passar a requisição para os handlers corretos
func MakeCompanyHandlers(router *mux.Router, n *negroni.Negroni) {
	router.Handle("/v1/company", n.With(
		negroni.Wrap(createCompany()),
	)).Methods("POST", "OPTIONS").Name("createCompany")
}

```

##Alguns pontos importantes sobre o código acima:

#### http.Handler
Na função `createCompany`, nós retornamos um `http.Handler`. O tipo `http.Handler` é responsável por captar uma requisição (`http.Request`) e um "escritor" de resposta (`http.ResponseWriter`), dessa forma ele consegue ler os dados que vieram da requisição, como por exemplo, o `body`, e também responder a essa requisição, enviando também o body ou status code. Esse tipo (o `http.Handler`) é retornado da função `http.HandlerFunc`, que recebe como parâmetro outra função com a implementação do handler (neste caso, passamos uma função anônima, ou seja, não demos nome para ela e a implementação dela ja está especificada) e passa para esta função estes dois objetos que especifiquei mais acima. Uma forma mais fácil de entender o conceito é se não utilizarmos uma função anônima, como abaixo:
```go
//Essa é a função handler que contém a implementação
func createCompanyHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Teste")
}

//Essa é a função que transforma o handler acima em um http.Handler
func createCompany() http.Handler {
	//Era na linha abaixo, no lugar de createCompanyHandler, que estávamos passando a função anônima
	return http.HandlerFunc(createCompanyHandler)
}
```
Eu não vou seguir assim porque separar a implementação e a transformação em http.Handler faria nosso código ficar confuso e cheio de referências desnecessárias. Mas a ideia foi explicar este ponto de forma mais clara.


#### MakeCompanyHandlers

Bom, a função `createCompany` cria uma implementação que pode ser atrelada a uma rota, mas ainda não foi atrelada a nenhuma. Por enquanto, ela é só uma função sem aplicação. E é aí que surge a `MakeCompanyHandlers`. Essa função recebe um objeto `mux.Router`(lembra, lá no arquivo `main.go`, que criamos um router mux? Esse cara que ela recebe) e um personagem novo, o `negroni.Negroni`.

O `mux.Router` é um roteador simples, onde eu especifico as rotas e passo um handler para tratá-las. Condiz bem com o que a gente ta precisando, né?

Mas o que raios faz esse `negroni`? Bom, para entender o que ele faz, precisamos entender o que é uma `middleware` no contexto de api.

`Middlewares` são processos ou lógicas que precisam ser executados sempre que uma ou mais rotas são chamadas, mas que não fazem parte da implementação destas rotas. Por exemplo, um processo de autenticação das minhas rotas. Eu poderia, em todas as rotas que eu criar, validar se o usuário está logado, por exemplo. Mas eu teria que repetir o mesmo código em todas as minhas rotas, e repetir código nunca é bom por muitas razões, entre elas, se um dia eu mudasse a minha autenticação, teria que mudar em todas as rotas que criei. Isso, além de criar acoplamento no código (acoplamento é quando códigos que não deveriam depender um do outro, dependem), atrapalhando os testes, dificultando a manutenção, etc etc etc.

É por isso que utilizamos middlewares. No caso acima, eu apenas criaria um middleware responsável por autenticar o usuário **antes** de chamar a rota que eu preciso. Assim, se o usuário não estivesse logado, o middleware já pararia esse cara. E a minha rota ficaria só com o código que ela tem que ficar, sem se preocupar com autenticação. 

E esse é o papel do `negroni`: prover uma estrutura simples para criarmos middlewares. No código, eu encapsulo a nossa função `createCompany` com o negroni utilizando a função `negroni.Wrap`, que converte um `http.Handler` (lembra dele?) em um `negroni.Handler`, e depois "registro" esse `negroni.Handler` na instância do `negroni` que recebi via parâmetro da função `MakeCompanyHandlers` para que ela "registre" esse novo handler e possa chamá-lo quando implementarmos um middleware. 

O restante é bem simples, chamo a função `router.Handle` com a rota que eu quero servir a implementação da nossa `createCompany`(no caso, `v1/company`), especifico quais métodos HTTP ela deve responder (POST e OPTIONS) e dou um nome para essa rota (createCompany).

Ufa ... Bora terminar de implementar isso aí.

## Integrando nossa rota

Voltando para o arquivo `management_api/api/main.go`, a primeira coisa que vamos fazer é gerar uma instância da classe (posso chamar assim em go? Não sei. Mas vou chamar de classe mesmo assim. Depois a turma me corrige) do `negroni` e depois, chamar a função `MakeCompanyHandlers` passando como parâmetro o router que já tínhamos e a instância do negroni. 

```go
//instancia o mux e o negroni
r := mux.NewRouter()
n := negroni.New()

//Chamo a função MakeCompanyHandlers que registra nossas rotas
handler.MakeCompanyHandlers(r, n)
```

o arquivo `main.go` inteiro fica assim

```go
package main

import (
    "io"
    "log"
    "net/http"
    "os"
    "strconv"
    "time"

    "github.com/gorilla/context"
    "github.com/gorilla/mux"
    "github.com/marcelocpinheiro/communication-engine/management_api/config"
)

func main() {
    //instancia o mux e o negroni
    r := mux.NewRouter()
    n := negroni.New()

    //Chamo a função MakeCompanyHandlers que registra nossas rotas
    handler.MakeCompanyHandlers(r, n)

    // Repassa as rotas para o roteador
    http.Handle("/", r)

    // Cria um handler para a url "/ping", escreve "running" na tela e retorna o status 200
    r.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Running")
        w.WriteHeader(http.StatusOK)
    })

    // Cria um logger para a aplicação
    logger := log.New(os.Stderr, "logger: ", log.Lshortfile)

    // Instancia um novo servidor com configurações específicas de timeout, endereço, log e handler
    srv := &http.Server{
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
        Addr:         ":" + strconv.Itoa(config.API_PORT),
        Handler:      context.ClearHandler(http.DefaultServeMux),
        ErrorLog:     logger,
    }

    //Printa no terminal a porta que a aplicação está ouvindo
    log.Printf("Listening on port %d", config.API_PORT)

   //inicia o servidor e, se houver erro, mata a aplicação e printa o erro
    err := srv.ListenAndServe()
    if err != nil {
        log.Fatal(err.Error())
    }
}
```

E é isso. Bora rodar? 

```bash
go run management_api/api/main.go
```

Quando ver que tá rodando, bora criar uma requisição POST. Eu utilizo o Curl, mas você pode usar o Insomnia, o próprio Postman, fica a seu critério.

Anyway, o comando que você tem que rodar é
```bash
curl --location --request POST 'http://localhost:8080/v1/company'
```

Se tudo deu certo, agora você está vendo a resposta `Teste`, que é o que retornamos na nossa função `createCompany` lá no arquivo `company.go`, indicando que está tudo funcionando.

Fique ligado para acompanhar a série, e siga @devmediano no instagram, devo estar postando mais sobre essa série por lá.

No próximo post vamos criar a implementação do nosso primeiro endpoint, armazenar a empresa na base de dados, retornar um json e também criar um endpoint de listagem de empresas. Até lá!