Skip to content

Treat "+json" structured-syntax-suffix media types as JSON - #1415

Open
fpcousins wants to merge 1 commit into
oxidecomputer:mainfrom
fpcousins:fc/json-structured-syntax-suffix
Open

Treat "+json" structured-syntax-suffix media types as JSON#1415
fpcousins wants to merge 1 commit into
oxidecomputer:mainfrom
fpcousins:fc/json-structured-syntax-suffix

Conversation

@fpcousins

Copy link
Copy Markdown

Firstly, thank you for progenitor! It's doing great work for us.

Would you consider accepting +json structured-syntax-suffix media types? I appreciate Dropshot never emits them, but they're standardised (RFC 6839 §3.1) and our in-house specs use application/problem+json for errors which means that our generated clients get untyped errors, so this would be a lovely addition! Happy to rework the implementation if you'd prefer a different shape.

Currently progenitor only recognises application/json exactly, so:

  • a response declared as application/problem+json (RFC 9457) generates Error<ByteStream> instead of a typed error;
  • a request body declared with a +json type is rejected with UnexpectedFormat.

This change classifies any +json media type as JSON for both request bodies and responses. Only the exact application/json or a +json suffix qualifies, text/json and friends are deliberately still rejected.

Request bodies keep the declared media type: BodyContentType::Json now carries it (as Text(String) does), and for a +json type the generated call sets Content-Type before .json(&body). reqwest's json() only adds application/json when no Content-Type is already present, so the declared type is what's sent, and because it's still .json() serialization errors are deferred as before. This matters where the media type itself carries semantics (e.g. application/merge-patch+json vs application/json-patch+json on the same JSON body) and other generators (oapi-codegen, hey-api) do the same. Plain application/json bodies generate exactly as before so no existing fixture changes.

One new fixture: sample_openapi/json-suffix.json: one operation with a +json request, a +json 2XX response and a problem+json default error, in the style of param-collision.json. It generates (positional variant):

pub async fn annotate_thing<'a>(&'a self, id: &'a str, body: &'a types::Annotation)
    -> Result<ResponseValue<types::Thing>, Error<types::Problem>>

sending Content-Type: application/vnd.example.annotation+json.

Not touched: the request Accept header and the httpmock success/created helpers still hard-code application/json for a +json response. Left alone as this is pre-existing behaviour.

Related: #1239 (open, no review yet) takes the same approach for responses only, without a fixture. This PR also covers request bodies and adds output tests, so I'd suggest it supersedes #1239 but I can rebase onto it if preferred.

Classify any "+json" media type as JSON for both request bodies and
responses. Requests send the media type the spec declares rather than
application/json. Adds a json-suffix.json sample spec covering a "+json"
request, a "+json" 2XX response, and a problem+json default error.

RFC 6839 §3.1: https://www.rfc-editor.org/rfc/rfc6839#section-3.1
@fpcousins
fpcousins marked this pull request as ready for review August 27, 2026 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant