NJson Schema additional property without Attribute - properties

I'm using NJsonSchema to create json shema from my backend to API UI.
I would like to add some customer properies to each properies of backend classıs. I know there is an attribute ([JsonSchemaExtensionData("description", "FirstName")]) whicj is working as expected. But I don't wanna do this for every single POCO classes and attributes.
What I want to do is showen in the below.For this example I wanna add "description": "FirstName" to every properties of my classes.
"$schema": "http://json-schema.org/draft-04/schema#", "title": "Person", "type": "object", "additionalProperties": false, "properties": {
"FirstName": {
"type": [
"null",
"string"
],
"description": "FirstName"
},
And I have seen an another (custom shema processor) solution which is looks like better way. But I don'y know how to implement .
Unfortunately unable to find fully working code sample.
public class MySchemaProcessor : ISchemaProcessor
{
public void Process(SchemaProcessorContext context)
{
// Don't know what to do here ??
}
}

Related

Using $vars within json schema $ref is undefined

While following the documentation for using variables in json schema I noticed the following example fails. It looks like the number-type doesn't get stored as a variable and cannot be read.
{
"$id": "http://example.com/number#",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["natural", "integer"]
},
"value": {
"$ref": "#/definitions/{+number-type}",
"$vars": {
"number-type": {"$ref": "1/type"}
}
}
},
"required": ["type", "value"],
"definitions": {
"natural": {
"type": "integer",
"minimum": 0
},
"integer": {
"type": "integer"
}
}
}
results in
Could not find a definition for #/definitions/{+number-type}
tl;dr $vars is not a JSON Schema keyword. It is an implementation specific extension.
The documentation you link to is not JSON Schema. It is documentation for a specific library which adds a preprocessing step to its JSON Schema processing model.
As such, this would only ever work when using that library, and would not create an interoperable or reuseable JSON Schema, if that's a consideration.
If you are using that library specifically, it sounds like a bug, and you should file an Issue in the appropriate repo. As you haven't provided any code, I can't tell what implementation you are using, so I can't be sure on that.

Are there more examples of readOnly being used at several levels of a schema to clarify the semantics?

I've been using the readOnly keyword in my schemas and I just realized that I was just making up my own semantics. Now I'm cleaning up a bunch of my designs and trying to validate that I was using this annotation as it was intended. The validation spec is what I'm basing this question on but I'd like to be aware of more example usage scenarios.
Let me give three examples. In this first example I mean to say the entire resource is read only. Nothing can be mutated at any level.
{
"type": "object",
"readOnly": true,
"properties": {
"name": {
"type": "string",
},
"members": {
"type": "object",
"properties": {
"member1": { "type" : "string" },
"member2": { "type" : "string" }
}
}
}
}
I don't think that's too controversial. But originally, my own mental model was that readOnly at the top level meant you couldn't replace this resource with a new resource. The server would prevent that. But the internal members were still mutable. So I sprinkled readOnly at the name sub-schema and each member sub-schema. I think removing all of those was correct. (My mental model was maybe loosely based on how I interpret const variables in JavaScript. If my const var is an object, I can't change the value of the variable, but I can mutate its members or even add members to it.)
In the second example I leave readOnly out of the schema completely. So it's not too controversial to take that to mean anything is mutable in the resource.
{
"type": "object",
"properties": {
"name": {
"type": "string",
},
"members": {
"type": "object",
"properties": {
"member1": { "type" : "string" },
"member2": { "type" : "string" }
}
}
}
}
In the third example, I want to mix and match
{
"type": "object",
"properties": {
"name": {
"type": "string",
"readOnly": true
},
"members": {
"type": "object",
"properties": {
"member1": { "type" : "string", "readOnly": true },
"member2": { "type" : "string", "readOnly": true },
"member3": { "type" : "string"},
"member4": { "type" : "string"}
}
}
}
}
In this example the name, member1 and member2 are immutable. member3 and member4 can be modified.
So the question is, is there anything wrong about my interpretation of readOnly?
The spec, as you linked defines the following for readOnly...
If "readOnly" has a value of boolean true, it indicates that the value
of the instance is managed exclusively by the owning authority, and
attempts by an application to modify the value of this property are
expected to be ignored or rejected by that owning authority.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-02#section-9.4
If you take the JSON defined meaning of value, it's the bit to the right of the key followed by colon. Therefore I would read this as any part of the value.
The OpenAPI specification only really defines readOnly as being applicable to individual properties.

How do you extend json schema meta schema to support new properties?

I want to allow a $role properties anywhere in a json schema document where type is allowed. In theory I should be able to extend it as below where I do allOf against both the json schema meta-schema and my extension for $role which includes additionalProperties to pick up my extension meta-schema recursively. What I find is that I get validation for a top-level $role, but not for any embedded one. Am I missing something? Is there some other way I should extend the JSON Schema meta-schema?
I've tried a bunch of different validators and they all fail at validating the second $role in the example.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"role": {
"type": "string",
"pattern": "^((lg)|(unionType\\([a-zA-Z][a-zA-Z0-9.]*\\)))$"
},
},
"allOf": [
{
"$ref": "http://json-schema.org/draft-07/schema#"
},
{
"properties": {
"additionalProperties": {
"$ref": "#"
},
"$role": {
"oneOf": [
{
"$ref": "#/definitions/role"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/role"
}
}
]
}
}
}
]
}
Example using this schema:
{
"$schema": "schema.json",
"title": "Prompt",
"$role": "unionType(Microsoft.IPrompt)",
"properties": {
"prompt": {
"type": "string",
"$role":"foo"
}
}
}
What I expect is that the second role should be invalid according to the schema. What I get is that it is valid even though it does not match the $role pattern. The first $role does validate successfully.
Yep, extending a meta schema is more complicated than it seems. Checkout the the JSON Hyper-Schema meta schema for an example of how to extend a meta schema. JSON Hyper-Schema adds two keywords: base and `links. When extending a schema, you need to redefine any recursive reference used in the original schema.
JSON Schemas (including meta-schemas) are immutable. You can't selectively modify an existing schema. Your meta schema only validates the $role keyword, all other keywords are validated by the draft-07 meta schema. Because your meta schema doesn't modify the draft-07 schema, keywords like properties are validated entirely within the context of the draft-07 schema and without knowledge of the new keyword you added in another schema.
It's unfortunate that so much duplication is involved in extending schemas and it is a problem that is being worked on. A potential solution to make this easier is slated to be introduced in the next draft.

Differences between api and model swagger

I'm new with swagger and I'm defining an API.
Can I define an api with swagger without needing to use the #ApiModelProperty annotation? What exactly is an object model in swagger?
Yes , you can define an API without using the #ApiModelProperty. Models object is not a required field in the OpenAPI Spec.
The Models Object holds a field per model definition, and this is different than the structure of the other objects in the spec. It follows a subset of the JSON-Schema specification.
#ApiModelProperty defines the properties of that object. Also Model Object is a part of the response in Swagger
Example you have a model - User class.
class User {
int id;
String name;
int age;
}
Model Object will contain information about User.
{
"User": {
"id": "User",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
}
}
}
#ApiModelProperty is used in the Java class User to produce this JSON by defining id, name and age inside it.

reusing an object for multiple JSON schemas

I have two separate JSON schemas (used to validate HTTP request endpoints for a REST API) where they both accept the same exact object, but have different required fields (this is a create vs update request). Is there a way I can reuse a single definition of this object and only change the required fields? I know how to use $ref for reusing an object as a property of another object, but I cannot figure out how to reuse an entire object as the top-level object in a schema. My failed attempt so far:
event.json
{
"id": "event",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"start_date": {
"type": "integer"
},
"end_date": {
"type": "integer"
},
"description": {
"type": "string"
}
},
"additionalProperties": false
}
event-create.json
{
"id": "event-create",
"type": "object",
"$ref": "event",
"additionalProperties": false,
"required": [ "name", "description" ]
}
Obviously that doesn't work. It seems like it tries to insert the entirety of 'event' into the definition of 'event-create', including the ID and such. I tried referincing event#/properties to no avail. I can't seem to do a $ref as the sole value inside a properties property either. Any ideas?
Any members other than "$ref" in a JSON Reference object SHALL be ignored.
- https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03#section-3
This is why your example doesn't work. Anything other than the $ref field is supposed to be ignored.
Support for $ref is limited to fields whose type is a JSON Schema. That is why trying to use it for properties doesn't work. properties is a plain object whose values are JSON Schemas.
The best way to do this is with allOf. In this case allOf can sort-of be thought of as a list of mixin schemas.
{
"id": "event-create",
"type": "object",
"allOf": [{ "$ref": "event" }],
"required": ["name", "description"]
}
I found some syntax that seems to work, but I'm not terribly happy with it:
{
"id": "event-create",
"allOf": [
{ "$ref": "event" },
{ "required": [ "name", "description" ] }
]
}
Seems like an abuse of the allOf operator, particularly for another case where there are no required fields (thus only one element insid the allof). But it works, so I'm going with it unless someone has a better idea.