RAML: Nested Schemas - raml

1) When writing RAML, can I use nesting in my schema definition?
For example:
schemas:
- DNSResponse: |
{
"type": "object",
"properties": {
"AnswerSection": {
"type": "array",
"items": (((I want a re-useable schema here. ex: ARecord)))
},
"AA": {"type": "boolean"},
"AD": {"type": "boolean"},
...
}
}
- ARecord: |
{
"type": "object",
"properties": {
"address": "string",
"ttl": "number",
"name": "string"
}
}
2) Can I use a choices/enum around a set of nestable schemas?
"items": [ARecord, MXRecord, PTRRecord, ...]

1) Yes, you can. See this example. That would be:
"items": { "$ref": "ARecord" }
2) I believe this is possible in Draft 4 of JSON Schema, using the oneOf directive. I don't think this is supported by RAML though. Alternatively, you could create a base schema and have ARecord, MXRecord and PTRRecord extend this base schema and then allow items of the base schema. This won't be very semantically rich but could get you started.

Since your question is not 100% requiring JSON, I will add this in the answers...
With the release of the RAML 1.0 specifications, you can use types, which allows you to do just that (in what I consider slightly cleaner).
Here is the reference link : http://docs.raml.org/specs/1.0/#raml-10-spec-types
RAML 1.0 introduces the notion of data types, which provide a concise and powerful way to describe the data in your API. The data can be in a URI parameter (base or resource URI), a query parameter, a request or response header, or of course a request or response body. Some types are built in, while custom types may be defined by extending (inheriting from) the built-in types. In any place where the API expects data, a built-in type may be used to describe the data, or a type may be extended inline to describe that data. CustomSecurityScheme types may also be named and then used like any built-in type.
And for those that want less text and more examples (taken from RAML documentation) :
#%RAML 1.0
title: API with Types
types:
User:
type: object
properties:
firstname: string
lastname: string
age: number
/users/{id}:
get:
responses:
200:
body:
application/json:
type: User

I think the following example applies here. It demonstrates defining two types Url and File (using RAML 1.0) and then using the logical OR to allow either type (aka schema) in Item as a subschema. You could potentially include more types if needed.
I also defined some examples inline which demonstrate how it works if you are using the raml-parser.
#%RAML 1.0
types:
Url:
properties:
url:
type: string
example: http://www.cats.com/kittens.jpg
description: |
The url to ingest.
File:
properties:
filename:
type: string
example: kittens.jpg
description: |
Name of the file that will be uploaded.
Item:
description: |
An example of a allowing multiple types using RAML 1.0
properties:
ext:
type: File | Url
examples:
file_example:
content:
ext:
filename: video.mp4
url_example:
content:
ext:
url: http://heres.a.url.com/asset.jpg
should_fail:
content:
ext:
unexpected: blah

Related

How to validate with yml file a karate structure response [duplicate]

This question already has an answer here:
Karate - Nested JSON object schema validation causes KarateException
(1 answer)
Closed 1 year ago.
recently I started working with Karate and Yaml for the first time. I was able to validate simple response structures where all the answer data were on the same level. But now I have to validate a more complicated structure and I spent a lot of time without success.
When I perform a GET request I receive the next answer:
[
{
"factories": [
{
"id": 1,
"scopes": [
{
"id": null,
"name": "name 1",
"expireD": 10,
"isExpired": true
}
],
"companyName": "TEST",
},
{
"id": 2,
"scopes": [
{
"id": null,
"name": "name 2",
"expireD": 7,
"isExpired": true
}
],
"companyName": "TEST2",
}
],
"scopeId": null
}
]
The structure validation is not directly in the karate code. It is on a yml file like this:
operationId: getTest
statusCode: 200
params:
body: null
matchResponse: true
responseMatches:
scopeId: '##number'
factories:
companyName: '#string'
id: '#number'
scopes:
expireD: '#number'
name: '#string'
id: '#null'
isExpired: '#boolean'
I review the structure around 100 times and I have the same error all the time when I arrive here:
* match response contains responseMatches
The error is the next one:
$[1].factories | data types don't match (LIST:MAP)
I tried to use match each, ignore one by one the structures to see which one is failing and also reduce the validations as #array and it is not working.
Any help will be more than welcome. Thank you.
I really recommend NOT using YAML especially in a testing / validation scenario. But finally it is your call.
Here is a tip to save you some time, you can print out the value of the YAML and see where you were going wrong. I don't know YAML (and avoid it as far as possible), but I made a guess after a few failed attempts and managed to insert a - at the right place (apparently there are many other ways) to make some of the YAML a JSON array - which is what you want.
* text foo =
"""
operationId: getTest
statusCode: 200
params:
body: null
matchResponse: true
responseMatches:
scopeId: '##number'
factories:
-
companyName: '#string'
id: '#number'
scopes:
expireD: '#number'
name: '#string'
id: '#null'
isExpired: '#boolean'
"""
* yaml foo = foo
* print foo
Try the above and see how it differs from your example.
Finally, a solution was found. The Karate documentation offers an idea about how to use it defining a structure of data that could be used as a type. I tried before but I added before the responseMatches section. The yml file looks like this:
operationId: getTest
statusCode: 200
params:
body: null
matchResponse: true
responseMatches:
scopeId: '##number'
factories: '#[_ <= 5] factoryStructure'
factoryStructure:
companyName: '#string'
id: '#number'
scopes: '#[] scopeStructure'
scopesStructure:
expireD: '#number'
name: '#string'
id: '#null'
isExpired: '#boolean'

Spring boot code generated from swaggerhub is not able to throw 400 on additional properties

I've logged in to swaggerhub and generated a sample inventory API which is part of their template.
In codegen options selected spring as server. ticked on useBeanValidation checkbox. Generated the code, tested it. Validations are working properly as expected except only one thing. I don't want to allow any additional property on the POST payload.
NB: The openAPI specification doesn't have 'additionalProperties' flag specified. Which defaults it to 'false' in my understanding. I tried to explicitly specify the same too. but no luck. There is no exception thrown while I add an additionalProperty.
The OpenAPI specification
openapi: 3.0.0
servers:
# Added by API Auto Mocking Plugin
- description: SwaggerHub API Auto Mocking
url: https://virtserver.swaggerhub.com/xxxx/apionopenApi3/1.0.0
info:
description: This is a simple API
version: "1.0.0"
title: Simple Inventory API
contact:
email: you#your-company.com
license:
name: Apache 2.0
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: admins
description: Secured Admin-only calls
- name: developers
description: Operations available to regular developers
paths:
/inventory:
get:
tags:
- developers
summary: searches inventory
operationId: searchInventory
description: |
By passing in the appropriate options, you can search for
available inventory in the system
parameters:
- in: query
name: searchString
description: pass an optional search string for looking up inventory
required: false
schema:
type: string
- in: query
name: skip
description: number of records to skip for pagination
schema:
type: integer
format: int32
minimum: 0
- in: query
name: limit
description: maximum number of records to return
schema:
type: integer
format: int32
minimum: 0
maximum: 50
responses:
'200':
description: search results matching criteria
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/InventoryItem'
'400':
description: bad input parameter
post:
tags:
- admins
summary: adds an inventory item
operationId: addInventory
description: Adds an item to the system
responses:
'201':
description: item created
'400':
description: 'invalid input, object invalid'
'409':
description: an existing item already exists
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/InventoryItem'
description: Inventory item to add
components:
schemas:
InventoryItem:
type: object
additionalProperties: False
required:
- id
- name
- manufacturer
- releaseDate
properties:
id:
type: string
format: uuid
example: d290f1ee-6c54-4b01-90e6-d701748f0851
name:
type: string
example: Widget Adapter
releaseDate:
type: string
format: date-time
example: '2016-08-29T09:12:33.001Z'
manufacturer:
$ref: '#/components/schemas/Manufacturer'
Manufacturer:
required:
- name
properties:
name:
type: string
example: ACME Corporation
homePage:
type: string
format: url
example: 'https://www.acme-corp.com'
phone:
type: string
example: 408-867-5309
type: object
additionalProperties: False
Got 400 for this payload on post API.
{
"id": "7f125802-7840-4ff0-8ddb-7c78c0948987",
"name11111": "Widget Adapter",
"releaseDate": "2016-08-29T09:12:33.001Z",
"manufacturer": {
"name": "ACME Corporation",
"homePage": "",
"phone": "408-867-5309"
}
}
Expected 400 but didn't get on this payload on post
{
"id": "7f125802-7840-4ff0-8ddb-7c78c0948983",
"name": "Widget Adapter",
"releaseDate": "2016-08-29T09:12:33.001Z",
"manufacturer": {
"name": "ACME Corporation",
"homePage": "",
"phone": "408-867-5309"
},
"newkey" : "newValue"
}
Can anybody pls help on this.. I want to completely disallow additional properties and throw a 400 on those requests..
The default for additionalProperties is actually True, not False.
Adding false does not cause the swagger-codegen for Spring to actually disallow additional fields though, annoyingly enough. After a few hours of running in the wrong direction I found the solution:
In application.properties
spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES=true
I had been having the same trouble and have tried to leverage filters but have had problems tying the models that are used in the automatic deserialization of #RequestBody to the servlet request and keeping the behavior consistent across model changes. Coming to that conclusion required writing quite a bit of unnecessary boilerplate and wasting a lot of time.
I also tried to find a way to inject some behavior in the automatic use of the model or any model annotation that would change how the model automatically disregards additional fields without reporting the bad request. After exhausting the road of annotations I found the solution.

How to validate JSON payload against OpenApi specification from Ruby?

I have HTTP request payload structured according to jsonapi.org guidelines:
{
"data": {
"type": "employee",
"attributes": {
"firstName": "John",
"lastName": "Doe",
}
}
}
then I have OpenApi specification (yaml) of this payload:
employee:
type: object
required: [data]
properties:
data:
type: object
properties:
type:
type: string
enum: [employee]
attributes:
type: object
required: [firstName, lastName]
properties:
firstName:
type: string
example: 'John'
lastName:
type: string
example: 'Doe'
and what I want is to validate the payload against the specification (from Ruby/Rails).
there exist openapi3_parser gem, but that one seems to be capable only to validate the specification, not the actual payload.
then, there are jsonapi.org payload deserializers, but those do not seem to take care about OpenApi formal specification at all.
I use OpenApi to describe the payload becuase I get http API docs for free via Swagger.
it can be achieved by using json-schema, e.g.:
errors = JSON::Validator.fully_validate(schema, payload)
(it is working for me with json-schema gem 2.8.1, schema itself is written in openapi v 2.0)
This gem https://github.com/interagent/committee validates requests/responses based off of an open api spec you provide.

what does "content" : mean in swagger/openapi "responses":

Using Swagger/OpenAPI (and subsequently swagger-codegen) I haven't been able to find what the difference should be between
This, taken direclty from https://swagger.io/specification/#responsesObject
(first example, json format)
"responses" : {
"200": {
"description": "a pet to be returned",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pet"
} } } } }
and
"responses" : {
"200": {
"description": "a pet to be returned",
"schema": {
"$ref": "#/components/schemas/Pet"
} } }
I've put this example into a trivial json swagger spec (json) and run the Swagger-Codegen (python, flask) to generate my controllers and model. Yaml seems to be the preferred internal representation, so when the generator runs it creates a yaml file.
With the former, the response type is "None"
responses:
200:
description: "a pet to be returned"
whereas the latter yields what I think I should be expecting:
responses:
200:
description: "a pet to be returned"
schema:
$ref: "#/components/schemas/Pet"
eg, the schema seems to be omitted from the first syntax using Content
What does content mean?
What am i missing from the example, why doesn't the Content result in a non-None return type and corresponding schema.
Note on the SwaggerCodgen: the generated code matches exactly what the generated yaml says, hence I haven't included any of those details here
The first example is OpenAPI 3.0, the second example is OpenAPI 2.0, hence the difference.
The content keyword used in OpenAPI 3.0 is a replacement for consumes/produces from OpenAPI 2.0. In the context of responses, content means that the response has a body and specifies the media type (JSON/XML/etc.) and structure of the response body.
OpenAPI 2.0 version:
swagger: "2.0"
...
paths:
/foo:
get:
produces:
- application/json
responses:
200:
description: OK
schema:
$ref: "#/definitions/Pet"
OpenAPI 3.0 version:
openapi: 3.0.0
...
paths:
/foo:
get:
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
The codegen issue is likely caused by any of the fololowing:
codegen does not support OpenAPI 3.0 yet
the spec is not valid (e.g. uses a mix of 2.0 and 3.0 keywords)

Putting arrays inside of objects using Swagger 2.0 and YAML

I am currently learning how to document using Swagger because my company is evaluating using it as a standard way of documenting for upcoming projects.
I read online that using YAML is easier to read than using JSON, and since YAML is a subset of JSON I figured it would be alright.
I'm working on the response for the 200 code, I would like to represent something similar to the following structure:
responses:
200:
description: OK.
schema:
title: response
type: object
items:
properties:
title: user
type: array
items:
id:
type: string
name:
type: string
status:
type: integer
Basically I return an object called "response" that contains two variables: An array called "user" that contains several strings (I included just two for the sake of clarity) and another variable (outside of the "user" array) called "status" that contains an integer.
The above code doesn't work, and the editor notifies me that it isn't a "valid response definition".
I'm not sure how to tackle this. I'd appreciate some help on what I'm doing wrong.
Basically I return an object called "response" that contains two variables: An array called "user" that contains several strings (I included just two for the sake of clarity) and another variable (outside of the "user" array) called "status" that contains an integer.
Based on your description, the response is supposed to be as follows (assuming the response is JSON). Basically, you have an object with a nested object:
{
"user": {
"id": "12345",
"name": "Alice"
},
"status": 0
}
This response can be defined as follows:
responses:
200:
description: OK.
schema:
title: response
type: object
required: [user, status]
properties:
user:
type: object
required: [id, name]
properties:
id:
type: string
name:
type: string
status:
type: integer
For convenience, complex schemas with nested objects can be broken down into individual object schemas. Schemas can be written in the global definitions section and referenced from other places via $ref. This way, for example, you can reuse the same schema in multiple operations/responses.
responses:
200:
description: OK.
schema:
$ref: "#/definitions/ResponseModel"
definitions:
ResponseModel:
title: response
type: object
properties:
user:
$ref: "#/definitions/User"
status:
type: integer
required:
- user
- status
User:
type: object
properties:
id:
type: string
name:
type: string
required:
- id
- name

Resources