utoipa icon indicating copy to clipboard operation
utoipa copied to clipboard

Export OpenAPI spec at build time

Open peteole opened this issue 1 year ago • 3 comments

Hi,

is there a simple way to export the generated OpenAPI spec to a file at compile time instead of serving it at runtime? This would fit my use case much better:)

And pretty cool crate btw!

peteole avatar Jul 09 '22 17:07 peteole

Hello,

Thanks, :)

There is no build in way to handle this but implementing something like this per user basis is not a big of a deal. I don't think build in implementaiton for this would be practical or at least I am not sure how it could be implemented so that the behaviour would be generic across the users. But of course ideas and PRs are always welcome. :)

I would implement it roughly something like this to get this behaviour.

# in Cargo.toml add custom bin target to generate the spec from the types
[[bin]]
name = "gen-openapi"
path = "./src/gen_openapi.rs"

Then in the in the Rust code something like this. Or perhaps you can call the code in your main app to generate the OpenAPI doc. and then write it to the file. You could easily share code between your app and binary which would generate the write the code to a file.

// in ./src/gen_openapi.rs
fn main() {
    let doc = gen_my_openapi();
    fs::write("./path/to/file", doc);
}

// in /src/openapi.rs 
fn gen_my_openapi() -> String {
  #[derive(Deserialize, ToSchema)]
  struct Person {
      /// Id of person
      id: i64,
      /// Name of person
      name: String,
  }

  #[derive(OpenApi)]
  #[openapi(schemas(components(Person)))]
  struct ApiDoc;

  ApiDoc::openapi().to_pretty_json().unwrap()
}

Then you can call the code from your terminal session with.

 cargo run --bin gen-openapi

While this is en extra step. But I concur it is better to have it as manual step than automatically write to the file when values for macros are changed. And if that was the approach then the runtime modifiers could not be used. This step could also be used together with cargo watch if necessary and needed with automatic document updates.

Aternatively if it is seen better that the API doc is dumped to a file everytime you build your application one could leverage usage of build.rs. The similar generation and file writing could be done within the build.rs file what is executed everytime the application is built.

juhaku avatar Jul 09 '22 18:07 juhaku

Thanks, this solved my issue! I am a bit new to rust so it will take a while and not be perfect from the beginning, but would you mind me creating a pull request for documenting this once I get it done? I am currently going one step further and generate clients from the OpenAPI-Spec in the build step: https://github.com/peteole/notifier/blob/master/src/generate_openapi.rs Once this works properly I could also add this as a "bonus recipe".

peteole avatar Jul 10 '22 18:07 peteole

Great, not at all. Just need to find a right place for this thing. Perhaps it could be in a form of an example in examples folder. And then add a link to the Go beyond the surface section.

juhaku avatar Jul 10 '22 18:07 juhaku

Added note about this in the REAMDE.md

juhaku avatar Feb 15 '23 23:02 juhaku

Aternatively if it is seen better that the API doc is dumped to a file everytime you build your application one could leverage usage of build.rs. The similar generation and file writing could be done within the build.rs file what is executed everytime the application is built.

I wish that would work. I have all the macro annotations inside the application code. Now funny things happen if I want to execute cargo run --bin gen-openapi inside build.rs: gen-openapi depends on the application code too, so it first has to build the application, which runs build.rs again, and you end up with infinite recursion. And Cargo doesn't provide a way to not run the build script for gen-openapi, which would have been an acceptable workaround.

Since the OpenAPI spec only actually exists at runtime, I unfortunately don't think it would be possible to export it at build time, without some major changes to the fundamental way this crate works. That's an important distinction.

pkb-pmj avatar Aug 19 '23 15:08 pkb-pmj