Using Rust for REST APIs
Founded a YC company named trieve which was built in Rust. I now work at Mintlify.
RESOURCES (nouns) ENDPOINTS (verbs + nouns)
───────────────── ────────────────────────────
User ───────► GET /api/users
POST /api/users
GET /api/users/{id}
PUT /api/users/{id}
DELETE /api/users/{id}
...


Utoipa is the glue that makes Rust good at REST.
#[derive(OpenApi)]
#[openapi(
info(
title = "Trieve API",
description = "Trieve OpenAPI Specification...",
contact(name = "Trieve Team", url = "https://trieve.ai"),
license(name = "BSL", url = "https://github.com/..."),
version = "0.13.0",
),
servers(
(url = "https://api.trieve.ai", description = "Production"),
(url = "http://localhost:8090", description = "Local"),
),
paths(handlers::dataset_handler::create_dataset),
components(schemas(CreateDatasetReqPayload)),
tags((name = "Dataset", description = "Dataset endpoint...")),
)]
pub struct ApiDoc;
.service(
SwaggerUi::new("/swagger-ui/{_:.*}")
.url("/api-docs/openapi.json", ApiDoc::openapi())
)
/// Create Dataset
///
/// Auth'ed user must be an owner of the organization.
#[utoipa::path(
post,
path = "/dataset",
context_path = "/api",
tag = "Dataset",
request_body(content = CreateDatasetReqPayload,
description = "JSON request payload"),
responses(
(status = 200, description = "Dataset created", body = Dataset),
(status = 400, description = "Service error", body = ErrorResponseBody),
),
params(("TR-Organization" = Uuid, Header)),
security(("ApiKey" = ["owner"])),
)]
Maintain flexibility for a migration to JsonRPC.
┌─────────────────┐
│ HTTP Request │
└────────┬────────┘
│
▼
┌─────────────────────────────────────────┐
│ HANDLERS │
│ (parse input, validate, call operator) │
└────────────────────┬────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ OPERATORS │
│ (business logic, DB queries, etc.) │
└─────────────────────────────────────────┘
pub async fn create_dataset_query(
new_dataset: Dataset,
pool: web::Data<Pool>,
) -> Result<Dataset, ServiceError> {
use crate::data::schema::datasets::dsl::*;
let mut conn = pool.get().await
.map_err(|_| ServiceError::BadRequest("Could not get database connection"))?;
diesel::insert_into(datasets)
.values(&new_dataset)
.execute(&mut conn)
.await
.map_err(|err| match err {
Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _) =>
ServiceError::BadRequest("Dataset tracking_id already exists"),
_ => ServiceError::BadRequest("Could not create dataset"),
})?;
Ok(new_dataset)
}
match tokio::time::timeout(
std::time::Duration::from_secs(timeout_secs),
next.call(service_req),
)
Using Rust for REST APIs