This is a preview of using warp server to generate an OpenApi document. This aims to mimic the Pet Store API using a special fork of warp.
View the documentation generated here!
View the OpenAPI file generated here.
This binary does two things:
- Produce an OpenAPI JSON file (default) describing a warp server.
- Actually run a warp server (
cargo run --feature serve). With the documentation hosted at127.0.0.1:8080/docs.
I've written down some possible macros that would make documentation much easier to write.
Currently the method of defining structs is tedious and prone to human error. e.g.
use warp::document::{DocumentedType, integer, ToDocumentedType};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct User {
id: u32,
user_name: String,
age: u8,
}
impl ToDocumentedType for User {
fn document() -> DocumentedType {
let mut hashmap = HashMap::with_capacity(3);
map.insert("id", integer());
// Needs to manually switch to camel case
map.insert("userName", string().example("Hiru")); // Examples can be added
map.insert("age", integer().description("The age of the *account*, NOT the user."));
map.into()
}
}use warp::document::ToDocumentedType;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, ToDocumentedType)]
#[serde(rename_all = "camelCase")]
pub struct User {
id: u32,
#[example("Hiru")]
user_name: String,
/// The age of the *account*, NOT the user.
age: u8,
}This relies on a few assumptions:
- Procedural Derive Macros can see attributes that don't belong to it. e.g.
#[serde(...)]. This implies that it should work. - Documentation comments desugar to #[doc(...)] attributes.
Currently we chain filters like this:
use warp::{any, document::{document, description, response}, Filter, Rejection, reply::Reply};
fn my_custom_filter() -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone {
any()
.and(document(description("This is my custom filter")))
.and(document(response(200, None)))
.map(|| "Success")
}Using warp::document::document unfortunately only creates Filter that implement Clone but not Copy.
If we use warp::document::exact, we can avoid this by doing
use warp::{any, document::{self, response}, Filter, Rejection};
fn my_custom_filter() -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Copy {
let filter = any().map(|| "Success");
document::exact(filter, |route| {
route.description("This is my custom filter");
route.response(response(200, None))
})
}This function (theoretically) should be able to implement Copy because the filter only holds a function pointer
(please feel free to correct me).
However it introduces more boilerplate and somewhat ugly code.
With a macro we could possibly do something like this:
use warp::{any, Filter, Rejection, reply::Reply};
#[warp_filter]
/// This is my custom filter
#[response(status = 200)]
fn my_custom_filter() -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Copy {
any().map(|| "Success")
}Which would turn into something like
use warp::{any, Filter, Rejection, reply::Reply};
fn my_custom_filter() -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Copy {
let filter = {
any().map(|| "Success")
};
warp::document::exact(filter, |route| {
route.description("This is my custom filter");
route.response(warp::response(200, None))
})
}