Include non-associated objects response which conforms JSON API specification - rails-api

I am trying to build an API in rails using JSON API specification
My User model has change objects associated with them. For example, user can have the following change:
{
id: 10,
type: 'changes',
diffs: [
{
subject: 'email',
from: 'old#example.org',
to: 'new#example.org'
},
{
subject: 'tags',
from: []
to: [{ id: 1, type: 'tags', label: 'Ruby' }]
}
]
}
As you can see the diffs property contains an array of change differences and the second difference is an array of objects difference. I would want to modify this format (if possible) so it will conform JSON API specification. Like this:
{
subject: 'tags',
from: []
to: [{ id: 1, type: 'tags' }]
}
And put the tag's attributes into the included section:
included: [
{
id: 1,
type: 'tags',
attributes: { label: 'Ruby' }
}
]
Question: differences is an array of objects (not records, they do not have ID) which contain fields with records. Is possible to format the response so deeply nested records (like tags in my case) will be reference to the records in the included section?
I would want to use fast_jsonapi gem

I don't think you can do this without violating the spec.
A resource object must contain an id:
“Resource objects” appear in a JSON API document to represent resources.
A resource object MUST contain at least the following top-level members:
id
type
There is only one exception allowed by spec:
Exception: The id member is not required when the resource object originates at the client and represents a new resource to be created on the server.
So if your diffs don't have an ID you can't model them as a resource object.
But you are not allowed to include a resource that is not referenced by a resource object:
Compound documents require “full linkage”, meaning that every included resource MUST be identified by at least one resource identifier object in the same document. (source)
There is only one exception that does not apply to the case discussed here:
The only exception to the full linkage requirement is when relationship fields that would otherwise contain linkage data are excluded via sparse fieldsets.

Related

requestBody not displaying subtypes with arrays within a $ref component but shows correctly in response body

I've been struggling with an issue in an openapi 3.0.1 spec json document I've been working on.
The issue I'm seeing in the online swagger editor (editor.swagger.io) is very strange where the Request body Example Value section of a POST does not show the "layers", which is an array defined within my MixBase schema component, based on the MixLayer schema component. The MixLayer schema component has an array of MixLayerComponent schema components.
However, if I include a $ref to the MixBase schema in the responses section, all the elements are shown correctly.
Request body Example Value section that is missing the 'layers':
{
"mixId": "4f8b533f-7449-4056-92ff-11b1de94d656",
"mixDescription": "SES5M",
"mixScaleName": "MyScale",
"mixRoom": "MixingRoomABC",
"mixProgramId": "ABC-123-ProgramId",
"mixDateTime": "2018-06-07T12:51:25.077Z",
"mixState": "Paused",
"mixNumber": "131",
"mixedByUserName": "john.smith#example.com",
"mixedByFirstName": "John",
"mixedByLastName": "Smith"
}
Responses Example Value section returning the correct list of elements including 'layers':
{
"mixId": "4f8b533f-7449-4056-92ff-11b1de94d656",
"mixDescription": "SES5M",
"mixScaleName": "MyScale",
"mixRoom": "MixingRoomABC",
"mixProgramId": "ABC-123-ProgramId",
"mixDateTime": "2018-06-07T12:51:25.077Z",
"mixState": "Paused",
"mixNumber": "131",
"mixedByUserName": "john.smith#example.com",
"mixedByFirstName": "John",
"mixedByLastName": "Smith",
"layers": [ -- this represents the MixLayer component
{
"unitOfMeasure": "g",
"Components": [ -- this represents the MixLayerComponent correctly
{
"code": "800C",
"description": "800C",
"poured": 204.5,
"density": 1.041
}
]
}
]
}
My requestBody section is defined as: (doesn't show 'layers')
requestBody:
required: true
description: Paint mix information to create
content:
application/json:
schema:
$ref: '#/components/schemas/MixBase'
My responses section is defined as: (and this displays correctly in the Response examples section)
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/MixBase'
Here is the definition of the 'layers' within the MixBase schema component (which is the last element in the MixBase definition which is why additionalProperties is set to false): (The formatting might not be correct in stack overflow but the swagger editor doesn't complain so I don't believe the issue is linked to formatting)
layers:
description: Layer related information for components of the mix
type: array
items:
$ref: '#/components/schemas/MixLayer'
readOnly: true
additionalProperties: false
Here is the definition of the MixLayer:
MixLayer:
required:
- Components
type: object
properties:
unitOfMeasure:
description: Unit of volume for the components of the layer
maxLength: 10
type: string
nullable: true
example: g
Components:
description: The components that make up the layer in the mix
type: array
items:
$ref: '#/components/schemas/MixLayerComponent'
readOnly: true
additionalProperties: false
Here is the definition of the MixLayerComponent:
MixLayerComponent:
required:
- code
- density
- poured
type: object
properties:
code:
description: The code associated with the mix component of the layer
maxLength: 25
minLength: 1
type: string
example: 800C
description:
description: The description of the mix component of the layer
maxLength: 120
type: string
nullable: true
example: 800C
poured:
description: >-
The quantity, expressed in the unit of measurement, consumed for the
mix component
type: number
format: double
example: 204.5
density:
description: The density associated with the mix component of the layer
type: number
format: double
example: 1.041
additionalProperties: false
I thought that the "Components" element in the MixLayer component schema might be a reserved keyword in openapi so I changed the references to something else and it still has the same issue.
I thought this issue might be with the online swagger editor (editor.swagger.io) but the same thing occurs in Postman. I also tried browsers Chrome, Edge, and Firefox and they all
have the same issue. I have also tried an XML content type in addition to the JSON I would like to use but still the same issue.
I don't access to post my openapi.json file on stack overflow but I hope this provides enough information.
Any insights anyone has for me to continue a line of investigation would be greatly appreciated.
Thank you for your time in advance,
Dave
layers is defined as a read-only property (readOnly: true) - that's why it doesn't appear in the request body example.

Zabbix LLD custom process monitoring item error

I want to track my custom processes through Zabbix (v2.4.8). I am generating the following json object and sending it through UserParameter=service.value[*],/usr/lib/zabbix/externalscripts/custom1.bash:
{
"data":[
{
"{#NAME}":"ntp",
"{#VALUE}":"1"
},
{
"{#NAME}":"mysql",
"{#VALUE}":"1"
},
{
"{#NAME}":"prometheus",
"{#VALUE}":"0"
},
{
"{#NAME}":"apache2",
"{#VALUE}":"0"
}
]
}
Also, creating an item prototype and graph prototype inside a new template with a new discovery rule, having the following information:
Discovery rule name: Service Graph
Type: Zabbix Agent
key: service.value
Item Prototype name: Service {#NAME} Graph
Type: Zabbix Agent
key: service.value[{#NAME},{#VALUE}]
Type of info: Numeric(Unsigned) & Decimal
When I apply these settings, the items keep giving the following error:
Not supported: Received value [{ "data":[ { "{#NAME}":"ntp", "{#VALUE}":"1" }, { "{#NAME}":"mysql", "{#VALUE}":"1" }, { "{#NAME}":"prometheus", "{#VALUE}":"0" }, { "{#NAME}":"apache2", "{#VALUE}":"0" } ]}] is not suitable for value type [Numeric (unsigned)] and data type [Decimal]
I have to create a graph prototype with these settings, so I cannot mention type as "Text" for obvious reasons.
Another question: The graphs thus generated are not clickable at all like the other existing graphs.
Please let me know where I am going wrong.
If your service.value key generates JSON, that should be used with the LLD rule only. You should not send any values in it. The key to be used in the prototypes should be like any normal key they only returns values it was asked for, do not use the LLD-generating key there.
Your current JSON looks like you might be able to use the built-in items for process monitoring, but that is hard to be sure about without additional detail.
Also note that [*] in the UserParameter definition is not needed if you do not pass parameters to this key.

Use object type query param in swagger documentation

I have a GET route where I would like to encode an object parameter in the url as a query string.
When writing the swagger documentation I basically get errors that disallow me to use schema/object types in a query type parameter:
paths:
/mypath/:
get:
parameters
- in: path
name: someParam
description: some param that works
required: true
type: string
format: timeuuid #good param, works well
- $ref: "#/parameters/mySortingParam" #this yields an error
parameters:
mySortingParam
name: paging
in: query
description: Holds various paging attributes
required: false
schema:
type: object
properties:
pageSize:
type: number
cursor:
type: object
properties:
after:
type: string
format: string
The request query param having an object value would be encoded in an actual request.
Even though swagger shows an error at the top of the screen the object is rendered correctly in the swagger UI editor, however with that error floating on top of the documentation.
I don't think you can use "object" as query parameter in Swagger spec as query parameter only supports primitive type (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types)
This is now possible with OpenAPI 3.0.
parameters:
- in: query
name: values
schema:
type: object
properties:
genre_id:
type: integer
author_id:
type: integer
title:
type: string
example:
{
"genre_id": 1,
"author_id": 1
}
style: form
explode: true
Here you can use style and explode keywords to specify how parameters should be serialised.
style defines how multiple values are delimited. Possible styles depend on the parameter location – path, query, header or cookie.
explode (true/false) specifies whether arrays and objects should
generate separate parameters for each array item or object property.
For the above example the url will be:
https://ebookstore.build/v1/users/books/search?genre_id=1&author_id=1
For more information on describing parameters with OpenAPI v3 and parameter serialisation, please refer here.
This is possible, just not with OpenAPI 2.0. OpenAPI 3.0 describes how this is possible here:
https://swagger.io/docs/specification/describing-parameters/
parameters:
- in: query
name: filter
# Wrap 'schema' into 'content.<media-type>'
content:
application/json: # <---- media type indicates how to serialize / deserialize the parameter content
schema:
type: object
properties:
type:
type: string
color:
type: string
In the meantime you could just have the query parameter as a plain old string type and then perform the serialization manually, then set the query parameter as required. This is what I'm doing until Swagger UI fully supports OpenAPI 3.0.

How to define flat object structure in swagger body parameter

I'm using swagger 2.0 and need to define a post request to create an account object. The object data is passed in the body as a flat object structure:
Example body data:
{
first_name: "Sherlock",
last_name: "Holmes",
address: "Bakerstreet 221b",
# tax_id: not set, # optional
}
When I create the request doc in yaml:
definitions:
new_account:
properties:
first_name:
type: string
last_name:
type: string
address:
type: string
tax_id:
type: string
required:
- first_name
- last_name
- address
paths:
/accounts:
post:
summary: Create account
parameters:
- name: account
in: body
schema:
$ref: "#/definitions/new_account"
the documentation describes a body with exactly one element: account which itself contains some fields. However my structure is flat, no top node account.
If I leave out the name attribute, it's basically the same, only that the name column is empty in the resulting documentation and the whole structure is either required or not.
My current workaround is to list all parameters and set in: query but that's obviously wrong.
How to define this?
account is just the name of the body parameter. One usage is in the method signature in the API client generated by Swagger Codegen. In other words, account is not a top node (FYI, in Swagger spec 1.2, the body parameter must be named body)
Your definition above is correct for the example body data you provided.

Rails 3 - Creating a JSON response to display Search Results

I'm working to have Rails 3 respond with a JSON request which will then let the app output the search results with the jQuery template plugin...
For the plugin to work, it needs this type of structure:
[
{ title: "The Red Violin", url: "/adadad/123/ads", desc: "blah yada" },
{ title: "Eyes Wide Shut", url: "/adadad/123/ads", desc: "blah yada" },
{ title: "The Inheritance", url: "/adadad/123/ads", desc: "blah yada" }
]
In my Rails 3 controller, I'm getting the search results which come back as #searchresults, which contain either 0 , 1 , or more objects from the class searched.
My question is how to convert that to the above structure (JSON)...
Thank you!
Update
Forgot to mention. The front-end search page will need to work for multiple models which have different db columns. That's why I'd like to learn how to convert that to the above to normalize the results, and send back to the user.
I am not really sure what is the problem here, since you can always call ".to_json" on every instance or collection of instances or hash, etc.
You can use .select to limit the number of fields you need, ie:
Object.select(:title, :url, :desc).to_json
I am guessing that the #searchresults is ActiveRecord::Relation, so you probably can use:
#searchresults.select(:title, :url, :desc).to_json

Resources