thread 'main' (478016) panicked at build.rs:16:46:
failed to parse: tmp/ojf.json: Error("invalid type: sequence, expected a string", line: 1191, column: 8)
That's serde_json trying to parse the OnlyJunk.Fans OpenAPI json (pretty printed with jq).
Line 1191 is:
},
The entire thing is perfectly valid JSON. It's big, though, but... that shouldn't be much of an issue. Right? Right?
@algernon Did you make a mistake when generating the json? What does other json parsers think of it?
@loke The JSON is valid. jq likes it, so does pretty much everything else I threw at it.
If I rearrange the JSON to have the problematic part elsewhere, it consistently fails at the same place: wherever I moved these parts.
If I remove everything under {"components": {"schemas": {}}}, then serde_json has no trouble with the rest.
Now to figure out which part of the schemas trigger the problem.
Leaving the first schema there: parses.
Leaving the second: fails to parse.
Reproducer:
{
"components": {
"schemas": {
"SomeType": {
"properties": {
"email": {
"type": []
}
}
}
}
}
}
If I change "type": [] to say, "x-type": [], then it parses. If I remove a level, it parses.
θΔ ⋐ & ∞
@algernon i would suggest it being about the rust keyword type but it can’t possibly be that
If I change the keys to a, b, c, d, e respectively, and leave type as-is, it parses.
If I just change components to component, it parses.
What the flying fuck is serde_json doing.
@tauon It's not. The same key appears elsewhere and is fine. It's also fine if I change any of the other keys.
Oh. Fun. It is not serde_json's fault. It tries to deserialize into a type provided by progenitor, and that fails.
It can deserialize fine into serde_json::Value.
It's not even progenitor's fault, either.
let spec: openapiv3::OpenAPI =
serde_json::from_str(&reproducer)
.unwrap();
This blows up too.
Which kind of makes sense, because the generated json is for OpenAPI 3.1.0, while the openapiv3 crate only supports 3.0.0. There's a draft pull request adding 3.1.0 support open since 2022.
So, uhh. This isn't going to be fixed anytime soon I guess.
So: can I talk utoipa into generating 3.0 instead of 3.1, I wonder?
@buherator Yeah, it turned out to be a 3.0 vs 3.1 incompatibility, and underlying crates only supporting 3.0, while my spec is 3.1.
There are 3.1 -> 3.0 downgrade tools, though.
Nice. Getting somewhere. Now I need to fix the spec. :)
Nice. Spec fixed. But progenitor doesn't support multipart/form-data yet. That may take a while. But some progress was made towards an API client, so that's something!
I could use another language for the API client, one where a suitable generator (preferably from OpenAPI 3.1) is available. But... I don't want to, and I don't care enough. I'll revisit this around OnlyJunk.Fans 1.0 or something.
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
use reqwest::header;
#[tokio::main]
async fn main() {
let token = std::env::var("OJF_DEMO_TOKEN").expect("$OJF_DEMO_TOKEN not set");
let auth_header = format!("Bearer {token}");
let mut headers = header::HeaderMap::new();
headers.insert(
header::AUTHORIZATION,
auth_header.parse().expect("Authorization header value failed to parse"),
);
let client = reqwest::ClientBuilder::new()
.default_headers(headers)
.build()
.expect("failed to build reqwest client");
let client = Client::new_with_client("http://127.0.0.1:8084", client);
let resp = client.account_view().send().await.unwrap();
println!("{resp:#?}");
}
=>
❯ cargo run -q
AccountResponse {
email: "demo@onlyjunk.fans",
}
Not bad. Due to multipart/form-data being unsupported, this won't be able to cover the entire API, but it can cover a large enough area. This will help me build some small tooling to help with admin tasks in the near future, replacing a handful of shell scripts that drive curl in various ways.