Введение
В этой статье представлен фреймворк actix-web для создания restful apis на языке Rust. Фреймворк actix-web поможет вам быстро создать быстрые и эффективные restful apis с помощью языка программирования Rust.
Предварительные условия
Чтобы понять эту статью, вы должны обладать рабочими знаниями языка Rust, и у вас на компьютере должен быть установлен Rust.
Что такое REST API?
REST API — это API, соответствующие принципу Representational State Transfer. REST API позволяют использовать HTTP-запросы для управления данными и ресурсами на сервере. Эти API очень полезны при создании интерфейсов для доступа других приложений к ресурсам на сервере.
Что такое Actix Web?
Actix Web — это микрофреймворк для создания REST API на языке Rust. Этот фреймворк маленький, простой, мощный и быстрый. Он создан на языке Rust, что является причиной его скорости.
Освоить этот фреймворк очень просто, особенно если вы программист на Rust. Если у вас нет большого опыта работы с Rust, это будет немного сложнее, если вы слишком рано углубитесь в детали. Этот фреймворк очень прост для начала, но требуется некоторое время, чтобы привыкнуть к нему.
Почему стоит использовать Actix Web?
Ниже перечислены причины, по которым стоит использовать Actix Web для ваших API:
- Он безопасен для типов, что означает, что он сильно типизирован везде.
- Он поставляется с большим количеством функций, таких как статический сервис, промежуточные модули, WebSockets и так далее.
- Он эффективен, что означает, что один сервер может обслуживать миллиарды пользователей, не оставляя большого следа.
- Он прагматичен, что означает, что его легко освоить большинству разработчиков Rust.
Простой API с Actix Web
В этом разделе вы узнаете, как создать простой API с помощью Actix Web. Этот пример даст вам базовое понимание того, как мы создаем RESTful API с помощью Actix Web.
Перед созданием API необходимо инициализировать проект и добавить зависимость Actix Web версии 4.0.1 в файл Cargo.toml.
actix-web = "4.0.1"
После добавления вышеуказанного в файл Cargo.toml, соберите проект для установки библиотеки и всех ее зависимостей с помощью команды ниже:
cargo build
Когда проект будет собран, перейдите в папку src и скопируйте приведенный ниже текст в файл main.rs.
use actix_web::{
HttpServer,
App,
web,
get,
post,
Responder,
};
#[get("/")]
async fn greet() -> impl Responder {
"Hello"
}
#[post("/hello-post")]
async fn hello_post() -> impl Responder {
let greeting = "Hello";
format!("{}, from the post method", greeting)
}
async fn route_hello() -> impl Responder {
let greeting = "Hi";
format!("{greeting}, from route-hello")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Server running...");
HttpServer::new(|| {
// Create and return an new app
App::new()
.service(greet)
.service(hello_post)
.route("/route-hello", web::get().to(route_hello))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Приведенная выше программа создает три маршрута при запуске программы.
Первый маршрут — корневой («/»). Когда вы посылаете запрос get на этот маршрут, он отвечает «Hello».
Второй маршрут — «/hello-post». Когда вы посылаете этому маршруту запрос post, он отвечает «Hello, from the post method».
Третий маршрут — «/route-hello». Когда вы отправляете запрос get на этот маршрут, он отвечает «Привет, от route-hello».
Третий маршрут создается с помощью более ручного метода создания маршрута API. Если вы создаете свой API в одном файле (без разделения кода на модули), я рекомендую использовать первые два метода создания маршрутов. Отследить, какая функция относится к тому или иному маршруту, становится сложнее, когда все функции находятся в одном файле.
Параметры пути
Параметры пути используются для указания категории данных, которые необходимо получить или обработать в API. Ниже приведен пример программы, в которой используются параметры пути:
use actix_web::{
HttpServer,
App,
web,
get,
Responder,
};
#[get("/hello/{name}/{age}")]
async fn hello_1(path: web::Path<(String, u32)>) -> impl Responder {
// The method call below moves "path" out of scope
let (name, age) = path.into_inner();
format!("Name: {name}nAge: {age}")
}
#[get("/{person}/greet")]
async fn hello_2(path: web::Path<(String, )>) -> impl Responder {
// path is borrowed here, which means you can use it again and again
let person = &path.0;
format!("{person}: Hello!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(hello_1)
.service(hello_2)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Приведенная выше программа создает три маршрута при запуске программы.
Первый маршрут — это «/hello/{имя}/{возраст}». Если вы отправите запрос get на «/hello/John/23», вы получите ответ, показанный ниже.
Name: John
Age: 23
Второй маршрут — «/{person}/speak». Если вы отправите запрос get на «/Hannah/speak», вы получите ответ ниже.
Hanna: Hello!
Переменные состояния
Rust не допускает глобальных переменных, что означает, что вы не можете иметь общее состояние приложения обычным способом. Состояние приложения полезно для обмена данными между маршрутами API. Чтобы иметь состояние приложения, создайте переменную struct и зарегистрируйте ее в приложении.
Ниже приведен пример API, в котором используется состояние приложения.
use actix_web::{
HttpServer,
App,
get,
web,
Responder,
};
// The App State's structure
struct AppState {
name: String,
numbers: Vec<u32>,
}
#[get("/")]
async fn display(data: web::Data<AppState>) -> impl Responder {
// data is a borrowed version of the state
format!("Name: {}nNumbers: {:?}", &data.name, &data.numbers)
}
#[get("/{query}")]
async fn access_data(path: web::Path<(String, )>, data: web::Data<AppState>) -> impl Responder {
let query = &path.0;
if query == "list" {
return format!("{:?}", &data.numbers);
} else {
return "not found".to_string();
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.app_data(web::Data::new(
// Register the app state
AppState {
name: "numbers".to_string(),
numbers: vec![10, 20, 30],
}
))
.service(display)
.service(access_data)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Состояние приложения позволяет использовать переменные «name» и «numbers» во всех маршрутах.
Изменяемые переменные состояния
Состояние приложения, созданное в предыдущем разделе, является неизменяемым, что означает, что оно не может изменяться. По умолчанию Rust делает эти переменные неизменяемыми, чтобы предотвратить их изменение во время выполнения. Чтобы сделать состояние приложения изменяемым, необходимо использовать Mutex.
Mutex — это структура, которая предоставляется стандартной библиотекой и может быть использована для добавления изменяемых переменных состояния в общее состояние приложения.
Чтобы создать изменяемую переменную состояния, мы создаем обычную структуру и инициализируем каждое поле как тип Mutex<T>. Структура Mutex является общей, и может быть инициализирована любой другой структурой данных.
Ниже приведен пример простого API с изменяемыми переменными состояния:
use std::sync::Mutex;
use actix_web::{
HttpServer,
App,
get,
web,
Responder,
};
struct AppState {
numbers: Mutex<Vec<u32>>,
}
#[get("/add/{number}")]
async fn add_number(path: web::Path<(u32, )>, data: web::Data<AppState>) -> impl Responder {
/* Add the number from the path parameter to the end of "numbers"
in the app state */
let mut number = data.numbers.lock().unwrap();
let number_to_add = path.into_inner().0;
number.push( number_to_add );
format!("Current list: {:?}", number)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Mutable app state should be created outside
let state = web::Data::new(AppState {
numbers: Mutex::new(vec![10, 20, 30])
});
HttpServer::new(move || {
App::new()
.app_data(state.clone()) // <- move created app state to closure and register
.service(add_number)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
В главной функции приведенной выше программы переменная состояния была создана вне закрытия, поскольку web::Data использует Arc внутри программы. Создание состояния приложения не позволяет приложению создавать больше Arc’ов.
Заключение
Если вы хотите узнать больше о фреймворке Actix Web, обязательно ознакомьтесь с его документацией. Я надеюсь, что эта статья была для вас полезной.
Спасибо за прочтение! И счастливого хакинга!