Posted: 2024.06.20
#Rust
Rustのactix-webによるAPIサーバ実装例
Rustを触ってなさすぎて記憶が怪しくなってきたので復習がてら以下の機能をもつAPIサーバを書いた:
- HTMLを返す
- プレーンテキストを返す
- Todo管理API
- GETに対して
Todo
構造体をJSONとして返す - POSTされたJSONを
Todo
構造体に変換
- GETに対して
- パラメタに基づいて動的に生成した画像を返す
use serde::{Serialize, Deserialize};
use image::{
codecs::png::PngEncoder,
ImageEncoder, ColorType, RgbImage
};
use actix_web::{
get, post, web, App, HttpServer, Responder, HttpResponse,
http::{
header::{ContentType},
}
};
#[derive(Serialize, Deserialize, Debug)]
struct Todo {
id: Option<u32>,
content: String,
done: bool,
}
#[get("/todo/{id}")]
async fn get_todo(id: web::Path<u32>) -> impl Responder {
let id_option: Option<u32> = Some(id.into_inner());
HttpResponse::Ok().json(Todo {
id: id_option,
content: String::from("Develop Todo App"),
done: false,
})
}
#[post("/todo")]
async fn post_todo(todo: web::Json<Todo>) -> impl Responder {
println!("Posted: {:?}", todo);
HttpResponse::Ok().body("ok")
}
#[get("/image/{r}")]
async fn fetch_image(r: web::Path<u8>) -> impl Responder {
let r = *r;
let mut img = RgbImage::new(512, 512);
for x in 0..img.width() {
for y in 0..img.height() {
let g = 255 - (x as f32 / img.width() as f32 * 255.0) as u8;
let b = (y as f32 / img.width() as f32 * 255.0) as u8;
img.put_pixel(x, y, image::Rgb([r, g, b]));
}
}
let mut buf = std::io::Cursor::new(Vec::new());
let encoder = PngEncoder::new(&mut buf);
encoder.write_image(&img, img.width(), img.height(), ColorType::Rgb8.into()).unwrap();
let image_content = buf.into_inner();
HttpResponse::Ok()
.content_type(ContentType::png())
.body(image_content)
}
#[get("/greet/{name}")]
async fn greet(name: web::Path<String>) -> impl Responder {
HttpResponse::Ok()
.content_type(ContentType::plaintext())
.body(format!("Hello {name}"))
}
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok()
.content_type(ContentType::html())
.body("<h1>It works!</h1>")
}
#[actix_web::main]
async fn main() -> Result<(), std::io::Error> {
HttpServer::new(|| {
App::new()
.service(get_todo)
.service(post_todo)
.service(fetch_image)
.service(greet)
.service(index)
})
.bind(("127.0.0.1", 4134))?
.run()
.await
}
curl
で/todo
にPOSTを投げる際は以下のように書く:
curl -X POST http://localhost:4134/todo \
-d '{"content": "aaa", "done": false}' \
-H "Content-Type: application/json"
また,/image/255
にGETアクセスしたときの戻り値は以下のような画像になる: