Fastify response schema with $merge-keyword throws FST_ERR_SCH_BUILD - jsonschema

When adding a response schema to a fastify resource that leverages the $merge keyword, an error
FST_ERR_SCH_BUILD: Failed building the schema for GET: /, due error undefined unsupported
is thrown.
Schema looks like the following, but the same error is thrown using the examples from ajv or fastify.
response: {
200: {
$merge: {
source: {
type: 'object',
properties: {
foo: { type: 'string' }
}
},
with: {
type: 'object',
properties: {
bar: { type: 'string' }
}
}
}
}
}
workaround described in own answer

I have found a workaround for this:
it seems that unlike when using $merge in any other schema, either fastify or ajv require the type keyword to be present on $merge level.
This might be a bug, as it can be deduced from the merged objects and the methodology works when using $merge for other schemas.

The serializer doesn't implement the ajv's schema customization (as it is $merge). Under the hood fast-json-stringify is used by default.
You should use standard JSON schema and its combining keywords.
In fastify v2 the serializer that uses the schemas is not customizable, so you should write your own serializer and set up it using setReplySerializer.

Related

Open API schema conditional response field based on the presence of a query parameter

I am working on providing a GET REST API where I would like to conditionally include the total_documents field (its an integer count of the total number of records present in the DB table).
The API signature and response payload will be something like:
GET /endpoint/?total_documents&.....
Response Payload:
{
documents: [....],
total_documents: 100
}
Now I would like the total_documents field to be appeared in the response payload if and only if the total_documents query parameter exists in the URL.
This is what I tried, based on my schema:
fastify.addSchema({
$id: 'persistence-query-params',
title: "PersistenceQueryParams",
type: 'object',
description: 'Persistence Service GET API URL query specification. Applicable for GET API only.',
properties: {
'total_documents': {
description: 'Total number of documents present in the collection, after applying filters, if any. This query paramater does not take any value, just pass it as the name (e.g. &total_documents).',
nullable: true,
},
},
}
querystring: {
description: 'Persistence Service GET API URL query specification. Applicable for GET API only.',
$ref: 'persistence-query-params#',
},
response: {
200: {
properties: {
'documents': {
description: 'All the retrieved document(s) from the specified collection for the specified service database and account.',
type: 'array',
items: {
$ref: 'persistence-response-doc#',
}
},
'total_documents': {
description: "If total_documents query paremeter is specified, gives the total number of documents present in the collection, after applying query paramaters, if any. If total_documents is not specified, this field will not be available in the response payload.",
type: 'number',
default: -1,
},
},
dependencies: {
'total_documents': { required: ['querystring/properties/total_documents'] },
},
},
'4xx': {
$ref: 'error-response#',
description: 'Error response.'
}
}
What is the way out here?
Thanks,
Pradip
JSON Schema has no notion of a request or response or HTTP.
What you have here is an OpenAPI specification document.
The OpenAPI specification defines a way to access dynamic values, but only within Link Objects or Callback Objects, which includes the query params.
Runtime expressions allow defining values based on information that
will only be available within the HTTP message in an actual API call.
This mechanism is used by Link Objects and Callback Objects.
https://spec.openapis.org/oas/v3.1.0#runtime-expressions
JSON Schem has no way to reference instance data, let alone data relating to contexts it is unaware of.

How to use Atlassian Document Format in create issue rest api

I am trying to create an issue via Jira API -
{
// other fields is here
description: {
type: "doc",
version: 1,
content: [
{
type: "text",
text: summary
}
}
}
but I get an error - "Operation value must be a string".
so how can I create an issue correctly?
Most likely you're using API version 2 - which accepts text for this field.
However, you're providing value as json (Atlassian Document Format) which is for API version3

Creating a titled Google Sheets results in a "Proto field" error when using the NodeJs client library

I am trying to create a Google Spreadsheet using a NodeJs backend and the Google Sheets v4 API.
I was following the spreadsheets.create tutorial in documentation. However, when I create the file using some specified properties, I always get the following error:
Error: Invalid JSON payload received. Unknown name "title" at 'spreadsheet.properties': Proto field is not repeating, cannot start list.
In the tutorial nothing, is mentioned about a "Proto" field. Is this a bug or am I missing something?
Creating the file does work, if I don't specify properties. However the properties are used to set a name for the file and the sheets, so I do need a way to set this metadata.
Here is the request I am sending with the properties included:
const request = {
auth,
resource: {
properties: {
title: name,
},
sheets: [
{
properties: {
title: 'General',
},
},
],
},
};

sails-rabbitmq adapter integration with mongodb issue

I have setup a sailsjs project and trying to access rabbitmq using sails-rabbitmq adapter. I have followed https://www.npmjs.com/package/sails-rabbitmq .
I want to use mongodb with rabbitmq. problem is when i 'sails lift' i get this error.
error: A hook (orm) failed to load!
error: Error: One of your models (message) refers to multiple datastores.
Please set its configured datastore to a string instead of an array in its model definition (.connection) or the app-wide default (sails.config.models.connection)
(this is conventionally set in your config/models.js file, or as part of your app's environment-specific config).
at constructError (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\lib\construct-error.js:57:13)
at validateModelDef (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\lib\validate-model-def.js:97:11)
at C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\lib\initialize.js:218:36
at arrayEach (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\lodash\index.js:1289:13)
at Function.<anonymous> (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\lodash\index.js:3345:13)
at Array.async.auto._normalizeModelDefs (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\lib\initialize.js:216:11)
at listener (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\node_modules\async\lib\async.js:605:42)
at C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\node_modules\async\lib\async.js:544:17
at _arrayEach (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\node_modules\async\lib\async.js:85:13)
at Immediate.taskComplete (C:\Users\demoapp\AppData\Roaming\npm\node_modules\sails\node_modules\sails-hook-orm\node_modules\async\lib\async.js:543:13)
at processImmediate [as _immediateCallback] (timers.js:383:17)
I have > connection: [ 'rabbitCluster', 'regularMongo' ]
in my Message model. regularMongo is mongodb connection. Please let me know what other configuration i am missing.
With following config I do not see any error. In sails.config.models set
module.exports.models = {
connection: 'someMongodbServer',
migrate: 'safe'
};
in Message.js set
module.exports = {
connection: [ 'rabbitCluster', 'someMongodbServer' ],
routingKey: [ 'parentMessage' ],
attributes: {
title: 'string',
body: 'string',
parentMessage: {
model: 'message'
}
}
};

Sencha touch 2 - show response (JSON string) on proxy loading

Is there a way to output the json-string read by my store in sencha touch 2?
My store is not reading the records so I'm trying to see where went wrong.
My store is defined as follows:
Ext.define("NotesApp.store.Online", {
extend: "Ext.data.Store",
config: {
model: 'NotesApp.model.Note',
storeId: 'Online',
proxy: {
type: 'jsonp',
url: 'http://xxxxxx.com/qa.php',
reader: {
type: 'json',
rootProperty: 'results'
}
},
autoLoad: false,
listeners: {
load: function() {
console.log("updating");
// Clear proxy from offline store
Ext.getStore('Notes').getProxy().clear();
console.log("updating1");
// Loop through records and fill the offline store
this.each(function(record) {
console.log("updating2");
Ext.getStore('Notes').add(record.data);
});
// Sync the offline store
Ext.getStore('Notes').sync();
console.log("updating3");
// Remove data from online store
this.removeAll();
console.log("updated");
}
},
fields: [
{
name: 'id'
},
{
name: 'dateCreated'
},
{
name: 'question'
},
{
name: 'answer'
},
{
name: 'type'
},
{
name: 'author'
}
]
}
});
you may get all the data returned by the server through the proxy, like this:
store.getProxy().getReader().rawData
You can get all the data (javascript objects) returned by the server through the proxy as lasaro suggests:
store.getProxy().getReader().rawData
To get the JSON string of the raw data (the reader should be a JSON reader) you can do:
Ext.encode(store.getProxy().getReader().rawData)
//or if you don't like 'shorthands':
Ext.JSON.encode(store.getProxy().getReader().rawData)
You can also get it by handling the store load event:
// add this in the store config
listeners: {
load: function(store, records, successful, operation, eOpts) {
operation.getResponse().responseText
}
}
As far as I know, there's no way to explicitly observe your response results if you are using a configured proxy (It's obviously easy if you manually send a Ext.Ajax.request or Ext.JsonP.request).
However, you can still watch your results from your browser's developer tools.
For Google Chrome:
When you start your application and assume that your request is completed. Switch to Network tab. The hightlighted link on the left-side panel is the API url from which I fetched data. And on the right panel, choose Response. The response result will appear there. If you have nothing, it's likely that you've triggered a bad request.
Hope this helps.
Your response json should be in following format in Ajax request
{results:[{"id":"1", "name":"note 1"},{"id":"2", "name":"note 2"},{"id":"3", "name":"note 3"}]}
id and name are properties of your model NOte.
For jsonp,
in your server side, get value from 'callback'. that value contains a name of callback method. Then concat that method name to your result string and write the response.
Then the json string should be in following format
callbackmethod({results:[{"id":"1", "name":"note 1"},{"id":"2", "name":"note 2"},{"id":"3", "name":"note 3"}]});