How to use OneOf with two similiar schemas in OpenApi? - schema

I have the following schema in openapi
/submit:
post:
description: Submit info
x-openapi-router-controller: abc.def
operationId: submit_info
requestBody:
description: Submit request
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitRequest'
responses:
200:
description: submitted successfully
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/FooResponse'
- $ref: '#/components/schemas/BarResponse'
FooResponse:
type: object
required:
- id
- value
properties:
id:
type: string
description: id
example: '1234'
value:
type: string
description: value
example: 'foo'
BarResponse:
type: object
required:
- id
- value
- data
properties:
id:
type: string
description: id
example: '1234'
value:
type: string
description: value
example: 'foo'
data:
type: object
required:
- transaction_id
description: Data associated bar response
properties:
transaction_id:
type: string
description: transaction id
example: 'c2345'
So I have FooResponse and BarResponse. I am getting OneOf matches multiple schema error though I have different required items in FooResponse and BarResponse. It seems like openapi matches two schemas even if there are additional required items in one of the schema.
Is there a way to fix this? I want to use OneOf, but not sure how to differentiate these two schema.
Appreciate the help.

The OpenAPI Schema Object has a property called additionalProperties that specifies if properties not defined in the schema are allowed anyway in the instances(those properties are ignored).
Default value for additionalProperties is true which will cause both FooResponse and BarResponse to be valid for your instances.
Setting additionalProperties to false on FooResponse should solve the problem.
If you don't want to disallow additional properties you would have to introduce some kind of type property in both objects and use a Discriminator Object.

Related

How to specify XML element names in bpmn-js

If I define a moddle file with bpmn-js like this
{
name: "thisArgument",
superClass: [
"Element"
],
properties: []
},
{
name: "myData",
superClass: [
"Element"
],
properties: [
{
name: "argument",
type: "thisArgument"
}
]
},
Then the resulting XML (when I call saveXML) will have an element called thisArgument, despite the fact that the name is "argument". First, is that a bug? If not, how do I control the output so that the XML contains argument rather than thisArgument? I've searched the docs and examples but can't find how to do this.
The only workaround I found was to make it type: "argument" and then define argument with a superClass of thisArgument and no extra properties (essentially making an alias). However, that only works if all instances of argument are identical. Eg. if the XML needed to be
<A><argument/></A>
<B><argument/></B>
where the argument in A has a different shape than the argument in B, then there would be a conflict since I can't define argument twice.
I can sort of answer my own question. I found this serialize option and experimented, and it mostly does what I want, but sometimes it adds an unwanted xsi:type="originalType" attribute and sometimes it doesn't. Maybe it depends on isBody but I'm not sure. If anyone knows the details of how it works, please reply.
properties: [
{
name: "argument",
type: "thisArgument",
xml: {
serialize: "xsi:type"
},
}
]
The closest thing I found to documentation on it is https://forum.bpmn.io/t/bpmn-json-documentation/1304 which describes it as "additional meta-data impecting XML serialization of a type", so I'd appreciate any extra details anyone can supply.
Update:
The docs don't mention this, but it turns out that serialize: "property" is exactly what I need. This does the same as serialize: "xsi:type" but doesn't add the xsi:type attribute.
xml: {
serialize: "property"
},
I found this by hunting the code in one of the related packages, moddle-xml.
In write.js, there's code that looks for the xsi:type or property entry:
// allow serialization via type
// rather than element name
var asType = serializeAsType(p),
asProperty = serializeAsProperty(p);
In the same file, I found some code that appears to explain why the xsi:type didn't always show up, too:
// only serialize xsi:type if necessary
if (descriptor.name === this.propertyDescriptor.type) {
return attributes;
}

Why am I seeing the _entities request in one service when the entity is native to another?

I'm working on implementing services compatible with Apollo GraphQL federation; my providing services are written in Lacinia (GraphQL library for Clojure).
I have one service that defines Users:
type User #key(fields: "id") {
id: String!
name: String!
}
type Query {
user_by_id(id:String!) : User
}
schema { query: Query }
and and a second that defines Products and extends Users:
type User #extends #key(fields: "id") {
id: String! #external
favorite_products: [Product]
}
type Product #key(fields: "upc") {
upc: String!
name: String!
price: Int!
}
type Query {
product_by_upc(upc: String!) : Product
}
schema { query: Query }
When I execute a query that spans services:
{
user_by_id(id: "me") {
id
name
favorite_products {
upc
name
price
}
}
}
I get a failure; the following request is sent to the products service:
INFO products.server - {:query "query($representations:[_Any!]!){_entities(representations:$representations){...on User{favorite_products{upc name price}}}}", :vars {:representations [{:__typename "User", :id "me"}]}, :line 52}
and that fails, because the products service shouldn't, as far as I know, have to provide the equivalent of __resolveReference for type User (which it extends); just type Product.
This is very unclear in the documentation and I'll experiment with providing a kind of stub reference resolver in Product for stubs of User.
Yes, indeed, you must provide the __resolveReference (or equivalent) for each type the service schema extends. In retrospect, it makes sense, as it provides the "kernel" of a raw value to be passed down the resolver tree.

How do I query MongoDB to find all records which contain a particular array of objects?

I am implementing tagging functionality in my Angular MEAN stack app and so want to query the DB to retrieve all objects (in this case "NFR"s) which have one or more of those tags ("Tag" objects). Thus I have NFR objects which may contain an array of Tag objects. I have tried a number of MongoDB find queries which return nothing despite tagged records existing.
Here are some code snippets (Mongoose schema defs for NFR and Tag). Thanks very muchly in advance :-).
Katie
NFR schema:
import * as mongoose from "mongoose";
import {Tag} from "../../app/main/models/tag";
let NFR = new mongoose.Schema({
category: String,
subCategory: String,
nfr: String,
acceptanceTest: String,
source: String,
status: String,
creationDate: Date,
createdBy: String,
changeLog: String,
tags: [{
type: Tag
}]
});
Tag schema
import * as mongoose from "mongoose";
let Tag = new mongoose.Schema({
name: String,
source: String,
creationDate: Date,
_id: String
});
In the database the NFR object to search on contains two Tag objects via object id reference .
Thanks Veeram, I had to move the Tag mongoose class inside the NFR one to get it creating the associated Tag object properly (which I can now search on). This is a bad hack, not sure why it doesn't work the proper way but it will do for now.

Swagger inheritance in objects [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
I want to document some wrapped json documents:
Action:
required:
- description
- name
properties:
description:
type: string
format: string
name:
type: string
format: string
Actor:
required:
- gpn
properties:
gpn:
type: string
format: string
Object:
required:
- image
- type
- url
properties:
image:
type: string
format: string
type:
type: string
format: string
url:
type: string
format: string
CreateActivity:
required:
- action
- actor
- object
- title
- externalID
properties:
action:
$ref: Action
actor:
$ref: Actor
object:
$ref: Object
title:
type: string
format: string
externalID:
type: string
format: string
And I have declared this with a $ref in Swagger
paths:
/activity:
get:
description: Returns an activity
operationId: fetchActivity
produces:
- application/json
parameters:
- name: externalActivityID
in: query
required: true
type: string
responses:
200:
description: existing activity
schema:
$ref: CreateActivity
default:
description: unexpected error
schema:
$ref: ErrorModel
The result isn't what im excepting (and i copyied the approach from pet shop). I want a object with linked entries (i.e. Action, Actor and Object are in CreateActivity with field names) and linked the request to the CreateActivity Object.
Screenshots are showing the actual situation:
the Object with the missing "subobjects"
And the missing link in the swagger documentation:
This is a known issue with swagger-editor.
Please take a look here - https://github.com/swagger-api/swagger-editor/issues/217.
Also, when you use "type": "string", there's no need to add "format":"string" as it adds no information to it. The "format" field is used to finely define the "type".

How to expose enum values in a REST API

In a mobility context of use of the API, an advanced research proposes several dynamic filters that must be returned by the server. (We don't want to make too many exchange with server to initialize our filters)
In a REST api, how to expose a enum of possible values ​​for filter search?
Thank you for your suggestions/ideas?
My initial thought would be to treat the search like a normal resource. In an object oriented perspective, a search can have a collection of fields which can be used to filter by. These fields can be numeric, boolean, string based, or whatever.
So, if I understand your question correctly, then I would propose doing this:
GET /search_fields
If your API have multiple type searches that can be performed, then they can be identified by an id or maybe their name, as long as it is unique, like so:
GET /searches/{search_id}/fields
which would return a collection of search fields like so:
[{
name: 'Field1',
type: 'boolean'
},
{
name: 'Field2',
type: 'number'
},
{
name: 'Field3',
type: 'string'
}]
or if your fields are really just simple enums then:
[{
name: 'Field1',
id: 1
},
{
name: 'Field2',
id: 2
},
{
name: 'Field3',
id: 3
}]
That's my suggestion. Remember, there's no one right way to expose an API.