OpenAPI - different schema per operation on same resource - openapi

I'm using OpenAPI 3.0 to describe an API where each resource has a subtly different schema based on its operation. Essentially certain properties are editable and/or required based on whether it's a POST or PUT request.
Is there a better way to do this other than specify a schema for each operation like this? (where field2 is readOnly on the PUT)
Ideally, I'd like to specify the schema (i.e. all the properties) in one place and then override some properties (e.g. readOnly) on each operation.
{
"paths":{
"/users":{
"put":{
"responses":{
"200":{
"$ref":"#/components/schemas/users_put"
}
}
},
"post":{
"responses":{
"200":{
"$ref":"#/components/schemas/users_post"
}
}
}
}
},
"components":{
"schemas":{
"users_post":{
"properties":{
"field1":{
"readOnly":true,
"type":"integer"
},
"field2":{
"type":"string"
}
}
},
"users_put":{
"properties":{
"field1":{
"readOnly":true,
"type":"integer"
},
"field2":{
"type":"string",
"readOnly":true
}
}
}
}
}
}

As far as I know, there is no override mechanism in openapi/swagger models.
But composition (extending) models is available.
Since in your example you need to update only readOnly directives (which means you mark properties that's available only in responses) try other approach when you describe requests and responses separately.
Such in your example the response for put and post methods would be the same (because they both have field1 and field2), and only put will have request (because in post all fields is readOnly):
(I use yaml for brevity, but it's easy convert to json back)
paths:
"/users":
put:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/users_put_request'
responses:
'200':
"$ref": "#/components/schemas/users_response"
post:
responses:
'200':
"$ref": "#/components/schemas/users_response"
components:
schemas:
users_response:
field1:
type: integer
field2:
type: integer
users_put_request:
field2:
type: string
Probably with this approach the different parts of models is describe explicitly.

Related

One way association with array of reference _id in sails js

I'm trying to use one way association because I need only to have reference from 1 model to other model but not vice versa.
Model Arts:
module.exports = {
attributes: {
fileName: {type: 'string', required: true},
softwareUsed: {
model: 'Softwares'
}
}
}
Model Softwares:
module.exports = {
attributes: {
name: {type: 'string', required: true}
}
}
This is my api:
http://localhost:1337/api/v1/arts/create
if this is my request body, it works fine:
request body:
{
"fileName": "booking.jpeg",
"softwareUsed": "5e70309cbf12b61299d6c528",
}
but i want to store array of softwareUsed, so i tried:
request body:
{
"fileName": "booking.jpeg",
"softwareUsed": ["5e70309cbf12b61299d6c528", "5e70309cbf12b61299d6c529"],
}
but i got an error with that:
error: OperationalError [UsageError]: Invalid new record.
Details:
Could not use specified `softwareUsed`. Expecting an id representing the associated record, or `null` to indicate there will be no associated record. But the specified value is not a valid `softwareUsed`. Instead of a string (the expected pk type), the provided value is: [ '5e70309cbf12b61299d6c528', '5e70309cbf12b61299d6c529' ]
I also tried to make it array in model:
softwareUsed: [{
model: 'Softwares'
}]
but still don't work.
Is there a way to that in one way association or I need to use other association, but how can I achieve that?
Thank you.
I think you need to label the softwareUsed attribute with a collection, not a model:
module.exports = {
attributes: {
fileName: {type: 'string', required: true},
softwareUsed: {
collection: 'Softwares'
}
}
}
All the documentation on one-to-many in the sails docs involves two-way associations and adding a via attribute, but I think this way works for a one-way association.
Of course, your first api call may now longer work: you may need to wrap the single software id in an array.

Database design - saving the entire object to a user or just the id of an object?

database noob here using MongoDB, in my program, I have users, and the core of my program are these roadmaps that I display. So, each user can create roadmaps, save others roadmaps, blah blah... Each user has a field named savedRoadmaps and createdRoadmaps which should store the roadmaps. My question is, should I just store the roadmap _ids in the savedRoadmap and createdRoadmaps field or the entire roadmap?
I am asking this because it feels like saving just the _id of the roadmaps can save storage, but it might not come in handy when I have to fetch the data of the user first, then fetch the roadmap using the roadmap ID in the user's savedRoadmap/createdRoadmap field, versus just fetching the user and the savedRoadmap field will already have the roadmap in there.
And btw, is there any sweet and brief database design read out there, please direct me to some if you know any!
For a user, I want it to have a name, email, password, description ofcourse, and also savedRoadmaps and createdRoadmaps. A user can create unlimited roadmaps and also save as much as he or she wants. For a roadmap, I want it to have a name, category, time_completion, author, date, and a roadmap object which will contain the actual json string that I will use d3 to display. Here's my User and Roadmap Schema right now:
const RoadmapSchema = new Schema({
author: {
type: String,
require: false
},
name: {
type: String,
require: true
},
category: {
type: String,
require: true
},
time_completion: {
type: Number,
require: true
},
date: {
type: Date,
default: Date.now
},
roadmap: {
type: "object",
require: true
}
});
and User Schema:
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
savedRoadmap: {
type: "object",
default: []
},
createdRoadmap: {
type: "object",
default: []
}
});
My question is, inside of the savedRoadmap and createdRoadmap fields of the User schema, should I include just the _id of a roadmap, or should I include the entire json string which represents the roadmap?
There are 3 different data-modeling techniques you can use to design your roadmaps system based on the cardinality of the relationship between users and roadmaps.
In general you need to de-normalize your data model based on the queries that are expected from your application:
One to Few: Embed the N side if the cardinality is one-to-few and there is no need to access the embedded object outside the context of the parent object
One to Many: Use an array of references to the N-side objects if the cardinality is one-to-many or if the N-side objects should stand alone for any reasons
One-to-Squillions: Use a reference to the One-side in the N-side objects if the cardinality is one-to-squillions
And btw, is there any sweet and brief database design read out there,
please direct me to some if you know any!
Rules of Thumb for MongoDB Schema Design: Part 1

How to specify the schema of a reusable request body parameter in OpenAPI 3.0

The swagger docs site shows an example for this case, but it does not follow through all the way to show the definition of the Pet schema.
E.g.:
paths:
/pets:
post:
summary: Add a new pet
requestBody:
$ref: '#/components/requestBodies/PetBody'
/pets/{petId}
put:
summary: Update a pet
parameters: [ ... ]
requestBody:
$ref: '#/components/requestBodies/PetBody'
components:
requestBodies:
PetBody:
description: A JSON object containing pet information
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
I don't understand where the request body parameter names go in this scenario. I want to see the definition of #/components/schemas/Pet. For query parameters you have the components/parameters where you can define a name and a schema for each parameter. But I don't see the equivalent for the request body parameters. For example if I have a POST /api/pets with an application/json body of:
{ "name": "Fluffy", "type": "cat", "legs": 4 }
Where do I describe the parameters name, type and legs including their names?
Also on an unrelated topic it would be nice if there was a tag for OpenAPI v3.0 (not sure how to create one)
Also possible related question here.
After scouring the swagger docs I think I understand it now, I think the Pet schema would be:
components:
schemas:
Pet:
type: object
properties:
name:
type: string
type:
type: string
legs:
type: integer
required:
- type
I was missing out on the properties attribute.

Freeform subobject in json-schema

I am drafting an API documentation with swagger.io and is trying to make it fit to our use case. The system is going to receive and process data from all sources, and they would each have different sets of fields.
While the product of the processing share the same schema, we want to include the input in the schema too for reference purpose. For instance, given
{
"foo": "bar"
"bar": "baz"
}
The product of the processing is
{
"original": {
"foo": "bar",
"bar": "baz"
}
"processed": {
"stdFieldA": "bar",
"stdFieldB": "baz"
}
}
Assuming for each input from different sources, we end up having stdFieldA and stdFieldB. So the response schema object we have
type: object
properties:
processed:
type: object
properties:
stdFieldA:
type: string
stdFieldB:
type: string
now that we have the processed subobject defined, can we define a freeform object for the original input, so that this object coming from another source is valid
{
"alpha": "lorem",
"beta": "ipsum"
}
If I don't get any answer to this, my workaround to the problem would be storing the original input as string (convert the original input into JSON string).
type: object without properties describes a free-form object. So the response schema can be:
type: object
properties:
original:
type: object # <----------
processed:
type: object
properties:
stdFieldA:
type: string
stdFieldB:
type: string

Should I include URLs or Ids of resources in REST API response?

I am designing a REST API. There's an entity Organization which may have a parent organization and multiple child organizations.
Let's say a user does request GET /organizations/1234.
What should I respond with?
I can use URLs to these other organizations.
{
"data": {
"name": "Microsoft",
"parent_organization": "http://api.myapi.asdfghj/organizations/1220",
"child_organizations": [
"http://api.myapi.asdfghj/organizations/1236",
"http://api.myapi.asdfghj/organizations/1214"
]
}
}
or I can use their ids
{
"data": {
"name": "Microsoft",
"parent_organization": 1220,
"child_organizations": [
1236,
1214
]
}
}
Which one is better?
If it's the one with full URLs, how do I do document that in swagger? Do I just set that as a string, something like the following?
definitions:
Organization:
type: object
properties:
data:
type: object
properties:
name:
type: string
parent_organization:
type: string
format: url
child_organizations:
type: array
items:
type: string
format: url
What about POST /organizations for creating a new user? Should the user specify parent and children as urls too?
I suggest you use urls rather than some ids. The advantage of having actual urls is that you can change them dynamically without worrying about the clients who depend on some base urls and then have to compute the actual urls from ids, etc.
For documentation purpose you can treat urls as strings and explain them like other params.