Can I get openapi3 referenced schema properties with vertx 4.0.0? - vert.x

I can get the openapi3 operation model as described in the documentation,
but I would like to get the referenced schema properties.
for example I have the "post-example" operation in my yaml:
/post-example:
post:
summary: Example for all the possible 200 query responses
operationId: post-example
tags:
- read
requestBody:
required: true
content:
"application/json":
schema:
$ref: "#/components/schemas/example-query"
responses:
200:
description: Expected response to a valid request
and I would like to get the "example-query" schema properties.
Is this possible with vertx 4.0.0?

Using RouterBuilder#getOpenAPI() you can get the OpenAPIHolder, which allows you to access to any component of the OpenAPI document using JsonPointer:
OpenAPIHolder holder = routerBuilder.getOpenAPI();
Object schema = holder.getCached(
JsonPointer.from("#/components/schemas/example-query")
);

Related

Fastify addSchema to provide meaningful name of the OpenAPI 2.0 definition objects

I have some schema definitions created with fastify as in below, where I have used 'title' to give meaningful name of my models.
fastify.addSchema({
$id: 'persistence-query-params',
title: "PersistenceQueryParams", // Here
type: 'object',
description: 'Persistence Service GET API URL query specification. Applicable for GET API only.',
properties: {
...........
},
});
However when I am looking at the json generated from the swagger (I am using fastify-swagger: 4.8.4 and fastify: 3.20.1), I am seeing this
def-7: ## Here
title: PersistenceQueryParams
type: object
description: >-
Persistence Service GET API URL query specification. Applicable for GET
API only.
properties:
This is coming up in the OpenAPI 2.0 https://editor.swagger.io/, when loading the json generated out of that schema.
I have tried out adding the name field also:
name: "PersistenceQueryParams",
However no luck.
How can I create meaningful names, instead of def-0, def-1 etc in OpenAPI 2.0?
Thanks,
Pradip

Define OpenAPI 2.0 returning JSON object of unknown type

I want to describe OpenAPI that returns JSON object of unknown/any type.
If I define return type in the yaml below I still see generated client returning just a raw string.
responses:
200:
description: Returns any JSON object
schema:
type: string
format: object
Is there a way to describe the return type as a JSON object without describing its schema?
An arbitrary object is defined as type: object, so the correct definition is:
responses:
200:
description: Returns any JSON object
schema:
type: object
Based on Helen's answer you can also explicitly define the content type besides the actual payload being unknown. This is for OpenAPI 3.0.
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
See a full example here.

OpenAPI: Design a reusable schema definition for GET, PUT, POST

I am using OpenAPI 3.0 to design and implement a simple API to allow basic CRUD operations on database entities.
Let's assume an entity Pet with some client-given properties (name & age) and some generated properties (id & created):
components:
schemas:
Pet:
type: object
properties:
id:
type: string
created:
type: string
format: date-time
name:
type: string
age:
type: integer
I want to specify REST endpoints to POST, GET, PUT (and if possible PATCH) a pet:
paths:
/pets:
post:
operationId: createPet
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
responses:
"200":
content:
application/json:
schema:
type: boolean
/pets/{id}:
parameters:
- name: id
schema:
type: string
in: path
required: true
get:
operationId: getPet
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
put:
operationId: updatePet
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
responses:
"200":
content:
application/json:
schema:
type: boolean
patch:
operationId: alterPet
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
responses:
"200":
content:
application/json:
schema:
type: boolean
From a logical point of view, the following properties are required per endpoint:
GET: id, created, name, age
POST: name, age
PUT: name, age
PATCH: name or age (or none depending on implementation)
I see two major approaches here:
Approach 1: Leave all properties optional
The Pet DTO is used as a shell where all properties are optional as defined above. It is left to the server & client to check if the required properties are filled on an endpoint call. If non-required properties are set in a POST/PUT/PATCH request body, they will be ignored.
pros:
Single, simple, and symmetric DTO schema definition in the API specification.
Smooth integration of the "GET -> modify -> PUT" workflow on the client side (e.g., a React frontend with Formik).
Supports the PATCH endpoint out-of-the-box.
cons:
All properties are optional and it is very tedious to handle these string | undefined types in Typescript. This is especially annoying in the GET direction as we know that all properties will be filled as long as we retrieve the Pet DTO.
The implementational "pain" is spread over the server and all possible clients.
Approach 2: Define separate DTO schemas for all operations
We introduce a GetPet, PutPet, PostPet, and PatchPet with corresponging required lists in the API specification. Yes, PutPet and PostPet can be identical, but maybe we want to allow a modified GetPet to be used as PutPet to streamline the "GET -> modify -> PUT" workflow for the client.
Imagine the Pet entity having 5+ generated properties and 20+ client-given properties. We do not want to flat define 4 variations of each entity, but use some kind of inheritance instead. Is there a way to introduce a BasePet bearing all properties (set to optional) and let the 4 operation-specific DTOs extend it with just overriding the required list?
pros:
Easier implementation for client & server as optionality is clarified for all properties.
The "pain" is handled in the API specification.
cons:
The API specification grows in complexity. It is not clear to me if the desired inhertance is possible and how it is specified.
Scalability & maintainability of the API may suffer.
So my question on this topic: How can the inhertiance of the DTOs be specified for OpenAPI 3.0? Are there better alternatives? I am happy for all suggestions concerning these thoughts on an API for basic CRUD operations.
I did face a similar issue while designing an API for a client recently. The trick here is to $ref: redundancies in the schemata for the different routes. For simplicity, I will only define GET, POST and PATCH.
Note: In this case it is easier, as the schema for write operations is a subset of the schema for the read operation.
By contrast, imagine a user-object, where there is a password field, it should be writable, but not readable. In this case, you would need three different schemata:
userRead
userWrite
userCommonFieldsForReadAndWrite
In any case, here is one possible solution to your question:
paths:
/pets:
post:
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/petCreateUpdate"
responses:
"201":
description: Pet created.
headers:
Location:
schema:
type: string
description: points to the Pet resource created. Can be directly used in a subsequent GET request.
example: "Location: /pets/32"
/pets/{id}:
parameters:
- name: id
schema:
type: string
in: path
required: true
get:
responses:
"200":
description: Pet with given id returned.
content:
application/json:
schema:
$ref: "#/components/schemas/petRead"
"404":
description: Pet with given id not found.
patch:
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/petCreateUpdate"
responses:
"204":
description: Pet updated successfully.
components:
schemas:
petRead:
allOf:
- type: object
properties:
id:
type: integer
format: int32
minimum: 1
created:
type: string
format: date-time
- $ref: "#/components/schemas/petCreateUpdate"
petCreateUpdate:
type: object
properties:
name:
type: string
age:
type: number
format: integer
minimum: 1
maximum: 100
This renders in SwaggerEditor as follows:
POST for the Pet
GET for the Pet
PATCH for the Pet

How to handle error datatypes and response messages in RESTful API design

I am building my first RESTful API for practising and learning. I am using RAML and will realize it with MuleSofts AnypointStudio. I don't really know how to deal with responses, particularly, error responses. I managed to figure out which HTTP status codes I want for my responses but didn't manage to figure out how to handle the response messages.
Do I need to define response datatype and example message for every response code (200, 201, 204, 404 etc.)? If I can have one datatype and one example message, how do I do use them accordingly?
Currently, I have defined one error type and one example message.
Error.raml
#%RAML 1.0 DataType
type: object
description: This general error structure is used throughout this API.
properties:
code:
type: integer
minimum: 400
maximum: 599
description?:
type: string
default: "Bad query parameter [$size]: Invalid integer value [abc]"
example: The server understood the request, but is refusing to fulfill it
reasonPhrase?:
type: string
examples:
example: Bad Request
example1: Forbidden
example: !include ../examples/error_example.json
error_example.json
{
"code": 400,
"description": "Bad query parameter [$size]: Invalid integer value [abc]",
"reasonPhrase": "Bad Request"
}
As you can see, I have variables in both datatype and example message. They were generated by Restlet. I don't know how to utilise them yet so I just left them for the time being.
Would really appreciate any help and tips.
Do I need to define response datatype and example message for every response code (200, 201, 204, 404 etc.)? If I can have one datatype and one example message, how do I do use them accordingly?
No you don't. For a resource you could specify responses such as 200 or 404 (these are the most commonly used)
From the docs:
resourceTypes:
collection:
description: Collection of available songs in Jukebox
get:
description: Get a list of songs based on the song title.
responses:
200:
body:
application/json:
post:
description: |
Add a new song to Jukebox.
queryParameters:
access_token:
description: "The access token provided by the authentication application"
example: AABBCCDD
required: true
type: string
body:
application/json:
type: song
responses:
200:
body:
application/json:
example: |
{ "message": "The song has been properly entered" }
An example of a resource with a not found error:
collection-item:
description: Entity representing a <<resourcePathName|!singularize>>
get:
description: |
Get the <<resourcePathName|!singularize>>
with <<resourcePathName|!singularize>>Id =
{<<resourcePathName|!singularize>>Id}
responses:
200:
body:
application/json:
404:
body:
application/json:
example: |
{"message": "<<resourcePathName|!singularize>> not found" }
There's an excellent blog post about this. Have a look at RAML tutorials as they have nice docs.
You could also have a look at Swagger for more "inspiration".

Is there a way to describe two different response types in OpenAPI 3.0?

What I'd like to do is specify that sometimes the response to an API call might be a PDF document, and sometimes it will be JSON. I'd like to do this in OpenAPI 3.0 format. In the case of a PDF, the response would look like this:
responses:
'200':
description: An invoice in PDF format.
content:
application/pdf:
schema:
type: string
format: binary
And in the case of a JSON response, this would describe the response:
responses:
'200':
description: A JSON object containing user name and avatar
content:
application/json:
schema:
$ref: "#/components/schemas/Invoice"
The OAS3 documentation (https://swagger.io/docs/specification/describing-responses/) provides the following example for how to specify that one of a few different JSON schemas could be the response to a particular API call. This is almost what I want, except instead of describing different possible JSON schemas, I'd like to specify different possible content types, as described above. Is there a way to do this in OAS3 format?
responses:
'200':
description: A JSON object containing pet information
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Hamster'
Just found that this works:
responses:
'200':
description: "An invoice."
content:
application/json:
schema:
$ref: "#/components/schemas/Invoice"
application/pdf:
schema:
type: "string"
format: "binary"
See the "Response Media Types" section here: https://swagger.io/docs/specification/describing-responses/