aide icon indicating copy to clipboard operation
aide copied to clipboard

Return `StatusCode` instead of `u16` for inferred responses

Open patrickariel opened this issue 10 months ago • 6 comments

Inferred responses now uses an explicit StatusCode, allowing you to specify ranged status codes. This is typically useful for app-wide error types:

#[derive(Deserialize, JsonSchema)]
struct AppError {
    message: String,
}

impl OperationOutput for AppError {
    type Inner = ();

    fn operation_response(ctx: &mut GenContext, _operation: &mut Operation) -> Option<Response> {
        ...
    }

    fn inferred_responses(
        ctx: &mut GenContext,
        operation: &mut Operation,
    ) -> Vec<(Option<StatusCode>, Response)> {
        if let Some(res) = Self::operation_response(ctx, operation) {
            vec![(Some(StatusCode::Range(4)), res)] // <-- ranged status codes!
        } else {
            Vec::new()
        }
    }
}

You can then use the type in your routes:

async fn greet(Json(name): Json<String>) -> Result<String, AppError> { // <-- neat return type
    Ok(format!("hello {name}!"))
}

Which aide will then automatically infer:

"4XX": { // <-- correct inference
  "description": "",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/AppError"
      }
    }
  }
}

patrickariel avatar Mar 03 '25 20:03 patrickariel

Looks good. It's a breaking change thus requires a version bump

JakkuSakura avatar Mar 04 '25 01:03 JakkuSakura

Should I bump the version in this PR?

patrickariel avatar Mar 04 '25 10:03 patrickariel

We don't know if anyone relies on this outside aide. I don't see a reason why this couldn't be an another method alongside the current one so that it is not an immediate breaking change and we can have some deprecation period.

tamasfe avatar Mar 04 '25 11:03 tamasfe

I feel like that would unnecessarily bloat the new method names (e.g. inferred_responses_typed). Also, making a new method for an incremental improvement doesn't feel quite right to me.

But if a breaking change is really not a choice here, I could do that.

patrickariel avatar Mar 04 '25 14:03 patrickariel

Frequent major releases can be rather annoying for downstream maintainers, it also causes people to depend on various incompatible versions of the library at the same time. We cannot just bump a major version with every single breaking change.

Since we don't have a release schedule I don't know when the release of the next major version should be, which could be just tomorrow or months away.

This is a feature that does not have to be a breaking change, we can release a version anytime supporting it and then do a cleanup before one of the next major releases whenever they happen.

tamasfe avatar Mar 04 '25 18:03 tamasfe

Alright makes sense. So you're saying that a new temporary method should be introduced, which can then be merged into the older one on the next breaking major release, right?

I was just concerned of permanently introducing legacy cruft (foo_beta_last_final_final_for_real_this_time), when a breaking change would be cleaner 🙂

patrickariel avatar Mar 04 '25 20:03 patrickariel

Hey. Next release is going to be a breaking one anyways due to schemars version having been bumped. Can you rebase this PR (don't bump the aide version)?

jplatte avatar Jul 16 '25 09:07 jplatte

I rebased it myself.

jplatte avatar Oct 23 '25 21:10 jplatte