Questions about XML in Swagger 2.0 - api

I'm working with APIs that could return XML as well as JSON, and was looking into if there's any way to represent XML schemas in Swagger and looks like there is none.
I had 2 follow up questions:
If one of my XML returning API's posts an XML sample in the 'example' object, that's still fine, right?
The schemas object has a XML Object. I read the description but I'm not sure what cases can this be used for? Could anyone please give an example? It'd be really helpful if you could.
I just want to make sure I'm not leaving out anything that I could have used to make my API metadata more descriptive.
Thanks guys.

When it comes to APIs returning both XMLs and JSON, Swagger assumes that they share a common structure that's basically interchangeable.
That is, if you have this JSON:
{
"key1": "value1",
"key2": "value2"
}
The XML would look like:
<object>
<key1>value1</key1>
<key2>value2</key2>
</object>
As you can see, there are still slight differences. The XML needs an encompassing element, which does not exist in JSON. This is where the XML Object in the Swagger Spec comes in as it allows you to add this additional information. It also allows you to define a field as an attribute, declare the namespace used and allow better control for arrays of values, which have several variants in XML as opposed to JSON.
While we don't have a wide array of samples for the XML Object, you can find one here - https://github.com/swagger-api/swagger-spec/blob/master/fixtures/v2.0/json/models/modelWithXmlAttributes.json. I need to add some more details to it in the spec, hopefully in the upcoming few weeks.
As for the example field - its value is a free-form JSON object. What you can do is something like this:
{
"xml" : "<object>.....</object>"
}

See swagger results below.
{
"in": "body",
"name": "xmlbody",
"description": "example of swagger with xml",
"required": true,
"schema": {
"$ref": "#/definitions/myOuter"
}
}
definitions:{
"myOuter":{
"type":"object",
"xml":{
"name":"House"
},
"properties":{
"class":{
"type":"string",
"enum":[
"singleFamily"
],
"xml":{
"attribute":true,
"prefix":"home"
}
},
"masterRoom":{
"type":"object",
"properties":{
"bed":{
"type":"string",
"xml":{
"prefix":"master"
}
},
"size":{
"type":"string",
"enum":[
"XL"
],
"xml":{
"attribute":true
}
},
"color":{
"type":"string",
"enum":[
"brown"
],
"xml":{
"attribute":true,
"name":"COLOR",
"prefix":"paint"
}
},
"window":{
"type":"string",
"enum":[
"slide"
],
"xml":{
"attribute":true,
"name":"open",
"prefix":"view",
"namespace":"http://doesntShowUpDueToENUM.com"
}
}
}
}
}
}
}
<?xml version="1.0"?>
<House home:class="singleFamily">
<masterRoom size="XL" paint:COLOR="brown" view:open="slide">
<master:bed>string</master:bed>
</masterRoom>
</House>

Related

AJV - How to validate relative references

I have a json that is used as ref in another json in the same folder:
jsonBase.json
{
"type": "number",
"title": "Your salary",
"presentation": {
"inputType": "money"
}
}
jsonFinal.json
{
"$ref": "jsonBase.json",
"presentation": {
"currency": "EUR"
}
}
When using AJV validate, the schema is invalid (it's missing the required properties), ignoring the base.json.
I checked this github issue and read the docs but I still don't understand exactly what change I need to make in order for the json to be valid.
Here's the codesandbox with demo.
You can only use $ref in a schema to reference a schema. It doesn't work in JSON instances.

Understanding JSON Schema errors using ajv

I have the following schema and json to validate using ajv.
const schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [ "countries" ],
"definitions": {
"europeDef": {
"type": "object",
"required": ["type"],
"properties": { "type": {"const": "europe"} }
},
"asiaDef": {
"type": "object",
"required": ["type"],
"properties": { "type": {"const": "asia"} }
}
},
"properties": {
"countries": {
"type": "array",
"items": {
"oneOf":[
{ "$ref": "#/definitions/europeDef" },
{ "$ref": "#/definitions/asiaDef"}
]
}
}
}
}
const data = {
"countries":[
{"type": "asia"},
{"type": "europe1"}
]
}
const isValid = ajv.validate(schema, data); //schema, data
if(! isValid){
console.log(ajv.errors);
}
and the error is:
[
{
keyword: 'const',
dataPath: '/countries/1/type',
schemaPath: '#/definitions/europeDef/properties/type/const',
params: { allowedValue: 'europe' },
message: 'should be equal to constant'
},
{
keyword: 'const',
dataPath: '/countries/1/type',
schemaPath: '#/definitions/asiaDef/properties/type/const',
params: { allowedValue: 'asia' },
message: 'should be equal to constant'
},
{
keyword: 'oneOf',
dataPath: '/countries/1',
schemaPath: '#/properties/countries/items/oneOf',
params: { passingSchemas: null },
message: 'should match exactly one schema in oneOf'
}
]
I know why the error is appearing (reason: as I have used 'europe1' and it is not conforming the schema standard)
I have following questions from the above error situation:
Being, I have provided 'asia' as a valid const, the error stills talks about 'asia' as part of second entry in the array. Why did it showing as an error despite schema is absolute fine from asia perspective. Is this because 'oneOf' getting used ? In other words, it is very hard to understand, what and where is the error and what is not?
For asia, 'message: 'should be equal to constant' (2nd item of the array) is misleading imo. It gives an impression that there are still some problems with the 'asia'.
How to parse this error: on the basis of schemaPath or dataPath? Also in any case, it will still give an impression that there is a problem in terms of 'asia' (and actually its not)
Also, how to explain the above error output to a novice, as the novice will still say, why asia is coming part of error despite its correct?
Also, if the schema become more complex using oneOf/anyOf,allOf or using if-then-else, the ajv.errors output becomes more complex to understand and to explain (when certain condition are accurate but displayed as error, example asia here)
Are there any theory/documentaion/guidelines to understand the errors in a better way?
For JSON Schema draft 2019-09, we created several standardised output formats. ajv provides one of the most useful outputs from a draft-07 schema in comparison to many libraries.
When looking at the errors, what you might be overlooking is the dataPath value.
In answer to 1, the errors reported are all when applying to data path /countries/1. /countries/0 is fine, as you say. Arrays in javascript start at 0.
I think knowing that also answers all your other questions.
I think you may have assumed that arrays start at 1, and the data path was referring to asia object while it's actually targeting europe1 object.
Please do comment if I'm missing something or you're still confused on this.

JSON Schema Array Validation Woes Using oneOf

Hope I might find some help with this validation issue: I have a JSON array that can have multiple object types (video, image). Within that array, the objects have a rel field value. The case I'm working on is that there can only be one object with "rel": "primaryMedia" allowed — either a video or an image.
Here are the object representations for the image and video case, both showing the "rel": "primaryMedia".
{
"media": [
{
"caption": "Caption goes here",
"id": "ncim87659842",
"rel": "primaryMedia",
"type": "image"
},
{
"description": "Shaima Swileh arrived in San Francisco after fighting for 17 months to get a waiver from the U.S. government to be allowed into the country to visit her son.",
"headline": "Yemeni mother arrives in U.S. to be with dying 2-year-old son",
"id": "mmvo1402810947621",
"rel": "primaryMedia",
"type": "video"
}
]
}
Here's a stripped-down version of the schema I created to validate this using oneOf (assuming this will handle my case). It doesn't however, work as intended.
{
"$id": "http://example.com/schema/rockcms/article.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {},
"properties": {
"media": {
"items": {
"oneOf": [
{
"additionalProperties": false,
"properties": {
"caption": {
"type": "string"
},
"id": {
"type": "string"
},
"rel": {
"enum": [
"primaryMedia"
],
"type": "string"
},
"type": {
"enum": [
"image"
],
"type": "string"
}
},
"required": [
"caption",
"id",
"rel",
"type"
],
"type": "object"
},
{
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"headline": {
"type": "string"
},
"id": {
"type": "string"
},
"rel": {
"enum": [
"primaryMedia"
],
"type": "string"
},
"type": {
"enum": [
"video"
],
"type": "string"
}
},
"required": [
"description",
"headline",
"id",
"rel",
"type"
],
"type": "object"
}
]
},
"type": "array"
}
}
}
Using the JSON Schema validator at https://www.jsonschemavalidator.net, the schema validates when data is correctly presented, but the doesn't work when trying to catch errors.
In the case below, headline is added for a video, and it's missing id. This should fail because headline isn't allowed on video, and id is required.
{
"media": [
{
"headline": "Yemeni mother arrives in U.S. to be with dying 2-year-old son",
"rel": "primaryMedia",
"type": "video"
}
]
}
The results I get from the validator, however, aren't entirely expected. Seems it's conflating the two object schemas in its response.
In addition to this, I've separately found that the schema will allow the population of BOTH a video and image object in media, which isn't expected.
Been trying to figure out what I've done wrong, but am stumped. Would very much appreciate some feedback, if anyone has to offer. Thanks in advance!
Validator Response:
Message: JSON is valid against no schemas from 'oneOf'.
Schema path: #/properties/media/items/oneOf
Message: Property 'headline' has not been defined and the schema does not allow additional properties.
Schema path: #/properties/media/items/oneOf/0/additionalProperties
Message: Value "video" is not defined in enum.
Schema path: #/properties/media/items/oneOf/0/properties/type/enum
Message: Required properties are missing from object: description, id.
Schema path: #/properties/media/items/oneOf/1/required
Message: Required properties are missing from object: caption, id.
Schema path: #/properties/media/items/oneOf/0/required
Your question is formed of three parts, but the first two are linked, so I'll address those, although they don't have a "solution" as such.
How can I validate that only one object in an array has a specific key, and the others do not.
You cannot do this with JSON Schema.
The set of JSON Schema keywords which are applicable to arrays do not have a means for expressing "one of the values must match a schema", but rather are applicable to either ALL of the items in a the array, or A SPECIFIC item in the array (if items is an array as opposed to an object).
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4
The validation output is not what I expect. I expect to only see the failing branch of oneOf which relates to my object type, which
is defined by the type key.
The JSON Schema specification (as of draft-7) does not specify any format for returning errors, however the error structure you get is pretty "complete" in terms of what it's telling you (and is similar to how we are specifying errors should be returned for draft-8).
Consider, the validator knows nothing about your schema or your JSON instance in terms of your business logic.
When validating a JSON instance, a validator may step through all values, and test validation rules against all applicable subschemas. Looking at your errors, both of the schemas in oneOf are applicable to all items in your array, and so all are tested for validation. If one does not satisfy the condition, the others will be tested also. The validator cannot know, when using a oneOf, what your intent was.
You MAY be able to get around this issue, by using an if / then combination. If your if schema is simply a const of the type, and your then schema is the full object type, you may get a cleaner error response, but I haven't tested this theory.
I want ALL items in the array to be one of the types. What's going on here?
From the spec...
items:
If "items" is a schema, validation succeeds if all elements in the
array successfully validate against that schema.
oneOf:
An instance validates successfully against this keyword if it
validates successfully against exactly one schema defined by this
keyword's value.
What you have done is say: Each item in the array should be valid according to [schemaA]. SchemA: The object should be valid according to on of these schemas: [the schemas inside the oneOf].
I can see how this is confusing when you think "items must be one of the following", but items applies the value schema to each of the items in the array independantly.
To make it do what you mean, move the oneOf above items, and then refactor one of the media types to another items schema.
Here's a sudo schema.
oneOf: [items: properties: type: const: image], [items: properties: type: image]
Let me know if any of this isn't clear or you have any follow up questions.

Validating correctness of $ref in json schema

The requirement is to validate given json schema that there are no dangling $ref pointing to the definitions within the file.
{
"$schema": "http://json-schema.org/draft-6/schema#",
"definitions": {
"date": {
"type": "string",
"pattern": "^(0?[1-9]|[12][0-9]|3[01])\\-(0?[1-9]|1[012])\\-\\d{4}$"
},
},
"properties": {
"my_date": {"$ref": "#/definitions/dat"}
}
}
Here, there is a typo in the reference (dat instead of date). I want to catch such instances rather than having a run time failure.
Library being used: https://github.com/java-json-tools/json-schema-validator
You could validate that the use of $ref resolves by digesting the JSON, recursivly extracting the value of $ref, splitting on slash, and checking the path exists.
This COULD get more complicated as you might have external references which target URLs.
I can't give you any code as I don't know JAVA. It doesn't seem like what you want is specifically available using that library.

API Pagination Standards

I have been working on an API and pagination is required. Only 25 elements will be returned in each request. I was looking around for standards and I seem to see 2 different things going on.
The Link Header
Link: https://www.rfc-editor.org/rfc/rfc5988
Example:
Link: <https://api.github.com/user/repos?page=3&per_page=100>; rel="next",
<https://api.github.com/user/repos?page=50&per_page=100>; rel="last"
In the JSON response
Link: API pagination best practices
Example:
"paging": {
"previous": "http://api.example.com/foo?since=TIMESTAMP"
"next": "http://api.example.com/foo?since=TIMESTAMP2"
}
Question:
Should I do both? and that being said; is the key "paging" the correct key? or "links" or "pagination"
I would say it depends on the structure of data you return (and may return in the future).
If you never have nested objects that need their own links, then using the Link header is (mildly) preferable, because it's more correct. The issue with nested objects is that you can't nest Link headers.
Consider the following collection entity:
{
"links": {
"collection": "/cards?offset=0&limit=25"
},
"data": [
{
"cardName": "Island of Wak-Wak",
"type": "Land",
"links": {
"set": "/cards?set=Arabian Knights"
}
},
{
"cardName": "Mana Drain",
"type": "Interrupt",
"links": {
"set": "/cards?set=Legends"
}
}
]
}
There's no good way to include links for the cards in the headers.