-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON Schema generated code accepts different payload to Ergo #10
Comments
For completeness, Here is the original message, prior to the message above: I have generated a JSON Schema from the HelloWorld template.... ...then used this to generate the Rust library. (Note: I used an online tool to create this rust lib https://app.quicktype.io/. In the fullness of time, I'll incorporate a Rust crate to do this.) I then wrote a simple Rust app to parse a Request response using the Rust Lib. The challenge is that, according to the Schema.json, the valid HelloWorld MyRequest object is:
whereas the one we use in TemplateStudio is:
Any ideas why the Schema.json specifies a different MyRequest payload to the one we use with current Ergo? (FYI... Full repo of this playpen app at: source code) Am I generating the code from Schema.json incorrectly? |
I think that I see the problem. The JSON Schema file that Concerto generates contains definitions but is not a helpful schema for validating on its own. To use the definitions, you need to include a For example, here's an abbreviated JSON Schema definition that matches {
"definitions": {
"org.accordproject.helloworld.MyRequest": {
"title": "MyRequest",
"description": "An instance of org.accordproject.helloworld.MyRequest",
"type": "object",
"properties": {
"$class": {
"type": "string",
"default": "org.accordproject.helloworld.MyRequest",
"pattern": "^org\\.accordproject\\.helloworld\\.MyRequest$",
"description": "The class identifier for org.accordproject.helloworld.MyRequest"
},
"input": {
"type": "string"
}
},
"required": [
"$class",
"input"
]
}
},
"$ref": "#/definitions/org.accordproject.helloworld.MyRequest"
} Then using the "JSON Schema" source type at https://app.quicktype.io/, I produce a Rust file that looks like this.... use serde::{Serialize, Deserialize};
/// An instance of org.accordproject.helloworld.MyRequest
#[derive(Serialize, Deserialize)]
pub struct MyRequest {
/// The class identifier for org.accordproject.helloworld.MyRequest
#[serde(rename = "$class")]
class: String,
input: String,
} This better matches what I would expect. My guess is that you generated Rust code using the "JSON" source type rather than "JSON Schema"? |
Thanks @mttrbrts - That did it! The "$ref" is the secret ingredient. I was using the "JSON" source type in https://app.quicktype.io/ because, without the "$ref", no code was being generated when using the "JSON Schema" source type. SO... I've expanded the "$ref" into a "properties" section with references to all the definitions. This now allows QuickType to generate Rust structs for all definitions - with the As a thought... It would be nice if we could get
|
I don't believe that the JSON Schema output should always contain an object as you describe it, because it is unlikely to validate against a JSON object directly. Alternatively, I suggest one (or both) of the following options:
Otherwise, it's not unreasonable to ask your Rust library to generate structs for all definitions, not just the root? |
@mttrbrts - I can see your point. However, I wasn't just trying to generate Rust for just a couple of specific concepts but for all concepts; and I'm not sure I like the idea of the user having to figure out which concepts that they want to validate against. My thinking was that, by default, the JSON Schema and Rust code generator should generate structs for all the object definitions, not just one or two. This is what I (manually) did above. By creating "properties" within the JSON Schema, with different "$ref" values pointing to each, individual definition then this forced QuickType to generate Rust structs for the all JSON Schema definitions. (Note: this means it is still a valid JSON Schema Definition as QuickType only accepts valid JSON Schema Defs.) In this way, the contract author doesn't have to decide which concepts that they want to validate against, as all are available in the Rust library to be used at compile time. Given it's simple to parse the JSON Schema and create the "properties" object containing all the "$ref" values then the suggestion is that we modify the JSONSchema Visitor to include these "properties". Is this unreasonable? Would having "properties" in the JSON Schema upset other use cases - even if it is still a valid JSON Schema definition? Is there another, better, more elegant way? |
My option two should satisfy what you need, for example, we could generate JSON schema such as... {
"$schema": "http://json-schema.org/draft-07/schema#",
"oneOf": [
{
"$ref": "#/definitions/org.accordproject.helloworld.MyRequest"
},
{
"$ref": "#/definitions/org.accordproject.helloworld.MyResponse"
},
...
],
"definitions": {
"org.accordproject.helloworld.MyRequest": {
"title": "MyRequest",
"description": "An instance of org.accordproject.helloworld.MyRequest",
"type": "object",
"properties": {
"$class": {
"type": "string",
"default": "org.accordproject.helloworld.MyRequest",
"pattern": "^org\\.accordproject\\.helloworld\\.MyRequest$",
"description": "The class identifier for org.accordproject.helloworld.MyRequest"
},
"input": {
"type": "string"
}
},
"required": [
"$class",
"input"
]
},
"org.accordproject.helloworld.MyResponse": {
"title": "MyRequest",
"description": "An instance of org.accordproject.helloworld.MyResponse",
"type": "object",
"properties": {
"$class": {
"type": "string",
"default": "org.accordproject.helloworld.MyResponse",
"pattern": "^org\\.accordproject\\.helloworld\\.MyResponse$",
"description": "The class identifier for org.accordproject.helloworld.MyResponse"
},
"input": {
"type": "string"
}
},
"required": [
"$class",
"input"
]
}
},
...
}
|
Hi @mttrbrts - I tried using the above and it doesn't seem to generate the Rust code correctly - at least, not with QuickType. It just generates one big struct "HelloWorld" containing a set of optional strings.
|
@mttrbrts - Of course, the other option is that we forget about generating Rust from JSON Schema and just handcraft a Visitor in Concerto and add However, I was, kinda, thinking to (lazily) use QuickType to generate the Rust from JSONSchema, instead of handcrafting Rust code gen logic from scratch. This would, obviously, introduce a dependency which, I appreciate, may not be desirable. What do you think? |
I say that if you're willing to crack open the code gen code, let's just go direct to rust. |
@mttrbrts - OK. <<< Insert cracking sound >>> |
Hi @mttrbrts
The JSON was hand-crafted by yours truly in order to match the Rust code's expectation.
This is my logic.
The
schema.json
file generated by Cicero contains the snippet for theMyRequest
object is as follows:The bit that we really only care about is the
"properties"
object above.The Rust that was generated from this snippet is;
This Rust code looks sensible to me when compared to the the JSON Schema above.
I hand-crafted the JSON Request object, based on the JSON Schema and Rust code.
When I pass in the below JSON Request object, the code works fine. :-)
When I pass the JSON object that is used by Ergo then it fails.
The only way I can get the original JSON MyRequest object to work is if I change the Rust code to be:
That is, ditch the
Class
andName
objects and use simpleString
types instead.Everything above looks fine to me. It's just that I can't see how Ergo is executing this model, unless Ergo is interpreting the Concerto CTO file differently to JSON Schema.
What am I missing?
The text was updated successfully, but these errors were encountered: