GREsau/okapi

Question: Accessing `State` in `OpenApiFromRequest` Similar to `FromRequest`

NewtTheWolf opened this issue · 4 comments

Hello rocket_okapi team,

I'm currently working on the zitadel-rust project and generating OpenAPI documentation using the OpenApiFromRequest trait. You can find the relevant PR here: smartive/zitadel-rust#559.

In this project, I need to configure the SecurityScheme for OpenID Connect, and the authority URL for this configuration is stored in Rocket's State.

In a typical request guard implementation using FromRequest, I can access the request object and retrieve the configuration from State like this:

#[async_trait]
impl<'request> FromRequest<'request> for &'request IntrospectedUser {
    type Error = &'request IntrospectionGuardError;

    async fn from_request(request: &'request Request<'_>) -> Outcome<Self, Self::Error> {
        // Accessing the authorization header
        let auth: Vec<_> = request.headers().get("authorization").collect();
        if auth.len() > 1 {
            return Outcome::Error((Status::BadRequest, &IntrospectionGuardError::InvalidHeader));
        } else if auth is_empty() {
            return Outcome::Error((Status::Unauthorized, &IntrospectionGuardError::Unauthorized));
        }

        let token = auth[0];
        if !token.starts_with("Bearer ") {
            return Outcome::Error((Status::Unauthorized, &IntrospectionGuardError::WrongScheme));
        }

        // Accessing the configuration from State
        let config = request.rocket().state::<IntrospectionConfig>();
        if config is_none() {
            return Outcome::Error((Status::InternalServerError, &IntrospectionGuardError::MissingConfig));
        }

        // Further processing...
    }
}

However, when working within the OpenApiFromRequest trait, I haven't found a way to similarly access the request object or State to retrieve the configuration data. Currently, I'm using figment to extract the configuration, like this:

let config: IntrospectionRocketConfig = figment
    .extract()
    .expect("authority must be set in Rocket.toml");

But I would prefer to directly access the State via the request, similar to how it's done in FromRequest, to keep consistency and avoid duplicating configuration extraction logic.

My Question:

Is it possible to access the request object within OpenApiFromRequest, or is there another recommended way to retrieve the State while generating OpenAPI documentation with rocket_okapi?

Thank you for your assistance!

Hey, sorry for the late reply. But the request object is never available in rocket_okapi or OpenApiFromRequest
This is because the openapi.json file is generated at the time the macro is called. So it has no knowledge of anything happening at runtime. So it does not relay on/or see any request.
For some info: https://github.com/GREsau/okapi?tab=readme-ov-file#how-it-works

I see your MR got merged. So if this issue is no longer needed, you can close it.

Hey @ralpha thx for your response

yes the PR got merged, but the issue is still here
so everything happens in the Compile Time what also makes sense

So the way to go would be to use the Rocket Config file or something simmilar that can be accesed via the Compile time if i am right?

You can do something during run time too, but although a bunch is done during compile time.
The moment the macro is called openapi_get_routes![] or similar you can some things.

But what exactly do you want to do? You want to change the OpenApi file depending on the Rocket.toml file?
You can always just intercept the spec and then link it yourself.
For example here.

let custom_route_spec = (vec![], custom_openapi_spec());

But you can even replace the mount_endpoints_and_merged_docs! to get even more control.
let openapi_docs = match rocket_okapi::okapi::merge::marge_spec_list(&openapi_list){

Line 164-168 creates all endpoint links.
Line 170-173 merges everything into 1 spec.
Line 175-182 mount so the openapi.json file is added to Rocket.

So if you want change any of that you can just create your own macro.

But if you describe your problem a bit more, I might be able to point you to exactly to what you can do.

Also does the https://github.com/GREsau/okapi/tree/master/examples/secure_request_guard example not describe what you want to do?