Swagger POST with json body - json

I am trying to write static .json file of server response using swagger. I'm stuck with post body and do not know how to describe it. It looks pretty much similar to Grooveshark api's where you have one page and different post parameters.
So, given grooveshark example (http://developers.grooveshark.com/docs/public_api/v3/)
Page that takes queries:
http://api.grooveshark.com/ws3.php?sig=cd3ccc949251e0ece014d620bbf306e7
POST body:
{
'method': 'addUserFavoriteSong',
'parameters': {'songID': 0},
'header': {
'wsKey': 'key',
'sessionID': 'sessionID'
}
}
How can I describe this with swagger?

without knowing a ton about how this API operates (such as, is "songID" the only parameter type?, I'm guessing you'd want something like this in your models section:
"models": {
"FavoriteSong": {
"id": "FavoriteSong",
"properties": {
"parameters": {
"type": "Parameter"
},
"header": {
"type": "Header"
}
}
},
"Parameter": {
"id": "Parameter",
"properties": {
"songID": {
"type": "integer",
"format": "int32"
}
}
}
"Header": {
"id": "Header",
"properties": {
"wsKey": {
"type": "string"
},
"sessionID": {
"type": "string"
}
}
}
}
}
And the operation would take the type "FavoriteSong" as a body type:
"parameters": [
{
"name": "body",
"description": "object to add",
"required": true,
"type": "FavoriteSong",
"paramType": "body"
}
]

Related

Specifying an object should be empty if another object has properties in JSON schema

I have data that comes back from GraphQL, I'd like to verify that data with JSON schema before manipulating it.
There might be a better way of doing this in graphQL than I currently am, but the data that comes back can be of two types with the same properties:
e.g. a simplified version of the data
obj: {
audio: {
artists: []
},
video: {}
}
or
obj: {
audio: {},
video: {
artists: []
}
}
So validity would be:
an object with both a audio and video property
an object with audio as an object with a property artists and an empty property video object
an object with video as an object with a property artists and an empty property audio object
neither audio or video should be empty together
neither audio or video should have properties together
I've built a simplified schema that looks like this:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "file://schemas/simple.schema.json",
"title": "simplified data",
"description": "simple",
"type": "object",
"properties": {
"audio": {
"type": "object"
},
"video": {
"type": "object"
}
},
"oneOf": [
{
"audio": {
"type": "object",
"properties": {
"artists": {
"type": "array"
}
}
},
"video": {
"type": "object",
"properties": {}
}
},
{
"audio": {
"type": "object",
"properties": {}
},
"video": {
"type": "object",
"properties": {
"artists": {
"type": "array"
}
}
}
}
]
}
but AJV doesn't seem to validate the data correctly when run against:
{
"audio": {
"artists": []
},
"video": {}
}
What might have I got wrong with my schema?
After an initial attempt, Jason pointed out a simpler solution...
Using oneOf, you can specify that only one of the objects may have at least one property.
You can test this here: https://jsonschema.dev/s/SSRaL
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "file://schemas/simple.schema.json",
"properties": {
"audio": {
"type": [
"object"
],
"properties": {
"artists": {
"$comment": "whatever validation you want"
}
}
},
"video": {
"type": [
"object"
],
"properties": {
"artists": {
"$comment": "whatever validation you want"
}
}
}
},
"oneOf": [
{
"properties": {
"video": {
"minProperties": 1
}
}
},
{
"properties": {
"audio": {
"minProperties": 1
}
}
}
]
}

Use conditional statements on json schema based on another schema object

I have a json object like:
{
"session": {
"session_id": "A",
"start_timestamp": 1535619633301
},
"sdk": {
"name": "android",
"version": "21"
}
}
The sdk name can either be android or ios. And the session_id is based on name field in sdk json. I have written a json schema using conditional statement (Using draft 7) as follows:
But it works in an unexpected manner:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/Base",
"definitions": {
"Base": {
"type": "object",
"additionalProperties": false,
"properties": {
"session": {
"$ref": "#/definitions/Session"
},
"sdk": {
"$ref": "#/definitions/SDK"
}
},
"title": "Base"
},
"Session": {
"type": "object",
"additionalProperties": false,
"properties": {
"start_timestamp": {
"type": "integer",
"minimum": 0
},
"session_id": {
"type": "string",
"if": {
"SDK": {
"properties": {
"name": {
"enum": "ios"
}
}
}
},
"then": {
"pattern": "A"
},
"else": {
"pattern": "B"
}
}
},
"required": [
"session_id",
"start_timestamp"
],
"title": "Session"
},
"SDK": {
"type": "object",
"additionalProperties": false,
"properties": {
"version": {
"type": "string"
},
"name": {
"type": "string",
"enum": [
"ios",
"android"
]
}
},
"required": [
"name",
"version"
],
"title": "SDK"
}
}
}
So the following JSON Passes:
{
"session": {
"session_id": "A",
"start_timestamp": 1535619633301
},
"sdk": {
"name": "ios",
"version": "21"
}
}
But this fails:
{
"session": {
"session_id": "B",
"start_timestamp": 1535619633301
},
"sdk": {
"name": "android",
"version": "21"
}
}
can someone explain y?.. Even this passes:
{
"session": {
"session_id": "A",
"start_timestamp": 1535619633301
},
"sdk": {
"name": "android",
"version": "21"
}
}
I think you're having a similar problem as in this question.
#Relequestual is right in that you need the properties keyword around your SDK callout. But for what you want to do, you need to reorganize.
Subschemas only operate on their level in the instance, not at the root.
Consider this schema for a simple JSON object instance containing a one and a two property:
{
"properties": {
"one": {
"enum": ["yes", "no", "maybe"]
},
"two": {
"if": {
"properties": {
"one": {"const": "yes"}
}
},
"then": {
... // do some assertions on the two property here
},
"else": {
...
}
}
}
}
The if keyword under the two property can only consider the portion of the instance under the two property (i.e. two's value). It's not looking at the root of the instance, so it can't see the one property at all.
To make it so that the subschema under the two property subschema can see the one property in the instance, you have to move the if outside of the properties keyword.
{
"if": {
"properties": {
"one": {"const" : "yes"}
}
},
"then": {
... // do some assertions on the two property here
},
"else": {
... // assert two here, or have another if/then/else structure to test the one property some more
}
}
For two possible values of one, this is pretty good. Even three possible values isn't bad. However, as the possible values of one increases, so does the nesting of ifs, which can make your schema horrible to read (and possibly make validation slower).
Instead of using the if/then/else construct, I suggest using an anyOf or oneOf where each subschema represents a valid state for the instance, given the varying values of one.
{
"oneOf": [
{
"properties": {
"one": {"const": "yes"},
"two": ... // do some assertions on the two property here
}
},
{
"properties": {
"one": {"const": "no"},
"two": ... // do some assertions on the two property here
}
},
{
"properties": {
"one": {"const": "maybe"},
"two": ... // do some assertions on the two property here
}
}
]
}
This is much cleaner in my opinion.
Hopefully that explanation helps you reconstruct your schema to allow those other instances to pass.
You have to move your conditional to a high enough level to be able to reference all of the the properties it needs to reference. In this case, that's the /definitions/Base schema. Then you just need to write your schemas properly as Relequestual explained.
{
"$ref": "#/definitions/Base",
"definitions": {
"Base": {
"type": "object",
"properties": {
"session": { "$ref": "#/definitions/Session" },
"sdk": { "$ref": "#/definitions/SDK" }
},
"allOf": [
{
"if": {
"properties": {
"sdk": {
"properties": {
"name": { "const": "ios" }
}
}
},
"required": ["sdk"]
},
"then": {
"properties": {
"session": {
"properties": {
"session_id": { "pattern": "A" }
}
}
}
},
"else": {
"properties": {
"session": {
"properties": {
"session_id": { "pattern": "B" }
}
}
}
}
}
]
},
...
}
The value of if must be a JSON Schema. If you were to take lines https://gist.github.com/Relequestual/f225c34f6becba09a2bcaa66205f47f3#file-schema-json-L29-L35 (29-35) and use that as a JSON Schema by itself, you would impose no validation constraints, because there are no JSON Schema key words at the top level of the object.
{
"SDK": {
"properties": {
"name": {
"enum": "ios"
}
}
}
}
This is allowed in the specification, because people may want to extend the functionality of JSON Schema by adding their own key words. So it's "valid" JSON Schema, but doesn't actually DO anything.
You Need to add properties to the schema for it to make sense.
{
"properties": {
"SDK": {
"properties": {
"name": {
"const": "ios"
}
}
}
}
}
Additionally, enum must be an array. When you only have a single item, you may use const.

Why does the "schema" disappear from the "responses" object when importing an OpenAPI definition?

I can successfully import the following OpenAPI definition into Azure API Management.
However, when I export the OpenAPI definition, the "schema" name has been removed from the "responses" object. As a result, developers in my portal are not shown a schema or example for this operation.
My API definition is valid and functions correctly if added to the official editor.
How can I prevent the schema from being stripped out?
{
"swagger": "2.0",
"info": {
"title": "Foo",
"description": "Foo",
"version": "1"
},
"host": "example.org",
"schemes": [
"https"
],
"paths": {
"/foo": {
"get": {
"summary": "List all foo.",
"responses": {
"200": {
"description": "Success.",
"schema": {
"$ref": "#/definitions/Foo"
}
}
}
}
}
},
"definitions": {
"Foo": {
"type": "object",
"properties": {
"example": {
"type": "string",
"description": "An example."
}
}
}
}
}
This problem seems to occur when the definition lacks a "produces" name, in either the root object, or in the operation object.
For example, the following definition should import successfully, and then export without the "schema" being stripped away. Note that the "produces" name has been added to the root object, in between "schemes" and "paths"
{
"swagger": "2.0",
"info": {
"title": "Foo",
"description": "Foo",
"version": "1"
},
"host": "example.org",
"schemes": [
"https"
],
"produces": ["application/json"]
"paths": {
"/foo": {
"get": {
"summary": "List all foo.",
"responses": {
"200": {
"description": "Success.",
"schema": {
"$ref": "#/definitions/Foo"
}
}
}
}
}
},
"definitions": {
"Foo": {
"type": "object",
"properties": {
"example": {
"type": "string",
"description": "An example."
}
}
}
}
}

Json schema limit number of the same object

Is there a way, to create a json schema, that limits the number a object can occur?
Or make sure, that a object is unique?
In the end, i want something like
{
"days": {
"monday": {
"schedule": {
"start_time": "23:35"
}
},
"tuesday": {
"schedule": {
"start_time": "23:23"
}
}
}
}
In this json, each day should only occur once. Like one start time per day.
So far, i tried it with the following schema but not successful at all.
With this schema, i can have multiple "monday" objects in my json and the schema is still valid. But what i'm looking for, is a schema that is not valid for more than one object.
{
"$schema": "http://json-schema.org/schema#",
"title": "DayScheduler",
"type": "object",
"required": [
"days"
],
"properties": {
"days": {
"monday": {
"$ref": "#/definitions/scheduler"
},
"tuesday": {
"$ref": "#/definitions/scheduler"
},
"wednesday": {
"$ref": "#/definitions/scheduler"
},
"thursday": {
"$ref": "#/definitions/scheduler"
},
"friday": {
"$ref": "#/definitions/scheduler"
},
"saturday": {
"$ref": "#/definitions/scheduler"
},
"sunday": {
"$ref": "#/definitions/scheduler"
}
}
},
"definitions": {
"scheduler": {
"type": "object",
"required": [
"schedule"
],
"properties": {
"schedule": {
"type": "object",
"required": [
"start_time"
],
"properties": {
"start_time": {
"type": "string",
"pattern": "^([01]?[0-9]|2[0-3]):[0-5][0-9]"
}
}
}
}
}
}
}
Is there a way to achieve this with a json-schema?
Duplicate keys are not allowed in JSON. JSON Schema is designed to validate JSON data. It's not equipped to validate data that is not valid JSON.
This example helps illustrate why this is not valid.
var value = {
"foo": 1,
"foo": 2
}
If you evaluate this as a JavaScript object and try to access the foo property of this object: value.foo === ???, is it 1 or 2? It's ambiguous.
My experience in JSON has lead me to understand that if you have multiple objects with the same key, the value of the last one will be taken for the key.
You could try adding
{
"name": name,
type: object,
properties: {
a:b,
c:d
},
"additionalProperties": false
}
to your schema, but I still think the last occurrence of each key will be taken as the value.

swagger-ui how to form multiple responses in schema array

I am trying to form a swagger document in this format. The response is the below json on 200 http code. I am unable to form a json like below.
[
{
"key":"test1",
"val":"val1"
},
{
"key":"test2",
"val":"val2"
},
{
"key":"test3",
"val":"val3"
}
]
so far I have this:
"responses": {
"200": {
"description": "response",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/res1",
"$ref": "#/definitions/res2"
}
}
}
}
"definitions": {
"res1": {
"type": "object",
"properties": {
"key": {
"type": "string",
"example": "test1"
},
"keyURL": {
"type": "string",
"example": "val1"
}
}
},
"res2": {
"type": "object",
"properties": {
"key": {
"type": "string",
"example": "test2"
},
"val": {
"type": "string",
"example": "val2"
}
}
}
But I dont see the res2 block at all. I just see res1
JSON pointers ($ref) must live "alone" in an object. Thus you cannot have multiple pointers in your items block:
"$ref": "#/definitions/res1",
"$ref": "#/definitions/res2"
will ignore the 2nd reference (res2) and only apply the first.
For what you're trying to do, you have many options. Probably the easiest is something like this:
type: array
items:
$ref: '#/definitions/Pair'
and having definitions like such:
definitions:
Pair:
properties:
key:
type: string
value:
type: string