Requisições HTTP em Go

Requisições HTTP em Go

Realizar requisições HTTP hoje em dia, é um dos assuntos mais pertinentes que um desenvolvedor em GoLang precisa saber 🤓

E você sabe por que?

Porque grande parte dos sistemas hoje, estão conectados e integrados entre si por meio da internet, sejam parcialmente ou totalmente.

Como é o caso de um gerenciador de estoque que está instalado na máquina de uma determinada filial, e que precisa manter seu banco de dados constantemente atualizado com um serviço que está na nuvem.

E a forma comumente usada para "trocar dados" entre sistemas envolve o uso do protocolo HTTP.

Mas você sabe o que é um protocolo de internet? O que é HTTP, pra que ele serve, e que ele faz?

Não, então fique tranquilo pois nesta lição você vai aprender tudo isso e mais um pouco 😋

O que é um protocolo de internet?

Um protocolo de internet é um conjunto de regras e padrões que define como os dispositivos se comunicam entre si na rede.

Ele estabelece um conjunto de diretrizes para o envio, recepção e interpretação dos dados na internet ou em redes locais.

Pense num protocolo de internet como uma espécie de meio utilizado para transferirmos dados entre dispositivos diferentes.

É por meio dele que:

✅ Definiremos como os dados são estruturados e transmitidos.

✅ Garantiremos que dispositivos diferentes possam se entender.

✅ Definiremos as regras de endereçamento e roteamento.

✅ Controlaremos a segurança, confiabilidade e erros na comunicação.

E como dito anteriormente, existem diferentes tipos de protocolos de internet que podemos utilizar, vamos começar com o primeiro deles, o famoso Protocolo IP (Internet Protocol).

Protocolo IP (Internet Protocol)

Você já deve ter ouvido falar de um tal de IP alguma vez na sua vida, não é verdade? 🙃

Este tipo de protocolo é responsável pelo endereçamento e roteamento dos pacotes de dados. Onde cada dispositivo conectado à internet, recebe um endereço de IP único.

Observação: você pode pensar no protocolo IP como seu RG ou CPF da sua identidade, onde cada pessoa tem um RG/CPF único e que não se repete.

Com relação a este tipo de protocolo, existem dois tipos deles:

  • IPv4 (Exemplo: 192.168.1.1)
  • IPv6 (Exemplo: 2001:db8::ff00:42:8329)

Protocolo TCP (Transmission Control Protocol)

Já o protocolo TCP, ele garante mais confiabilidade na transmissão de dados, pois ele divide a mensagem em pequenos pacotes, para que os mesmos sejam enviados e verificados corretamente pela máquina receptora.

Um grande exemplo do uso do protocolo TCP, são navegadores de internet, emails e transferências de arquivos.

Protocolo UDP (User Datagram Protocol)

Diferente do protocolo TCP, nós temos o UDP que é usado para enviar pacotes sem a necessidade de verificar se eles chegaram corretamente ao seu destino final.

E sim, ele funciona de uma forma mais rápida que o TCP, porém ele é considerado menos confiável, pois você nunca sabe se o pacote chegou ou não.

Tal pacote é muito utilizado em chamadas VoIP, jogos online e streaming de vídeos.

Protocolo HTTP/HTTPS (Hypertext Transfer Protocol)

Este tipo de protocolo é o queridinho entre os desenvolvedores de software. Pois será a partir do HTTP/HTTPS que é definido como as páginas da web são requisitadas e transmitidas.

Usamos o HTTP para requisições não seguras para web. Já o HTTPS (famoso cadeado verde na barra do navegador) é usado para adicionar criptografia usando SSL/TLS para aumentar a segurança da conexão.

Protocolo DNS (Domain Name System)

No caso do protocolo DNS, você ainda vai ouvir muito dele quando estiver trabalhando com domínios e servidores de hospedagem.

Quando você compra um domínio (Por exemplo: seusite.com), inevitavelmente você vai precisar apontar seu domínio para algum servidor na qual contenha os arquivos do seu site.

E o simples fato de você precisar apontar o domínio, envolve o uso do protocolo DNS. Que é responsável por converter nomes de domínio em endereços de IP.

Com isso você consegue acessar o conteúdo do seu site por meio do nome do seu domínio (seusite.com), em vez de ficar digitando o endereço de IP do seu servidor (182.176.8.9)

Protocolo FTP (File Transfer Protocol)

Como o próprio nome já nos diz, o protocolo FTP é usado para transferir arquivos entre servidores e clientes.

Ele é extremamente útil quando você precisa transferir de forma direta seus arquivos para algum dispositivo que está conectado a internet.

Quando você tem um servidor online, você pode usar o protocolo FTP em conjunto com algum software que seja capaz de fazer essa ponte, e transferir seus arquivos para seu servidor.

Protocolo SFTP (Secure File Transfer Protocol)

O SFTP (Protocolo Seguro de Transferência de Arquivos) é um protocolo usado para transferir arquivos de forma segura entre um cliente e um servidor, utilizando criptografia via SSH (Secure Shell).

Ele atua como uma alternativa segura ao FTP. E diferente do FTP e FTPS, o SFTP não usa múltiplas conexões — ele opera dentro do protocolo SSH, garantindo segurança por padrão.

Os mesmos softwares que você utilizaria para realizar conexões FTP, também costumam possuir suporte ao SFTP.

Protocolo SMTP/POP3/IMAP (Emails)

Os protocolos SMTP, POP3 e IMAP são usados para enviar e receber emails na internet. Cada um tem uma função específica:

  • SMTP (Simple Mail Transfer Protocol): usando para enviar emails.
  • POP3 (Post Office Protocol 3): usado para baixa emails para o dispositivo.
  • IMAP (Internet Message Access Protocol): usado para gerencia emails no servidor.

Agora que você já sabe o funcionamento dos protocolos de internet, vamos focar agora no entendimento detalhado do nosso querido protocolo HTTP 😇

O que é o protocolo HTTP?

Como dito anteriormente, o HTTP (HyperText Transfer Protocol) é um protocolo que permite a comunicação entre clientes e servidores na web.

Ele define como as mensagens são formatadas e transmitidas, e como os servidores e navegadores devem responder às diversas solicitações.

Uma requisição HTTP é composta pelos seguintes componentes que precisamos declarar para compor este tipo de requisição:

Método HTTP: precisamos informar a ação a ser executada, neste ponto nós desenvolvedores precisamos informar o método que iremos usar para isso (GET, POST, PUT, DELETE, etc.).

URL (Uniform Resource Locator): também precisamos informar o endereço do recurso no servidor, que nada mais é do que o IP (188.987.1.2) ou o nome do domínio (seusite.com/usuarios)

Headers: além disso, podemos passar informações adicionais como tipo de conteúdo, autenticação, etc. O Header nada mais é do que o cabeçalho da requisição.

Corpo (Body): por fim, e não menos importante, podemos (ou não) passar os dados a serem enviados na requisição. Como é o caso de um arquivo em JSON, XML, CSV ou qualquer outro tipo de informação que você queria.

Para que você possa entender melhor, vamos supor que uma requisição HTTP é uma carta que será enviada para o endereço de alguém:

Podemos dizer que o método HTTP seria o 📬 tipo de carta (convite, reclamação, solicitação) e representa a intenção da requisição:

  • GET: Pedindo informações (exemplo: solicitando um catálogo de produtos).
  • POST: Enviando algo novo (exemplo: um pedido de compra).
  • PUT: Atualizando algo (exemplo: corrigindo um endereço cadastrado).
  • DELETE: Pedindo para excluir algo (exemplo: cancelar um pedido).

A URL pode ser representada pelo 📩 envelope daquela carta, onde contém as informações de endereço de destino. Ele indica para onde a carta (requisição) deve ser enviada.

Os Headers, podem ser representados pelas informações que existem no 📝 topo da carta, como remetente, destinatário, data e assunto. Eles trazem metadados importantes, tais como:

  • De quem veio? (User-Agent)
  • Tipo de papel usado? (Content-Type: application/json)
  • Autorização para abrir a carta? (Authorization: Bearer token)

O Body (Corpo da Requisição), nada mais é do que o 📄 conteúdo que existe dentro do envelope, ou seja, os dados enviados ao servidor (como um formulário preenchido ou um JSON).

Por fim, e não menos importante (e que de uma certa forma não está totalmente atrelado à aquela carta) é o famoso 📌 selo postal, que representa o protocolo HTTP/HTTPS.

O selo e as regras de envio garantem que a carta será processada corretamente, assim como o protocolo HTTP/1.1, HTTP/2 ou HTTP/3.

Dessa forma, o servidor age como o destinatário da carta, processando a requisição e enviando uma resposta HTTP de volta. 🚀

Exemplo de uma requisição HTTP

Uma requisição HTTP pode ser exemplificada em um formato bruto, como por exemplo:

POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer <TOKEN>
Content-Length: 45

{
  "name": "micilini",
  "email": "hey@micilini.com"
}

Note que no topo da requisição, informamos o método, seguido do endpoint (/api/users) e da versão do protocolo (HTTP/1.1), indicando que estamos fazendo uma requisição POST para criar um novo usuário na API.

A seguir, temos os headers, que fornecem informações essenciais para o servidor processar a requisição corretamente:

Host (example.com): indica o domínio do servidor que receberá a requisição.

Content-Type (application/json): especifica o formato dos dados enviados no corpo da requisição. Aqui, estamos usando JSON.

Authorization (Bearer <TOKEN>): fornece um token de autenticação necessário para validar a requisição e garantir que apenas usuários autorizados possam acessar esse recurso.

Content-Length (45): indica o tamanho (em bytes) do corpo da requisição. Isso ajuda o servidor a saber exatamente quantos dados esperar.

Logo após os headers, temos uma linha em branco que separa os metadados do corpo da requisição (body).

No body, enviamos os dados do novo usuário que queremos criar, utilizando o formato JSON:

{
  "name": "Micilini",
  "email": "hey@micilini.com"
}

Caso a requisição seja bem-sucedida, o servidor pode responder com um código HTTP 201 Created, indicando que o usuário foi criado com sucesso.

E falando em códigos de retorno, que tal aprendermos um pouco mais sobre eles? 🙃

Status Code HTTP

Quando realizamos uma requisição HTTP, nos é retornado alguns status dessa requisição.

Funciona como se fosse uma espécie de semáforo, onde o vermelho indica um erro, o amarelo atenção, e o verde que a requisição foi um sucesso.

Só que em vez de retornar cores como os semáforos, uma requisição nos retorna códigos que vão de 200 a 500.

Vejamos alguns deles 😉

Começando pelo status 2xx (200, 201 etc.), ele indica que a requisição foi um sucesso:

  • 200 OK: Requisição bem-sucedida.
  • 201 Created: Recurso criado.
  • 204 No Content: Sem conteúdo (para DELETE, por exemplo).

Temos também o status 3xx (300, 301 etc.), indicando que a requisição sofreu um redirecionamento, ou seja, o endereço daquele link existia, mas foi alterado:

  • 301 Moved Permanently: URL alterada permanentemente.
  • 302 Found: Redirecionamento temporário.

Já quando temos um erro no lado do cliente, costumamos usar os status 4xx (400, 401 e etc.), vejamos:

  • 400 Bad Request: Requisição inválida.
  • 401 Unauthorized: Autenticação necessária.
  • 403 Forbidden: Acesso negado.
  • 404 Not Found: Recurso não encontrado.

Por fim, temos os status 5xx (500, 501 etc.), que indicam um erro no lado do servidor da aplicação:

  • 500 Internal Server Error: Erro interno no servidor.
  • 502 Bad Gateway: Resposta inválida de outro servidor.
  • 503 Service Unavailable: Serviço indisponível temporariamente.

Tais status podem ser interpretados e enviados pela sua própria aplicação, dependendo do contexto onde eles se encontram.

Conhecendo mais sobre os métodos HTTP

Agora voltando um pouco nos métodos HTTP que vimos anteriormente (GET, POST etc.), eles são usados para instruir o servidor sobre o tipo de resultado que você quer.

Atualmente existem 6 deles:

GET: é usado para obter os dados de um servidor, como carregar uma página da web, buscar usuários, buscar produtos e afins:

GET /api/users/1 HTTP/1.1
Host: example.com

POST: é usado para enviar dados para o servidor (geralmente para criar um recurso):

POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "name": "Micilini",
  "email": "hey@micilini.com"
}

PUT: é usado para atualiza um recurso existente (substitui todo o recurso).

PUT /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer <TOKEN>
Content-Length: 45

{
  "name": "Micilini Roll",
  "email": "new@email.com"
}

DELETE: é utilizado para remover um recurso existente na base de dados do servidor em questão:

DELETE /api/users/123 HTTP/1.1
Host: example.com
Authorization: Bearer <TOKEN>

PATCH: é usado para alterar apenas campos específicos, diferente do PUT que altera tudo de uma única vez:

PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json
Authorization: Bearer <TOKEN>
Content-Length: 30

{
  "email": "updated@email.com"
}

OPTIONS: é usado para perguntar ao servidor quais métodos e cabeçalhos são suportados para um determinado recurso. Ele não modifica nem recupera dados, apenas retorna informações sobre a API:

OPTIONS /api/users HTTP/1.1
Host: example.com
Origin: https://myfrontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type

Veja como pode ser seu retorno:

HTTP/1.1 204 No Content
Allow: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: https://myfrontend.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type

Agora que você já sabe tudo o que precisa saber sobre requisições HTTP, vamos então colocar a mão na massa, e aprender a como realizar estes tipos de requisições em GoLang 😁

Criando seu projeto de testes

Dentro da pasta JornadaGoLang, nós iremos criar uma nova pasta chamada de 19-requisicoes-http, onde dentro dela, vamos criar o nosso arquivo main.go:

package main

func main() {

}

Feito isso, vamos aprender a utilizar a biblioteca net/http 😉

Importando a biblioteca net/http no seu projeto

A biblioteca net/http faz parte dos pacotes padrões do GoLang, bastando apenas você fazer a importação da mesma para começar a utilizá-la.

Ela é considerada uma biblioteca excelente para realizar requisições HTTP, atuando de forma robusta, eficiente e sendo amplamente utilizada em projetos profissionais.

Para importar a biblioteca net/http dentro do seu projeto, basta fazer isso da seguinte forma:

import "net/http"

Caso você tiver outras bibliotecas já importadas no seu arquivo, basta usar a lógica abaixo:

import (
    ...
    "net/http"
)

Feito isso, já estamos prontos para vê-la em ação 🤩

Realizando requisições GET com net/http

Como você já sabe, usamos o GET para buscar informações em um servidor.

Para utilizá-lo é bem simples, basta usar a função http.get() informando a URL entre os parêntesis, observe:

package main

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

func main() {
	url := "https://jsonplaceholder.typicode.com/posts/1"

	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Resposta:", string(body))
}

No caso do comando acima, estamos usando um endpoint gratuito (https://jsonplaceholder.typicode.com/) para buscar postagens fictícias e mostrá-las no nosso terminal.

Mas e se quisermos enviar cabeçalhos durante a requisição?

A função http.Get(url) não permite adicionar cabeçalhos diretamente. Para isso, precisamos criar a requisição manualmente com http.NewRequest e adicionar os cabeçalhos antes de enviá-la com um http.Client, vejamos:

package main

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

func main() {
	url := "https://jsonplaceholder.typicode.com/posts/1"

	// Criando um cliente HTTP
	client := &http.Client{}

	// Criando a requisição manualmente
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}

	// Adicionando headers personalizados
	req.Header.Set("Authorization", "Bearer MEU_TOKEN_AQUI")
	req.Header.Set("Custom-Header", "MeuValorPersonalizado")

	// Enviando a requisição
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	// Lendo resposta
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Resposta:", string(body))
}

Realizando requisições POST com net/http

O POST é usado para enviar informações a um determinado servidor, e no caso dele, podemos usar a função http.post() em conjunto com funções responsáveis por montar o corpo da requisição, observe:

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://jsonplaceholder.typicode.com/posts"
	jsonData := `{"title": "GoLang", "body": "Aprendendo Go!", "userId": 1}`
	reqBody := bytes.NewBuffer([]byte(jsonData))

	resp, err := http.Post(url, "application/json", reqBody)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Resposta:", string(body))
}

Mas e se quisermos enviar cabeçalhos a esta requisição?

Neste caso, você precisa criar a requisição manualmente usando http.NewRequest, pois o método http.Post não permite adicionar cabeçalhos diretamente:

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://jsonplaceholder.typicode.com/posts"
	jsonData := `{"title": "GoLang", "body": "Aprendendo Go!", "userId": 1}`
	reqBody := bytes.NewBuffer([]byte(jsonData))

	// Criando cliente HTTP
	client := &http.Client{}

	// Criando a requisição manualmente
	req, err := http.NewRequest(http.MethodPost, url, reqBody)
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}

	// Adicionando headers
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer MEU_TOKEN_AQUI")
	req.Header.Set("Custom-Header", "MeuValorPersonalizado")

	// Enviando requisição
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	// Lendo resposta
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Resposta:", string(body))
}

Note que criamos nossos cabeçalhos usando a função req.Header.Set() junto com o comando client.Do(req), que realmente envia a solicitação.

Realizando requisições PATCH com net/http

Para atualizarmos apenas uma parte de um determinado recurso com PATCH, precisamos usar o NewRequest de forma direta:

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://jsonplaceholder.typicode.com/posts/1"
	jsonData := `{"id": 1, "title": "Atualizado", "body": "Conteúdo atualizado", "userId": 1}`
	reqBody := bytes.NewBuffer([]byte(jsonData))

	client := &http.Client{}
	req, err := http.NewRequest(http.MethodPut, url, reqBody)
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Resposta:", string(body))
}

Observação: você pode usar o comando req.Header.Set() para enviar cabeçalhos a sua requisição (como mostrado em tópicos anteriores).

Realizando requisições PUT com net/http

Para atualizarmos um recurso inteiro, podemos fazer o uso do PUT, também em conjunto com o comando NewRequest de forma direta:  

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://jsonplaceholder.typicode.com/posts/1"
	jsonData := `{"id": 1, "title": "Atualizado", "body": "Conteúdo atualizado", "userId": 1}`
	reqBody := bytes.NewBuffer([]byte(jsonData))

	client := &http.Client{}
	req, err := http.NewRequest(http.MethodPut, url, reqBody)
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Resposta:", string(body))
}

Observação: você pode usar o comando req.Header.Set() para enviar cabeçalhos a sua requisição (como mostrado em tópicos anteriores).

Realizando requisições DELETE com net/http

Para remover um determinado recurso do servidor, você pode usar o DELETE em conjunto com o comando NewRequest da seguinte forma:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url := "https://jsonplaceholder.typicode.com/posts/1"

	client := &http.Client{}
	req, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	fmt.Println("Status:", resp.Status)
}

Observação: você pode usar o comando req.Header.Set() para enviar cabeçalhos a sua requisição (como mostrado em tópicos anteriores).

Realizando requisições OPTIONS com net/http

Por fim, temos o método OPTIONS que é usado para entender o funcionamento de uma API, veja como podemos usá-lo:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url := "https://jsonplaceholder.typicode.com/posts"

	client := &http.Client{}
	req, err := http.NewRequest(http.MethodOptions, url, nil)
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	fmt.Println("Métodos permitidos:", resp.Header.Get("Allow"))
}

Observação: você pode usar o comando req.Header.Set() para enviar cabeçalhos a sua requisição (como mostrado em tópicos anteriores).

Enviando e recebendo JSON com a biblioteca net/http

Como dito anteriormente nesta lição, a grande parte dos sistemas se comunicam entre si por meio de requisições HTTP usando a anotação JSON.

Sendo assim, é muito importante que você saiba como receber e enviar JSON usando a biblioteca net/http 😁

Começando pelo recebimento de um JSON por parte de um servidor externo, você pode usar a seguinte lógica:

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

// Estrutura do JSON esperado
type RequestData struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

// Estrutura do JSON de resposta
type ResponseData struct {
	Message string `json:"message"`
	Status  int    `json:"status"`
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Método não permitido", http.StatusMethodNotAllowed)
		return
	}

	// Lendo o corpo da requisição
	body, err := io.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Erro ao ler o corpo da requisição", http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()

	// Decodificando JSON recebido
	var requestData RequestData
	err = json.Unmarshal(body, &requestData)
	if err != nil {
		http.Error(w, "Erro ao decodificar JSON", http.StatusBadRequest)
		return
	}

	// Criando resposta JSON
	response := ResponseData{
		Message: fmt.Sprintf("Bem-vindo, %s! Seu email é %s.", requestData.Name, requestData.Email),
		Status:  200,
	}

	// Convertendo para JSON
	responseJSON, _ := json.Marshal(response)

	// Definindo cabeçalho da resposta
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(responseJSON)
}

func main() {
	http.HandleFunc("/api", handler)

	fmt.Println("Servidor rodando em http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

Note que estamos utilizando a biblioteca encoding/json para fazer a interpretação de um JSON que recebemos de um servidor em questão.

Para aprender mais sobre o uso de JSON em GoLang, não deixe de consultar nossa lição que fala sobre a manipulação desses arquivos.

Já para enviar um JSON para um servidor específico, você pode fazer isso da seguinte forma:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

// Estrutura para o envio
type RequestData struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

// Estrutura para a resposta
type ResponseData struct {
	Message string `json:"message"`
	Status  int    `json:"status"`
}

func main() {
	url := "http://localhost:8080/api"

	// Criando JSON para enviar
	requestData := RequestData{Name: "William", Email: "william@email.com"}
	jsonData, _ := json.Marshal(requestData)

	// Criando requisição HTTP
	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonData))
	if err != nil {
		fmt.Println("Erro ao criar requisição:", err)
		return
	}

	// Adicionando cabeçalhos
	req.Header.Set("Content-Type", "application/json")

	// Criando cliente HTTP e enviando requisição
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Erro na requisição:", err)
		return
	}
	defer resp.Body.Close()

	// Lendo resposta
	body, _ := io.ReadAll(resp.Body)

	// Decodificando JSON de resposta
	var responseData ResponseData
	json.Unmarshal(body, &responseData)

	fmt.Println("Resposta do servidor:", responseData.Message)
}

Note que ainda estamos usando o encoding/json para enviar o nosso JSON para o servidor externo.

Incrível, não acha? 😄

Repositório da lição

Todos os arquivos relacionados com esta lição, podem ser encontrados nos seguintes repositórios abaixo:

Conclusão

Nesta lição, você aprendeu a fazer o uso da biblioteca net/http para realizar requisições HTTP de diversas formas diferentes (GET, POST, PUT, PATCH etc.).

Além disso, ainda aprendeu um pouco mais sobre a teoria existente por trás dos protocolos de internet, e o uso da anotação JSON em conjunto com HTTP.

Até a próxima lição 😇

Criadores de Conteúdo

Foto do William Lima
William Lima
Fundador da Micilini

Inventor nato, escreve conteudos de programação para o portal da micilini.

Torne-se um MIC 🤖

Mais de 100 mic's já estão conectados na plataforma.