---
title: "Fazer Requisição HTTP em Rust"
url: "https://rustlang.com.br/receitas/fazer-requisicao-http/"
markdown_url: "https://rustlang.com.br/receitas/fazer-requisicao-http.MD"
description: "Aprenda como fazer requisição HTTP em Rust com reqwest. GET, POST, headers, JSON body e chamadas assíncronas com tokio. Exemplos completos."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Fazer Requisição HTTP em Rust

Aprenda como fazer requisição HTTP em Rust com reqwest. GET, POST, headers, JSON body e chamadas assíncronas com tokio. Exemplos completos.


# Fazer Requisição HTTP em Rust

A crate `reqwest` é a biblioteca HTTP mais popular do ecossistema Rust. Ela suporta requisições síncronas e assíncronas, headers personalizados, envio de JSON, upload de arquivos e muito mais.

## Dependências

**Cargo.toml:**
```toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
```

## Requisição GET simples

A forma mais básica de fazer uma requisição HTTP:

```rust
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // GET simples — retorna o corpo como String
    let resposta = reqwest::get("https://httpbin.org/get")
        .await?
        .text()
        .await?;

    println!("Resposta:\n{}", resposta);

    Ok(())
}
```

**Saída (simplificada):**
```
Resposta:
{
  "args": {},
  "headers": {
    "Host": "httpbin.org",
    ...
  },
  "url": "https://httpbin.org/get"
}
```

## GET com verificação de status

Sempre verifique o status da resposta em código de produção:

```rust
use reqwest;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let resposta = reqwest::get("https://httpbin.org/status/200").await?;

    println!("Status: {}", resposta.status());
    println!("Content-Type: {:?}", resposta.headers().get("content-type"));

    if resposta.status().is_success() {
        let corpo = resposta.text().await?;
        println!("Sucesso! Corpo: {} bytes", corpo.len());
    } else {
        println!("Erro HTTP: {}", resposta.status());
    }

    // error_for_status() converte códigos 4xx/5xx em erro
    let resultado = reqwest::get("https://httpbin.org/status/404")
        .await?
        .error_for_status();

    match resultado {
        Ok(_resp) => println!("Tudo certo!"),
        Err(e) => println!("Erro esperado: {}", e),
    }

    Ok(())
}
```

**Saída:**
```
Status: 200 OK
Content-Type: Some("text/html; charset=utf-8")
Sucesso! Corpo: 0 bytes
Erro esperado: HTTP status client error (404 Not Found) for url (https://httpbin.org/status/404)
```

## POST com corpo JSON

Envie dados JSON no corpo da requisição:

```rust
use reqwest;
use serde::{Deserialize, Serialize};
use std::error::Error;

#[derive(Serialize)]
struct NovoPedido {
    produto: String,
    quantidade: u32,
    preco_unitario: f64,
}

#[derive(Debug, Deserialize)]
struct Resposta {
    json: serde_json::Value,
    url: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let pedido = NovoPedido {
        produto: "Notebook Rust Edition".to_string(),
        quantidade: 2,
        preco_unitario: 4599.90,
    };

    let client = reqwest::Client::new();

    let resposta = client
        .post("https://httpbin.org/post")
        .json(&pedido) // serializa automaticamente para JSON
        .send()
        .await?
        .json::<Resposta>()
        .await?;

    println!("URL: {}", resposta.url);
    println!("Dados enviados: {:#}", resposta.json);

    Ok(())
}
```

**Saída:**
```
URL: https://httpbin.org/post
Dados enviados: {
  "preco_unitario": 4599.9,
  "produto": "Notebook Rust Edition",
  "quantidade": 2
}
```

## Headers personalizados

Adicione headers de autenticação, tipo de conteúdo e outros:

```rust
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE, USER_AGENT};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Headers por requisição
    let client = reqwest::Client::new();

    let resposta = client
        .get("https://httpbin.org/headers")
        .header(USER_AGENT, "MeuApp/1.0")
        .header(AUTHORIZATION, "Bearer meu-token-aqui")
        .header("X-Custom-Header", "valor-personalizado")
        .send()
        .await?
        .text()
        .await?;

    println!("Headers enviados:\n{}", resposta);

    // Headers padrão para todas as requisições do client
    let mut headers_padrao = HeaderMap::new();
    headers_padrao.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
    headers_padrao.insert(USER_AGENT, HeaderValue::from_static("MeuApp/1.0"));

    let client = reqwest::Client::builder()
        .default_headers(headers_padrao)
        .timeout(std::time::Duration::from_secs(10))
        .build()?;

    let resp = client
        .get("https://httpbin.org/get")
        .send()
        .await?;

    println!("\nStatus com headers padrão: {}", resp.status());

    Ok(())
}
```

**Saída (simplificada):**
```
Headers enviados:
{
  "headers": {
    "Authorization": "Bearer meu-token-aqui",
    "User-Agent": "MeuApp/1.0",
    "X-Custom-Header": "valor-personalizado",
    ...
  }
}

Status com headers padrão: 200 OK
```

## Requisições paralelas

Faça múltiplas requisições ao mesmo tempo com `join!`:

```rust
use reqwest;
use std::error::Error;
use tokio;

async fn buscar_url(url: &str) -> Result<(String, u16, usize), Box<dyn Error + Send + Sync>> {
    let resp = reqwest::get(url).await?;
    let status = resp.status().as_u16();
    let corpo = resp.text().await?;
    Ok((url.to_string(), status, corpo.len()))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let urls = vec![
        "https://httpbin.org/get",
        "https://httpbin.org/ip",
        "https://httpbin.org/user-agent",
        "https://httpbin.org/headers",
    ];

    // Executar todas as requisições em paralelo
    let mut handles = Vec::new();
    for url in urls {
        handles.push(tokio::spawn(buscar_url(url)));
    }

    println!("{:<45} {:>6} {:>10}", "URL", "Status", "Bytes");
    println!("{}", "-".repeat(63));

    for handle in handles {
        match handle.await? {
            Ok((url, status, tamanho)) => {
                println!("{:<45} {:>6} {:>10}", url, status, tamanho);
            }
            Err(e) => println!("Erro: {}", e),
        }
    }

    Ok(())
}
```

**Saída:**
```
URL                                           Status      Bytes
---------------------------------------------------------------
https://httpbin.org/get                          200        364
https://httpbin.org/ip                           200         32
https://httpbin.org/user-agent                   200         44
https://httpbin.org/headers                      200        220
```

## Versão síncrona (blocking)

Se você não precisa de async, use a feature `blocking`:

**Cargo.toml:**
```toml
[dependencies]
reqwest = { version = "0.12", features = ["json", "blocking"] }
```

```rust
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // GET síncrono
    let corpo = reqwest::blocking::get("https://httpbin.org/ip")?
        .text()?;

    println!("IP: {}", corpo);

    Ok(())
}
```

## Veja também

- [Criar Servidor HTTP](/receitas/criar-servidor-http/) — construa o lado servidor
- [Parse JSON em Rust](/receitas/parse-json/) — processe as respostas JSON
- [Serializar Struct para JSON](/receitas/serializar-json/) — prepare dados para enviar
- [Async/Await Básico](/receitas/async-await-basico/) — entenda o modelo assíncrono
- [Conectar ao PostgreSQL](/receitas/conectar-postgresql/) — persista dados de APIs
- Documentação da crate: [reqwest](https://docs.rs/reqwest/)
