#rocket #openapi #swagger #swagger-ui #rust

macro df_rocket_okapi_codegen

Macros supporting rocket_okapi, used in DF Storyteller project

1 unstable release

0.4.1 Sep 28, 2020

#12 in #swagger-ui


Used in 4 crates (2 directly)

MIT license

23KB
559 lines

Okapi

Okapi: Download API Docs

Rocket-Okapi: Download API Docs

unsafe forbidden

Automated OpenAPI (AKA Swagger) document generation for Rust/Rocket projects.

Never have outdated documentation again. Okapi will generate documentation for you while setting up the server. It uses a combination of Rust Doc comments and programming logic to document your API.

The generated OpenAPI files can then be used by various programs to visualize the documentation. Rocket-okapi currently includes RapiDoc and Swagger UI, but others can be used too.

Supported OpenAPI Spec: 3.0.0
Supported Rocket version (for rocket_okapi): 0.5.0

Example of generated documentation using Okapi:

[^1]: More examples will be added, please open an issue if you have a good example.

Examples

  • Json web API: Simple example showing the basics of Okapi.
  • UUID: Simple example showing basics, but using UUID's instead of normal u32/u64 id's.
  • Custom Schema: Shows how to add more/custom info to OpenAPI file and merge multiple modules into one OpenAPI file.
  • Secure Request Guard: Shows how to implement authentication methods into the OpenAPI file. It shows: No authentication, API keys, HTTP Auth, OAuth2, OpenID and Cookies.
  • Special types: Showing use of some more obscure types and there usage. (Still work in progress)
  • And more

FAQ

Q: Can I generate code from my OpenAPI file?

A: No, this crate only allows you to automatically generate the OpenAPI file from your code. There are other crates that (attempt to) do this. So:

  • (Rust code (Rocket) --> OpenAPI) == Okapi
  • (OpenAPI --> Rust code) != Okapi

Q: How do I document my endpoints?

A: Okapi automatically uses the Rust Doc Comments from most places, this includes: - Endpoint functions. - Endpoint function arguments, using Schemars. Adding documentation for String and other default types is not possible unless used in an other struct. See this issue for more info. - Endpoint function return type, using Schemars. Same rules apply as arguments. In case of Result<T, E>, the error codes can be documented, see this example.

Some more info can be provided using the #[openapi(...)] derive macro, for more info see: OpenApiAttribute.

Schemars also can be used to provide more info for objects that implement #[derive(JsonSchema)] using the #[schemars(...)] and #[serde(...)] syntax. For more info see Attrs

Documentation can be enhanced in most other places too, but might require custom implementations. See our examples for more info.

If the above is not sufficient, you can always create your custom OpenAPI objects. This will can then be merged into the final OpenAPI file. For more info see this example. Use this method only if really necessary! (As it might overwrite other generated objects.)

Q: My (diesel) database does not implement OpenApiFromRequest.

A: This is because the parameter does not show up in the path, query or body. So this is considered a Request Guard. There is a derive macro for this, but this does not work in combination with the #[database("...")] marco. You can solve this my implementing it manually, like this:

Implement `OpenApiFromRequest` for Diesel DB
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use rocket_okapi::gen::OpenApiGenerator;
use rocket_sync_db_pools::{diesel, database};

#[database("sqlite_logs")]
pub struct MyDB(diesel::SqliteConnection);

impl<'r> OpenApiFromRequest<'r> for MyDB {
    fn from_request_input(
        _gen: &mut OpenApiGenerator,
        _name: String,
        _required: bool,
    ) -> rocket_okapi::Result<RequestHeaderInput> {
        Ok(RequestHeaderInput::None)
    }
}

Q: ... does not implement JsonSchema?

A: The JsonSchema implementation is handled by Schemars, make sure you enabled the right feature flags for it. If it is still not implemented open an issue in the Schemars repo.

Q: Can I add custom data to my OpenAPI spec?

A: Yes, see the Custom Schema example. Okapi also has build in functions if you want to merge the OpenAPI objects manually.

Q: Can I use this with other web frameworks then Rocket?

A: Yes, but not there are no other implementations right now. But you can use the Okapi crate independently and use Serde to create the json or yaml file.

Feature Flags

Okapi:

  • impl_json_schema: Implements JsonSchema for Schemars and Okapi types themselves.
  • preserve_order: Keep the order of struct fields in Schema and all parts of the OpenAPI documentation.

Rocket-Okapi:

Note that not all feature flags from Schemars are re-exported or enabled. So if you have objects for which the JsonSchema trait is not implemented, you might need to enable a feature flag in Schemars. For an example see the "uuid1" example. (Make sure crate versions match)

How it works

This crate automatically generates an OpenAPI file when the Rocket server starts. The way this is done is shortly described here.

The Schemars crate provides us with the schemas for all the different structures and enums. Okapi does not implement any schemas directly, this is all handled by Schemars.

The Okapi crate just contains all the structures needed to create an OpenAPI file. This crate does not contain any code for the creation of them, just the structure and code to merge two OpenAPI structured together. This crate can be reused to create OpenAPI support in other web framework.

Rocket-Okapi crate contains all the code for generating the OpenAPI file and serve it once created. This code is usually executed using macro's like: mount_endpoints_and_merged_docs!{...}, openapi_get_routes![...], openapi_get_routes_spec![...] and openapi_get_spec![...] .

When the Rocket server is started (or wherever macro is placed) the OpenAPI file is generated once. This file/structure is then stored in memory and will be served when requested.

The Rocket-Okapi-codegen crate contains code for derive macros. #[openapi], rocket_okapi::openapi_spec![...], rocket_okapi::openapi_routes![...] and #[derive(OpenApiFromRequest)] in our case. This needs to be in a separate crate because of Rust restrictions. Note: derive or codegen crates are usually a bit hard to work with then other crates. So it is recommended to get some experience with how derive macros work before you change things in here.

TODO

  • Tests
  • Documentation
  • Benchmark/optimise memory usage and allocations
  • Implement OpenApiFrom___/OpenApiResponder for more rocket/rocket-contrib types
  • Allow customizing openapi generation settings, e.g.
    • custom json schema generation settings
    • change path the document is hosted at

License

This project is licensed under the MIT license.

All contributions to this project will be similarly licensed.

Dependencies

~8.5MB
~176K SLoC