
Rust API - Creating the Get by ID Route with Rust - Part V
First we’ll deal with our services file, where we’ll import our Path, to recognize from it the id or uuid in this case, which we’ll work on our search query:
use actix_web::{
get,
post,
web::{
Data,
Json,
scope,
Query,
Path,
ServiceConfig
},
HttpResponse,
Responder
};
And we’ll write our function below:
#[get("/tasks/{id}")]
async fn get_task_by_id(path: Path<uuid::Uuid>, data: Data<AppState>) -> impl Responder {
}
Inside the scope of our function, we’ll start to verify from our URL the task_id, or the uuid from our URL:
#[get("/tasks/{id}")]
async fn get_task_by_id(path: Path<uuid::Uuid>, data: Data<AppState>) -> impl Responder {
let task_id = path.into_inner();
}
Next point is to make our query and error handling:
#[get("/tasks/{id}")]
async fn get_task_by_id(path: Path<uuid::Uuid>, data: Data<AppState>) -> impl Responder {
let task_id = path.into_inner();
let query_result = sqlx
::query_as!(TaskModel, "SELECT * FROM tasks WHERE id = $1", task_id)
.fetch_one(&data.db).await;
match query_result {
Ok(task) => {
let task_note = json!({
"status": "success",
"task": task
});
return HttpResponse::Ok().json(task_note);
}
Err(error) => {
return HttpResponse::InternalServerError().json(
json!({
"status": "error",
"message": format!("{:?}", error)
})
)
}
}
}
Finally, add it to our config:
pub fn config(conf: &mut ServiceConfig) {
let scope = scope("/api")
.service(health_checker)
.service(create_task)
.service(get_all_tasks)
.service(get_task_by_id);
conf.service(scope);
}
Our file in the end looks like this:
src/services.rs
use crate::{
model::TaskModel,
schema:: {
CreateTaskSchema,
FilterOptions
}, AppState
};
use actix_web::{
get,
post,
web::{
Data,
Json,
scope,
Query,
Path,
ServiceConfig
},
HttpResponse,
Responder
};
use serde_json::json;
#[get("/healthchecker")]
async fn health_checker() -> impl Responder {
const MESSAGE: &str = "Health check API is up and running smoothly.";
HttpResponse::Ok().json(json!({"status": "success", "message": MESSAGE }))
}
#[post("/task")]
async fn create_task(body: Json<CreateTaskSchema>, data: Data<AppState>) -> impl Responder {
match
sqlx
::query_as!(
TaskModel,
"INSERT INTO tasks (title, content) VALUES ($1, $2)
RETURNING * ",
body.title.to_string(),
body.content.to_string()
)
.fetch_one(&data.db)
.await {
Ok(task) => {
let task_note = json!({
"status": "success",
"task": task
});
return HttpResponse::Ok().json(task_note);
}
Err(error) => {
return HttpResponse::InternalServerError().json(
json!({
"status": "error",
"message": format!("{:?}", error)
})
)
}
}
}
#[get("/tasks")]
pub async fn get_all_tasks(opts: Query<FilterOptions>, data: Data<AppState>) -> impl Responder {
let limit = opts.limit.unwrap_or(10);
let offset = (opts.page.unwrap_or(1) - 1) * limit;
match
sqlx
::query_as!(
TaskModel,
"SELECT * FROM tasks ORDER by id LIMIT $1 OFFSET $2",
limit as i32,
offset as i32
)
.fetch_all(&data.db)
.await {
Ok(task) => {
let task_note = json!({
"status": "success",
"task": task
});
return HttpResponse::Ok().json(task_note);
}
Err(error) => {
return HttpResponse::InternalServerError().json(
json!({
"status": "error",
"message": format!("{:?}", error)
})
)
}
}
}
#[get("/tasks/{id}")]
async fn get_task_by_id(path: Path<uuid::Uuid>, data: Data<AppState>) -> impl Responder {
let task_id = path.into_inner();
let query_result = sqlx
::query_as!(TaskModel, "SELECT * FROM tasks WHERE id = $1", task_id)
.fetch_one(&data.db).await;
match query_result {
Ok(task) => {
let task_note = json!({
"status": "success",
"task": task
});
return HttpResponse::Ok().json(task_note);
}
Err(error) => {
return HttpResponse::InternalServerError().json(
json!({
"status": "error",
"message": format!("{:?}", error)
})
)
}
}
}
pub fn config(conf: &mut ServiceConfig) {
let scope = scope("/api")
.service(health_checker)
.service(create_task)
.service(get_all_tasks)
.service(get_task_by_id);
conf.service(scope);
}
To test, we’ll create a new task:
curl --request POST \
--url http://localhost:8080/api/task \
--header 'Content-Type: application/json' \
--data '{
"title": "title test2",
"content": "content test"
}'
It should generate this task where I’ll grab our id:
{
"status": "success",
"task": {
"content": "content test",
"created_at": "2023-06-10T15:05:53.710564Z",
"id": "d6b52611-8117-43d3-a8f6-56732ac94bd5",
"title": "title test2"
}
}
And we can test it as follows:
curl --request GET \
--url http://localhost:8080/api/tasks/d6b52611-8117-43d3-a8f6-56732ac94bd5
And we get the following result:
{
"task":{
"content":"content test",
"created_at":"2023-06-10T15:05:53.710564Z",
"id":"d6b52611-8117-43d3-a8f6-56732ac94bd5",
"title":"title test2"
}
"status":"success"
}
And well, that’s it for today!