Chegamos a um dos momentos mais importantes e aguardados do nosso treinamento: a criação do endpoint para cadastrar dados na nossa API. Nesta aula, vamos aprender a receber informações enviadas pelo cliente através do corpo da requisição e salvá-las no nosso banco de dados em memória.
Quando um cliente deseja cadastrar algo em uma API REST, ele utiliza o método POST e envia as informações estruturadas em texto no formato JSON dentro do corpo do pedido (conhecido como Request Body).
O papel do nosso servidor Go é ler esse texto JSON e transformá-lo novamente em um objeto utilizável pelo nosso código. Na aula de listagem, nós usamos o json.NewEncoder para transformar nossa Struct em JSON (Codificação). Agora, faremos o processo inverso: usaremos o json.NewDecoder para transformar o JSON recebido em uma Struct do Go (Decodificação).
A nossa nova função realiza um passo a passo muito seguro para processar a requisição:
var aluno Aluno que servirá de molde.json.NewDecoder(r.Body).Decode(&aluno) passando o endereço de memória da nossa variável. Se o cliente enviar um JSON quebrado ou malformado, o Go captura o erro, responde com o status 400 Bad Request através do http.Error e interrompe a execução com o return.uuid e chamamos a nossa função mediaSituacao para calcular a média e preencher a situação de forma automatizada.append para adicionar o aluno processado dentro do nosso slice global alunos.201 Created (http.StatusCreated) e devolvemos o objeto do aluno recém-criado já formatado em JSON.Abra o seu arquivo main.go e adicione a função cadastrarAluno, além de registrar a nova rota POST /alunos dentro da função principal. O código completo atualizado do seu projeto deve ficar assim:
// Pacote principal da aplicação
package main
// Importações
import (
"encoding/json"
"fmt"
"net/http"
"://github.com"
)
// Modelo (Struct)
type Aluno struct {
Codigo string `json:"codigo"`
Nome string `json:"nome"`
Nota1 float64 `json:"nota1"`
Nota2 float64 `json:"nota2"`
Media float64 `json:"media"`
Situacao string `json:"situacao"`
}
// Slice (Nosso banco de dados em memória)
var alunos = []Aluno{}
// Função para gerar a média e a situação
func mediaSituacao(aluno *Aluno) {
// Gerar média
aluno.Media = (aluno.Nota1 + aluno.Nota2) / 2
// Gerar situação
if aluno.Media >= 7 {
aluno.Situacao = "Aprovado(a)"
} else if aluno.Media >= 5 {
aluno.Situacao = "Em Recuperação"
} else {
aluno.Situacao = "Reprovado(a)"
}
}
// Função para retornar um Hello World! (Mantida para testes temporários)
func helloWorld(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
codigoUnico := uuid.New().String()
mensagem := map[string]string{
"codigoUnico": codigoUnico,
"mensagem": "Hello World!",
}
json.NewEncoder(w).Encode(mensagem)
}
// Função responsável pela listagem de alunos
func listarAlunos(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(alunos)
}
// Função responsável pelo cadastro de um aluno
func cadastrarAluno(w http.ResponseWriter, r *http.Request) {
// Definir o cabeçalho como JSON
w.Header().Set("Content-Type", "application/json")
// Objeto do tipo Aluno inicialmente vazio
var aluno Aluno
// Decodificar o JSON recebido no corpo da requisição (r.Body) para a nossa variável aluno
erro := json.NewDecoder(r.Body).Decode(&aluno)
if erro != nil {
// Se houver erro na estrutura do JSON, retorna o status 400 Bad Request
http.Error(w, "Falha ao decodificar o JSON", http.StatusBadRequest)
return
}
// Gerar o código único do aluno de forma automática
aluno.Codigo = uuid.New().String()
// Calcular e preencher a média e a situação automaticamente usando ponteiros
mediaSituacao(&aluno)
// Adicionar o objeto preenchido no final do nosso Slice global
alunos = append(alunos, aluno)
// Definir o Status Code como 201 Created
w.WriteHeader(http.StatusCreated)
// Retorna o objeto do aluno que acabou de ser cadastrado no formato JSON
json.NewEncoder(w).Encode(aluno)
}
// Função principal
func main() {
// Definição das Rotas da nossa API
http.HandleFunc("GET /", helloWorld)
http.HandleFunc("GET /alunos", listarAlunos)
http.HandleFunc("POST /alunos", cadastrarAluno)
// Retornar o funcionamento do servidor
fmt.Println("Servidor em execução no endereço: http://localhost:8080")
// Configurar servidor
http.ListenAndServe(":8080", nil)
}
Como o navegador web comum só consegue realizar requisições do tipo GET diretamente pela barra de endereços, para testar nossa rota de cadastro POST, você precisará usar um cliente HTTP externo de sua preferência, como o Thunder Client (extensão do próprio VSCode), o Postman ou o Insomnia.
Para simular o cadastro, configure o seu cliente HTTP com as seguintes definições:
POSThttp://localhost:8080/alunos{
"nome": "Henrique Silva",
"nota1": 8.5,
"nota2": 6.5
}
Ao clicar em enviar, você verá que o servidor retornará o status 201 Created junto com o aluno totalmente processado, contendo seu ID exclusivo gerado por UUID, a média calculada em 7.5 e a situação preenchida como "Aprovado(a)"!
E o teste mais legal de todos: depois de fazer o cadastro pelo cliente HTTP, abra novamente seu navegador comum na URL http://localhost:8080/alunos. Note que a listagem que antes estava vazia ([]), agora exibirá o estudante que você acabou de salvar!