Agora que nossa API já consegue cadastrar, listar e gerenciar as respostas com o charset correto, precisamos aprender a atualizar os dados de um aluno que já existe no sistema. Nesta aula, usaremos o método PUT e descobriremos como capturar informações passadas diretamente na URL.
Para alterar um estudante específico, o cliente precisa nos dizer quem ele quer modificar. O padrão do mercado para isso é passar o identificador único diretamente na URL do endpoint, ficando algo como: /alunos/a7b2c891-....
No roteador nativo das versões modernas do Go, definimos essa variável dinamicamente usando chaves na rota: "PUT /alunos/{codigo}". Para recuperar esse valor de dentro do nosso código de forma extremamente simples, utilizamos o método r.PathValue("codigo").
A função de alteração executa um algoritmo muito seguro baseado nos passos abaixo:
r.PathValue("codigo").alunos procurando o registro correspondente.mediaSituacao para recalcular as notas automaticamente e substituímos o objeto antigo pelo novo diretamente no índice correspondente do slice.for e dispara um erro 404 Not Found (http.StatusNotFound) avisando que o estudante não existe.Abra o seu arquivo main.go e insira a nova função alterarAluno, mapeando a rota PUT /alunos/{codigo} na função principal do servidor. O código completo do projeto deve ficar estruturado assim:
// Pacote principal da aplicação
package main
// Importações
import (
"encoding/json"
"fmt"
"net/http"
"github.com/google/uuid"
)
// 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; charset=utf-8")
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) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
var aluno Aluno
erro := json.NewDecoder(r.Body).Decode(&aluno)
if erro != nil {
http.Error(w, "Falha ao decodificar o JSON", http.StatusBadRequest)
return
}
aluno.Codigo = uuid.New().String()
mediaSituacao(&aluno)
alunos = append(alunos, aluno)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(aluno)
}
// Função responsável pela alteração de dados de um aluno
func alterarAluno(w http.ResponseWriter, r *http.Request) {
// Definir o cabeçalho explicitando o charset UTF-8
w.Header().Set("Content-Type", "application/json; charset=utf-8")
// Extrair o código dinâmico enviado na URL da requisição
codigo := r.PathValue("codigo")
// Laço de repetição para procurar o aluno no nosso slice global
for indice := range alunos {
// Condicional para verificar o código de cada aluno existente
if alunos[indice].Codigo == codigo {
// Cria uma instância vazia de aluno para receber as novas modificações
var aluno Aluno
// Decodificar JSON recebido com os novos dados
erro := json.NewDecoder(r.Body).Decode(&aluno)
if erro != nil {
http.Error(w, "Falha ao decodificar o JSON", http.StatusBadRequest)
return
}
// Garante que o código original do aluno seja preservado e injetado na nova instância
aluno.Codigo = codigo
// Recalcular a média e a situação com base nas novas notas enviadas
mediaSituacao(&aluno)
// Substitui o aluno antigo pelos novos dados no índice correto do Slice
alunos[indice] = aluno
// Definir o Status Code como 200 OK para atualizações bem-sucedidas
w.WriteHeader(http.StatusOK)
// Retorna o aluno modificado com os dados atualizados
json.NewEncoder(w).Encode(aluno)
// Finaliza imediatamente a ação de alteração para poupar processamento
return
}
}
// Caso o laço termine sem encontrar o ID informado, retorna erro 404
http.Error(w, "Código não encontrado", http.StatusNotFound)
}
// Função principal
func main() {
// Definição das rotas da API
http.HandleFunc("GET /", helloWorld)
http.HandleFunc("GET /alunos", listarAlunos)
http.HandleFunc("POST /alunos", cadastrarAluno)
http.HandleFunc("PUT /alunos/{codigo}", alterarAluno) // Nova rota com parâmetro dinâmico
// Retornar o funcionamento do servidor
fmt.Println("Servidor em execução no endereço: http://localhost:8080")
// Configurar servidor
http.ListenAndServe(":8080", nil)
}
Para testar esta nova rota, siga estes passos ordenados dentro do seu testador HTTP (como Thunder Client):
POST para colocar um aluno válido na memória. Copie o campo codigo que o servidor gerou para ele.PUT e altere a URL adicionando o código copiado no final (ex: http://localhost:8080/alunos/COLE_O_CODIGO_AQUI).O servidor retornará o status 200 OK e os dados totalmente atualizados, exibindo a nova média e o status recalculado para "Aprovado(a)" instantaneamente!