Первоначально это было опубликовано здесь.

Вызов REST API с помощью rust поначалу может показаться сложной задачей из-за крутой и долгой кривой изучения rust как языка программирования.

Мы знаем, что контакт с REST API — это то, с чем мы сталкиваемся при создании почти любого другого приложения, которое приходит на ум.

Мы воспользуемся reqwest библиотека, чтобы сделать наш запрос, который, по сути, является реализацией HTTP-клиента более высокого уровня по умолчанию.

# Cargo.toml
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
dotenv = "0.15.0" # optional
serde = {version = "1.0.144", features = ["derive"]}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Мы импортируем следующие библиотеки, чтобы сделать эту работу

БиблиотекаЦель
запроссделать наши запросы
Токиоделать асинхронные запросы и другие асинхронные вещи.
основнойчтобы десериализовать ответ json в структуру ржавчины



Выполнение базовых запросов GET

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp = reqwest::get("<url>").await?;
    let resp_json = resp.json::<HashMap<String, String>>().await?;

    println!("{:#?}", resp_json);

    Ok(());
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Здесь мы делаем следующие ключевые вещи:

  • Мы добавляем tokio::main атрибут нашей основной функции, чтобы использовать ожидание внутри нашей функции.
  • Мы меняем возвращаемый тип основной функции с единичного типа — () к Result<(), Box<dyn std::error::Error>> чтобы отловить ошибки из запроса, если они есть.
  • Затем мы делаем запрос с помощью get функцию и ожидание этого, а также мы используем функцию turbofish оператор, чтобы получить только возвращаемый тип future
    • Подробнее о том, почему мы используем этого оператора, см. здесь.
  • Затем мы десериализуем ответ JSON на HashMap<String, String> для удобства и ждать на этом.


Добавление заголовков к нашему запросу

Чтобы добавить заголовки в наш запрос, мы сначала создаем клиент запроса и используем его для добавления заголовков в наше приложение.

use reqwest::header::HeaderMap;

#[tokio::main]
async fn main() {
    ...
    let client = reqwest::Client::new();
    let mut headers = HeaderMap::new();
    headers.insert("content-type", "application/json".parse().unwrap());
Войти в полноэкранный режим

Выйти из полноэкранного режима

use reqwest::header::HeaderMap;

#[tokio::main]
async fn main() {
    ...
    let client = reqwest::Client::new();
    let mut headers = HeaderMap::new();
    headers.insert("content-type", "application/json".parse().unwrap());
    headers.insert("Authorization", format!("Bearer {}", API_TOKEN).parse().unwrap());

    let resp = client.get("<url>")
                                .headers(headers)
                                .send()
                                .await?;

    ...
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Вот что мы сделали выше:

  • Мы создаем клиент запроса для отправки нашего запроса.
  • Мы создаем изменяемый экземпляр HeaderMap Экземпляр, похожий на HashMap
  • Мы вставляем наши заголовки как пары ключ-значение в заголовок.
    • Мы используем .parse().unwrap() на &str преобразовать строковый тип в значение заголовка тип.
  • Затем мы добавляем наши заголовки в клиентский запрос, используя .headers() метод.
  • Кроме того, одно отличие от прямого использования метода get заключается в том, что мы должны вызвать метод send метод по нашему запросу, прежде чем ожидать его.


Отправка почтового запроса с телом JSON

Мы отправляем почтовый запрос, используя post метод на запрос клиента или прямо из библиотеки и используйте json метод добавления тела к почтовому запросу.

Тело здесь просто HashMap в ржавчине.

...
let mut body = HashMap::new();
body.insert("username", "myusername");
let resp = client.post("<url>")
    .json(&body)
    .send()
    .await?;
...
Войти в полноэкранный режим

Выйти из полноэкранного режима


Десериализация ответа JSON

Мы можем десериализовать ответ JSON от API, используя json метод в отправленном запросе и получить его в нашей предпочтительной форме или типе, вызывая его в общем случае с этим типом.

Следует отметить, что тип должен реализовывать трейт Deserialize.

Прежде всего, мы создаем тип, в котором мы хотим получить наш ответ JSON, и реализуем для него трейт десериализации, реализовать трейт самостоятельно утомительно и ненадежно, поэтому мы используем serde библиотека, которую мы импортировали ранее, сделает это за нас.

use serde::Deserialize;

// deriving the Debug trait also to be able to print it
#[derive(Debug, Deserialize)]
struct APIResponse {
    message: String;
    error: String;
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Затем мы можем использовать приведенную выше структуру для десериализации нашего ответа как:

...
let resp_json = resp.json::<APIResponse>().await?;
...
Войти в полноэкранный режим

Выйти из полноэкранного режима


использованная литература