I am trying to understand how to nest ref inside a ref..
I have 2 objects, ResponseObject and LastUpdatedAt:
ResponseObject:
type: object
properties:
code:
type: integer
format: int32s
minimum: 100
maximum: 600
message:
type: string
data:
type: object
required:
- code
- message
and
LastUpdatedAt:
type: object
properties:
last_updated_at:
type: long
readOnly: true
example: 1574933675150
What I want to achieve is making my example look like this:
I keep trying without success, this is as far as I've gotten:
LastUpdatedAtResponse:
schema:
$ref: "#/components/schemas/ResponseObject"
example:
- code: 200
message: 'Success'
data:
schema:
$ref: "#/components/schemas/LocalDataLastUpdatedAt"
example:
- lastUpdated: 1574933675150
but this ends up looking like this:
My end goal is to have all my objects use the ResponseObject but I can't seem to make it work.
Any idea what I'm missing?
The example keyword does not support $ref. You need to specify the whole example value inline:
LastUpdatedAtResponse:
...
example:
- code: 200
message: 'Success'
data:
last_updated_at: 1574933675150
Note that $ref is supported in multiple examples, but it can only be used to reference the entire Example Object, it's impossible to $ref just a part of an example.
Related
I'm using OpenApi 3. A tool I use, Owasp Zap looks at the OpenAPI doc and creates fake requests. When it gets a 404, it complains that it doesn't have the media type that the OpenAPI promises.
But I didn't write anything in the OpenAPI doc about how 404s are handled. Obviously I can't write an infinite number of bad end points & document that they return 404s.
What is the right way to record this in the OpenAPI yaml or json?
Here is a minimal yaml file... I know for sure that this file does say anything about 404, ie. 404s aren't in the contract so tools are complaining that 404s are valid responses, but 404 is what a site should return when a resource is missing
---
"openapi": "3.0.0"
paths:
/Foo/:
get:
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Foo"
default:
description: Errors
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Foo:
type: object
required:
- name
properties:
name:
type: string
Error:
type: object
required:
- error
properties:
error:
type: string
message:
type: string
data:
type: object
This has been proposed already but not implemented: https://github.com/OAI/OpenAPI-Specification/issues/521
In the comments someone gave a suggestion: https://github.com/OAI/OpenAPI-Specification/issues/521#issuecomment-513055351, which reduces a little your code, but you would still have to insert N*M entries for N paths * M methods.
Since we don't have the ability to make the specification change to our needs, all that remains is we adapting ourselves.
From your profile, you seem to be a windows user. You can for example, create a new explorer context menu to your .yaml files (Add menu item to windows context menu only for specific filetype, Adding a context menu item in Windows for a specific file extension), and make it run a script that auto-fills your file.
Here, an example python script called yamlfill404.py that would be used in the context call in a way like path/to/pythonexecutable/python.exe path/to/python/script/yamlfill404.py %1, where %1 is the path to the file being right clicked.
Python file:
import yaml
from sys import argv
import re
order = ['openapi','paths','components']
level0re = re.compile('(?<=\n)[^ ][^:]+')
def _propfill(rootnode, nodes, value):
if len(nodes) == 1:
rootnode[nodes[0]] = value
if len(nodes) > 1:
nextnode = rootnode.get(nodes[0])
if rootnode.get(nodes[0]) is None:
nextnode = {}
rootnode[nodes[0]] = nextnode
_propfill(nextnode, nodes[1:], value)
def propfill(rootnode, nodepath, value):
_propfill(rootnode, [n.replace('__slash__','/') for n in nodepath.replace('\/','__slash__').split('/')], value)
def yamlfill(filepath):
with open(filepath, 'r') as file:
yamltree = yaml.safe_load(file)
#propfill(yamltree, 'components/schemas/notFoundResponse/...', '')
propfill(yamltree, 'components/responses/notFound/description', 'Not found response')
propfill(yamltree, 'components/responses/notFound/content/application\/json/schema/$ref', '#/components/schemas/notFoundResponse')
responses = [mv['responses'] if 'responses' in mv else [] for pk,pv in (yamltree['paths'].items() if 'paths' in yamltree else []) for mk,mv in pv.items()]
for response in responses:
propfill(response, '404/$ref', '#/components/responses/notFound')
yamlstring = yaml.dump(yamltree)
offsets = [i[1] for i in sorted([(order.index(f.group(0)) if f.group(0) in order else len(order),f.start()-1) for f in [f for f in level0re.finditer('\n'+yamlstring)]])]
offsets = [(offset,(sorted([o for o in offsets if o > offset]+[len(yamlstring)-1])[0])) for offset in offsets]
with open(filepath[:-5]+'_404.yaml', 'w') as file:
file.write(''.join(['\n'+yamlstring[o[0]:o[1]] for o in offsets]).strip())
yamlfill(argv[-1])
It processes the %1, which would be path/to/original.yaml and saves it as path/to/original_404.yaml (but you can change it to overwrite the original).
This example script changes the yaml formating (quotes type, spacing, ordering etc), because of the library used pyyaml. I had to reorder the file with the order = ['openapi','paths','components'], because it loses ordering. For less instrusion, maybe a more manual insertion would be better suited. Maybe one that uses only regex. Maye using awk, there are plenty of ways.
Unfortunately it is just a hack not not a solution.
Given a path template with two parts such as:
paths:
/blah/{fooPart}-stuff-{barPart}:
parameters:
- in: path
name: fooPart
description: foo part of this matrix ID
required: true
schema:
type: string
- in: path
name: barPart
description: bar part of this matrix ID
required: true
schema:
type: string
I'd like to provide an list of examples. Since the fooPart and the barPart are correlated, i'd like to have each example have the corrrelated data elements. I'd imagine putting it in the components
examples:
Happy:
summary: Happy path
value:
fooPart: red
barPart: up
Sad:
summary: Sad path
value:
fooPart: up
barPart: red
When i add the refs as an examples list to each parameter, like so
- in: path
name: fooPart
description: foo part of this matrix ID
required: true
schema:
type: string
examples:
happy:
$ref: "#/components/example/Happy"
sad:
$ref: "#/components/example/Sad"
the rendered display is ... adequate? Wrong? Not helpful? The examples aren't correlated and the array specified as value is presented in the box for each parameter, as seen here. I recognize, this is what i told it to do. Is there any way to bundle all the examples together? Or is my only option the one i will offer as an answer? Ugh.
I'm assuming the only option is
examples:
HappyFoo:
summary: Happy path
value: red
HappyBar:
summary: Happy path
value: up
SadFoo:
summary: Sad path
value: red
SadBar:
summary: Sad path
value: red
With each parameter only including its own values like so:
parameters:
- in: path
name: fooPart
description: foo part of this matrix ID
required: true
schema:
type: string
examples:
Happy:
$ref: "#/components/examples/HappyFoo"
Sad:
$ref: "#/components/examples/SadFoo"
The examples aren't correlated, but at least the value in the box is correct as seen here.
I refer to an other component, and some of its fields become required.
Example with AbstractQuestion, a component that I will refer to later on:
AbstractQuestion:
type: object
properties:
title:
description: Question statement
type: string
label:
description: Question label
type: string
required:
description: whether an answer is required for this question or if it could be left blank
type: boolean
question_type:
description: campaign type
enum:
- profile
- feeling
type: string
answer_type:
enum:
- string
- list
- date
type: string
max_length:
description: >-
for open ended questions this is the max characters possible. for list type questions
this would be the max number of options to select when multiple answers are accepted
type: integer
modelizable:
description: 'whether the questions'' answers are suitable for feeding ML models (e.g. 1,2,3,4)'
type: boolean
choices:
$ref: '#/components/schemas/QuestionChoices'
Now, I will use it to define a Post request body, specifying which field are required. NB: I didn't specify this in the previous object because it is also used in an other context (GET or PUT requests for example) where those fields are not required.
QuestionPost:
allOf:
- $ref: '#/components/schemas/AbstractQuestion'
required:
- title
- label
- required
- question_type
- answer_type
- modelizable
When I try this solution, my tests do not pass, as they match the yaml file to my api and find this error:
openapi_spec_validator.exceptions.ExtraParametersError: Required list has not defined properties: ['label', 'title', 'answer_type', 'question_type', 'modelizable', 'required']
It seems unable to find the required properties in the referenced component.
When I try this solution:
QuestionPost:
$ref: '#/components/schemas/AbstractQuestion'
required:
- title
- label
- required
- question_type
- answer_type
- modelizable
I get a warning in my editor. My understanding of the doc is that the required field will be ignored.
Maybe what I'm trying to achieve is just not possible? How would you do it?
Here's what my data looks like (YAML):
-
name: objectA
components:
-
name: "component_1"
-
name: "component_2"
styles:
-
name: "new style"
components:
-
name: "component_1"
-
name: "other style"
components:
-
name: "component_4"
I would like to retrieve in my mustache the full list of components for objectA, meaning i need to access all the components children values and concatenate them or uniq them.
The goal would be to have a template like this:
{{#allComponents}}
{{name}}
{{/allComponents}}
which should output:
component_1
component_2
component_4
PS: i am using GRMustache
There's very little chance any Mustache implementation could handle such a specific need with any native built-in syntax of any kind. And GRMustache does actually not.
The simplest path is to prepare your allComponents key before rendering your data.
I have a many to many relationship between products and colours.
What I am trying to do is find products by their colours.
eg)
$colours = $em->getRepository('Xxxxx\XxxxxBundle\Entity\Colour')->findBy(array('name'=>'red');
$products = $em->getRepository('Xxxxx\XxxxxBundle\Entity\Product')->findBy(array('colours'=>$colours));
This is my Yaml config:
Xxxxx\XxxxxBundle\Entity\Product:
type: entity
manyToMany:
colours:
targetEntity: Colour
joinTable:
name: Product_Colour
joinColumns:
product_id:
referencedColumnName: id
inverseJoinColumns:
colour_id:
referencedColumnName: id
.
Xxxxx\XxxxxBundle\Entity\Colour:
type: entity
id:
id:
type: integer
generator:
strategy: AUTO
fields:
hex:
type: string
length: 320
name:
type: string
length: 320
The error message I am getting is:
Notice: Undefined index: joinColumns in /home/xxx/public_html/products/vendor/doctrine/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1217
Would someone be able to shine some light on why this is not working.
I know this is an old question, but if anyone else arrives here via Google (like I did), I had to eschew the findBy and use DQL in the repository:
$products = $em->getRepository('Vendor\Bundle\Entity\Product')->findByColours($colours);
And in the repository:
public function findByColours($colours)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb ->select(array('p'))
->from('VendorBundle:Product', 'p')
->join('p.colours', 'c', 'WITH', $qb->expr()->in('c.id', $colours));
$result = $qb->getQuery()->execute();
return $result;
}
You may need to change the join based on what $colours is. This is assuming it's an array of colour IDs. If it's a string you can forgo the in() or if it's an array of strings you'll need to bind the strings as parameters (see the following link). Clarification on expr() and such is in the Doctrine docs
I don't know why Undefined index: joinColumns occurs, but this is a method to side-step it altogether. Hopefully someone can clarify as to the error, as my solution adds extra work to the Many to Many relationship.