OpenApi required property in nested objects not working - json

I need to describe an api having in request body an object with required fields and one of these fields it's an object itself having another set of required fields.
I'm using open api v3 and swagger editor (https://editor.swagger.io/)
After i put my .yaml file onto the editor I generate an html client (> generate client > html). Then I open the static page index.html generated in the .zip file obtaning this schema:
Table of Contents
body
secureoauthservicesv2Nested_nestedobj
body
id
Integer id of nested obj
nestedobj
secureoauthservicesv2Nested_nestedobj
secureoauthservicesv2Nested_nestedobj
nested object
field1 (optional)
String
field2 (optional)
String
I expect field1 to be required and field2 to be optional but it's not.
This is my .yaml file
openapi: 3.0.0
info:
title: Example API
description: Example API specification
version: 0.0.1
servers:
- url: https://example/api
paths:
/secure/oauth/services/v2/Nested:
post:
summary: Try nested
description: Used to post Nested obj
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
- nestedobj
properties:
id:
type: integer
description: id of nested obj
nestedobj:
type: object
required:
- field1
description: nested object
properties:
field1:
type: string
field2:
type: string
responses:
'200':
description: Nested object OK

Solved!
I used components and schemas, but I think this could be a bug, opened an issue on swagger editor repo:
https://github.com/swagger-api/swagger-editor/issues/1952
openapi: 3.0.0
info:
title: Example API
description: Example API specification
version: 0.0.2
servers:
- url: https://example/api
paths:
/secure/oauth/services/v2/Nested:
post:
summary: Try nested
description: Used to post Nested obj
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
- nestedobj
properties:
id:
type: integer
description: id of nested obj
nestedobj:
$ref: '#/components/schemas/nestedobj'
responses:
'200':
description: Nested object OK
components:
schemas:
element:
type: object
required:
- fieldArray1
properties:
fieldArray1:
type: string
description: field array
fieldArray2:
type: number
nestedobj:
type: object
required:
- field1
description: nested object
properties:
field1:
$ref: '#/components/schemas/woah'
field2:
type: string
woah:
type: object
required:
- woahthis
description: woah this
properties:
field3:
type: array
items:
$ref: '#/components/schemas/element'
woahthis:
type: number
description: numeber woah this
EDIT 23/08/21:
I opened a bug in swagger-codegen github in april 2019 but it still has no response whatsoever

Related

Is the Ansible Inventory compatible with OpenAPI standards?

I´m trying to specify the API used by ansibles dynamic inventory.
Does anyone have experience with solving the incompatibility?
For a single host it might work as following:
The Ansible json output will be like this:
{
"ansible_host": "172.16.19.123",
"proxy": "somehost.domain.fake"
}
The openapi.yml
paths:
/api/inventory/host/:
get:
summary: Gets One Ansible Host
parameters:
- in: query
name: hostname
schema:
type: string
required: true
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/SingleHost'
components:
schemas:
SingleHost: # A Single Host for ansible-inventory --host [hostname] requests
type: object
properties:
ansible_host:
type: string
description: IP-Address of the host
ansible_port:
type: integer
description: ssh-port number of host
But when specifiyng the endpoint for ansible-inventory --list it gets tricky already..
example of a ansible inventory yml
{
"HostGroupName-A": {
"hosts": [
"Host-A"
]
},
"HostGroupName-B": {
"hosts": [
"Host-A",
"Host-B"
]
}
}
Should I just avoid using openapi to specify this?

AWS CloudFormation - using !Ref inside !Sub

I'm writing AWS CloudFormation template (using yaml) which creates AWS Service Catalog Product.
I'm getting the template for the product using parameter S3FilePath which has a value like the above path: https://bucket.s3-eu-west-1.amazonaws.com/template.yml.
The URL to the file needs to be send in a JSON format as shown here (this example works):
Resources:
Type: AWS::ServiceCatalog::CloudFormationProduct
Properties:
Description: Example Product
Distributor: xyz
Name: ExampleProduct
Owner: xyz
ProvisioningArtifactParameters:
- Description: Example Product
Info: { "LoadTemplateFromURL": "https://bucket.s3-eu-west-1.amazonaws.com/template.yml" }
Name: Version1
I tried to replace the URL using !Sub and !Ref as shown below:
Parameters:
S3FilePath:
Type: String
Description: file name
Resources:
Type: AWS::ServiceCatalog::CloudFormationProduct
Properties:
Description: Example Product
Distributor: xyz
Name: ExampleProduct
Owner: xyz
ProvisioningArtifactParameters:
- Description: Example Product
Info: !Sub
- '{ "LoadTemplateFromURL": "${FILEPATH}" }'
- {FILEPATH: !Ref S3FilePath}
Name: Version1
But the CloudFormation stack fails with the error: "invalid input".
I guess I am building the JSON in a wrong way, I tried to use \ before each ' " ' but it didn't help either and I couldn't find an example which explain how to build this correctly. There is no problem with the S3FilePath parameter.
Can you please advice how to use the !Sub and !Ref correctly to build the JSON? Thanks.
Here is an example: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html#w2ab1c25c28c59c11
Despite the documentation saying the Info parameter is JSON, the example shows just a name/value pair (Map): https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-servicecatalog-cloudformationproduct-provisioningartifactproperties.html
Try formatting your string as
Info: !Sub
- "LoadTemplateFromURL": "${FILEPATH}"
- {FILEPATH: !Ref S3FilePath}
You can reference any Parameters or LogicalResourceId directly inside a !Sub like so:
ProvisioningArtifactParameters:
- Description: Example Product
Info: !Sub '{ "LoadTemplateFromURL": "${S3FilePath}" }'
Name: Version1
This should work totally fine. The way you were doing substitutions is useful when you want to use conditions and/or mapping inside a !Sub.
I think it should be simply:
ProvisioningArtifactParameters:
- Description: Example Product
Info:
LoadTemplateFromURL: !Ref S3FilePath
Name: Version1
This is at least what I have in my own AWS::ServiceCatalog::CloudFormationProduct templates.
ProvisioningArtifactParameters:
- DisableTemplateValidation: false
Info:
LoadTemplateFromURL: !Ref S3FilePath

'Templating' on Swagger API Description with yaml

Is it possible to use templating w/ swagger.
How is it done.
I do not want to repeat the three properties time, len and off each time.
Have a look at the end of this post where I made up a 'template' for explanation.
More Detail:
I have a JSON response structure which always returns a JSON always with the same properties but only the content of data is subject to change.
data could be an array, could be a string, a number, null or an object.
That depends on the Api's function handling.
{
time: "2019-02-01T12:12:324",
off: 13,
len: 14,
data: [
"Last item in the row of 14 items :-)"
]
}
See at the end of this post for my example of the Swagger definition.
It is a yaml which can be pasted into the swagger editor at https://editor.swagger.io/
In the swagger documentation (yaml) I do not want to repeat the statically reoccuring items, which will not change in their functionality for any other request.
Let me know, if the question is not precisely enough to understand.
swagger: "2.0"
info:
description: ""
version: 1.0.0
title: "Templating?"
contact:
email: "someone#somewhere.com"
host: localhost
basePath: /api
paths:
/items:
get:
summary: "list of items"
produces:
- application/json
responses:
200:
description: "successful operation"
schema:
$ref: "#/definitions/Items"
/item/{id}:
get:
summary: "specific item"
produces:
- application/json
parameters:
- name: id
in: path
description: "ID of the demanded item"
required: true
responses:
200:
description: "successful operation"
schema:
$ref: "#/definitions/Item"
definitions:
Items:
type: object
description: ""
properties:
time:
type: string
format: date-time
description: "date-time of the request"
off:
type: integer
description: "index 0 based offset of list data"
default: 0
len:
type: integer
description: "overall amount of items returned"
default: -1
data:
type: array
items:
$ref: "#/definitions/ListingItem"
Item:
type: object
description: ""
properties:
time:
type: string
format: date-time
description: "date-time of the request"
off:
type: integer
description: "index 0 based offset of list data"
default: 0
len:
type: integer
description: "overall amount of items returned"
default: -1
data:
$ref: "#/definitions/InfoItem"
ListingItem:
type: integer
description: "ID of the referenced item"
InfoItem:
type: object
properties:
id:
type: string
text:
type: string
Based on #Anthon's answer it came to my mind that this is somewhat the construct I would need. Actually it is inheriting from a 'template':
...
templates:
AbstractBasicResponse:
properties:
time:
type: string
format: date-time
description: "date-time of the request"
off:
type: integer
description: "index 0 based offset of list data"
default: 0
len:
type: integer
description: "overall amount of items returned"
default: -1
definitions:
Items:
type: object
extends: AbstractBasicResponse
properties:
data:
type: array
items:
$ref: "#/definitions/ListingItem"
Item:
type: object
extends: AbstractBasicResponse
properties:
data:
$ref: "#/definitions/InfoItem"
ListingItem:
type: integer
description: "ID of the referenced item"
InfoItem:
type: object
properties:
id:
type: string
text:
type: string
...
You might not have to revert to full templating, there are two things within YAML that help with "undoubling" recurring data: anchors/aliases and merge keys.
An example of an anchor (introduced by &) referenced by an alias (*) would be:
definitions:
Items:
type: object
description: ""
properties:
time:
type: string
format: date-time
description: "date-time of the request"
off: &index
type: integer
description: "index 0 based offset of list data"
default: 0
len: &amount
type: integer
description: "overall amount of items returned"
default: -1
data:
type: array
items:
$ref: "#/definitions/ListingItem"
Item:
type: object
description: ""
properties:
time:
type: string
format: date-time
description: "date-time of the request"
off: *index
len: *amount
data:
A YAML parser needs to be able to handle this, but since the alias points to the same object after loading, the code using the data might no longer work the same because of side effect in some cases depending on how the loaded data is processed.
You can have multiple aliases referring to the same anchor.
The merge key (<<) is a special key in a mapping with which you can pre-load that mapping where it occurs with a bunch of key-value pairs. This is most effective when used with a anchor/alias. With that you you some finer control and you could do:
len: &altlen
type: integer
description: "overall amount of items returned"
default: -1
and then
len:
<<: &altlen
default: 42
Which would then be the same doing:
len:
type: integer
description: "overall amount of items returned"
default: 42
Merge keys are normally resolved at load time by the YAML parser, so there are no potential side-effects when using those even though they involve anchors and aliases.

Swagger POST Json Body Parameter Schema YAML

i'm working on a RESTful API using swagger-api and swagger-editor for routes.
I can't figure out why the JSON i am sending through body, never reaches my controller.
here is my YAML
schemes:
- http
- https
produces: [application/json, multipart/form-data, application/x-www-form-urlencoded]
paths:
/projects:
x-swagger-router-controller: project
post:
description: create a new project
operationId: postProjects
consumes:
- application/json
parameters:
- name: param1
in: body
description: description
required: false
schema:
$ref: "#/definitions/Project"
responses:
"200":
description: Success
schema:
$ref: "#/definitions/Project"
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
definitions:
Project:
properties:
name:
type: string
required:
- name
an example of the post request i'm sending.
curl -v -X POST -H "Content-Type: application/json" -d '{"name":"test"}' http://127.0.0.1:10010/projects
and the response
{"message":"Request validation failed: Parameter (param1) failed schema validation","code":"SCHEMA_VALIDATION_FAILED","failedValidation":true,"results":{"errors":[{"code":"OBJECT_MISSING_REQUIRED_PROPERTY","message":"Missing required property: name","path":[]}],"warnings":[]},"path":["paths","/projects","post","parameters","0"],"paramName":"param1"}
If i set the parameter "name" as not required, i just received an empty response like this
{ param1:
{ path: [ 'paths', '/projects', 'post', 'parameters', '0' ],
schema:
{ name: 'param1',
in: 'body',
description: 'description',
required: false,
schema: [Object] },
originalValue: {},
value: {} } }
I have no clue why since other format such as header, path or formdata works fine.
I always receive an empty object. req.swagger.params has no value.
I tried several schema but even the simplest is not working.
i can tell from the header that 'content-type': 'application/json'.
So the content type is set, the schema validates a simple string argument named "name". Everything should be ok. but still not.
This issue has been fixed.
It wasn't swagger related.
I built an API with nodeJs and i realized i didn't have a middleware to handle body parameter.
So because i missed a step before enabled the swagger middleware, i couldn't do anything with body parameter.
The main reason behind getting null values when sending json data to the API backend is the paramater path most of the time you give and the naming you give the parameter.
You also have to declare explicitly the type of schema you expect
You have to set parameter name to body and set in: body so that it picks the body object as a JSON
An example is here. You can try it out
/auth/register:
post:
tags:
- Auth
parameters:
- in: body
name: user
description: Create a new user.
schema:
type: object
required:
- firstName
- lastName
- email
- password
- confirmPassword
properties:
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
confirmPassword:
type: string
example:
firstName: Jane
lastName: Doe
email: janedoe#gmail.com
password: pass
confirmPassword: pass
responses:
"200":
description: OK

Convert Json reponse in swagger with description

I try to specify the response from GET method with Swagger Editor.
But when I look in Swagger UI, the response JSON doesn't show.
My declaration swagger :
/clients/{id}:
get:
consumes:
- application/hal+json
produces:
- application/hal+json
# This is array of GET operation parameters:
parameters:
# An example parameter that is in query and is required
- name: id
in: path
required: true
type: string
# Expected responses for this operation:
responses:
# Response code
200:
description: Succes
# A schema describing your response object.
# Use JSON Schema format
schema:
example:
application/json: |
- {"produits":[{"idOffre":{"codeBanque":"038","identifiant":"123"},"idProduit":{"codeBanque":"061","identifiant":"123"}},{"idOffre":{"code":"038","identifiant":"123"},"idProduit":{"code":"061","identifiant":"123"}}]}
.....
In Swagger UI , the box where is written Response Class (Status 200) > Model Schema there is an empty json like that -> {}
I'm not sure swagger-ui supports examples, however I fixed some errors in you swagger extract:
example renamed examples
examples at same indentation level as schema (in you example, example is processed as a property of the response schema, I'm not sure this is what you want)
schema must describe response model, complete TODO
Fixed version:
swagger: '2.0'
info:
title: Clients
description: API
version: "1.0.0"
host: api.test.com
schemes:
- https
basePath: /v1
produces:
- application/json
paths:
/clients/{id}:
get:
consumes:
- application/hal+json
produces:
- application/hal+json
parameters:
- name: id
in: path
required: true
type: string
responses:
200:
description: Succes
schema:
type: array
items:
properties:
produits:
type: string
description: TODO
examples:
application/json: |
- {"produits":[{"idOffre":{"codeBanque":"038","identifiant":"123"},"idProduit":{"codeBanque":"061","identifiant":"123"}},{"idOffre":{"code":"038","identifiant":"123"},"idProduit":{"code":"061","identifiant":"123"}}]}