Вызов 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"]}

Выполнение базовых запросов 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?;
...

Рекомендации