Allow swagger query param to be array of strings or integers - node.js

In building a rest api using swagger2 (openAPI), I want to allow a query param station_id to support the following:
?station_id=23 (returns station 23)
?station_id=23,45 (returns stations 23 and 45)
?station_id=[3:14] (returns stations 3 through 14)
?station_id=100% (%s act as wildcards so returns things like 1001,
10049, etc..)
I use the following swagger definition (an array of strings) as an attempt to accomplish this:
parameters:
- name: station_id
in: query
description: filter stations by station_id
required: false
type: array
items:
type: string
With this definition all of the previous examples work except ?station_id=23 as swagger validation fails with the following message:
{
"message": "Validation errors",
"errors": [
{
"code": "INVALID_REQUEST_PARAMETER",
"errors": [
{
"code": "INVALID_TYPE",
"params": [
"array",
"integer"
],
"message": "Expected type array but found type integer",
"path": [],
"description": "filter stations by station_id"
}
],
"in": "query",
"message": "Invalid parameter (station_id): Value failed JSON Schema validation",
"name": "station_id",
"path": [
"paths",
"/stations",
"get",
"parameters",
"0"
]
}
]
}
note that if I quote the station_id like ?station_id='23' validation passes and I get a correct response. But I'd really prefer not to have to use quotes. Something like a union type would help solve this, but as far as I can tell they aren't supported.
I also have another endpoint /stations/{id} that can handle the case of a single id, but still have many other (non primary key) numerical fields that I want to filter on in the way specified above. For instance station_latitude.
Any ideas to a work around - maybe I can use pattern (regex) somehow? If there is no workaround in the swagger definition is there a way to tweak or bypass the validator? This is a nodejs project using swagger-node I've upgraded the version of swagger-express-mw to 0.7.0.

I think what you'd need is the anyOf or oneOf keyword similar to the one provided by JSON Schema so that you could define the type of your station_id parameter to be either a number or a string. anyOf and oneOf are supported in OpenAPI 3.0 but not in 2.0. An OpenAPI 3.0 definition would look like this:
openapi: 3.0.0
...
paths:
/something:
get:
parameters:
- in: query
name: station_id
required: true
explode: false
schema:
oneOf:
- type: integer # Optional? Array is supposed to cover the use case with a single number
example: 23
- type: array
items:
type: integer
minItems: 1
example: [23, 45]
- type: string
oneOf:
- pattern: '^\[\d+:\d+]$'
- pattern: '^\d+%$'
# or using a single pattern
# pattern: '^(\[\d+:\d+])|(\d+%)$'
example: '[3:14]'
As an alternative, perhaps you could add sortBy, skip, and limit parameters to allow you to keep the type uniform. For example: ?sortBy=station_id&skip=10&limit=10 would retrieve only stations 10 - 20.

Related

How to check UUID using regular expressions?

In order to make validation over a api, i'm send companyId as UUID like: 71158c1a-56fd-4dd4-8e7f-fb95711a41de
To have this validation I used jsonschema with the following patterns (test all 3 of them):
/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$
/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi
[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}
jsonschema:
companyId: {
type: "string",
default: "",
title: "The companyId Schema",
pattern: "/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$",
examples: ["71158c1a-56fd-4dd4-8e7f-fb95711a41de"],
},
For some reason the validation returned me errors:
path: Ä 'companyId' Å,
property: 'instance.companyId',
message: 'does not match pattern "/ÜÄ0-9a-fA-FÅä8åÖÖb-Ä0-9a-fA-FÅä4åÖÖb-Ä0-9a-fA-FÅä4åÖÖb-Ä0-9a-fA-FÅä4åÖÖb-Ä0-9a-fA-FÅä12å$"',
schema: ä
type: 'string',
default: '',
title: 'The companyId Schema',
pattern: '/ÜÄ0-9a-fA-FÅä8åÖb-Ä0-9a-fA-FÅä4åÖb-Ä0-9a-fA-FÅä4åÖb-Ä0-9a-fA-FÅä4åÖb-Ä0-9a-fA-FÅä12å$',
examples: ÄArrayÅ
å,
instance: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
name: 'pattern',
argument: '/ÜÄ0-9a-fA-FÅä8åÖb-Ä0-9a-fA-FÅä4åÖb-Ä0-9a-fA-FÅä4åÖb-Ä0-9a-fA-FÅä4åÖb-Ä0-9a-fA-FÅä12å$',
stack: 'instance.companyId does not match pattern "/ÜÄ0-9a-fA-FÅä8åÖÖb-Ä0-9a-fA-FÅä4åÖÖb-Ä0-9a-fA-FÅä4åÖÖb-Ä0-9a-fA-FÅä4åÖÖb-Ä0-9a-fA-FÅä12å$"'
å,
Also im getting these cyrillic letters, maybe this is the reason?
The latest version of JSON Schema supports the uuid format (you may need to explicitly turn on format validation in the implementation, as by default it is supposed to be annotation-only):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"format": "uuid",
}
Also, you have a stray / in your pattern before the ^ anchor, so your pattern will never match.

Azure API Management does not validate required properties in payload

We are using Azure API Management in a project, and we want APIM to be our shield against invalid requests. Since we've already specified what a valid request looks like in our OpenAPI specification and uploaded that to APIM, it seems like a reasonable assumption.
I have specified a component in our OpenAPI (version 3.0.1) specification like this:
TemperatureRange:
description: Defines a desired temperature range
required:
- min
- max
properties:
min:
type: number
max:
type: number
When uploaded to APIM the schema looks fine:
{
"required": [
"min",
"max"
],
"properties": {
"min": {
"type": "number"
},
"max": {
"type": "number"
}
},
"description": "Defines a desired temperature range"
}
However, when I call an API that uses this definition, I can leave out properties even though they are marked as required.
The payload I sent looks like this, leaving out the required max property:
[{
"someProperty": "someValue",
"temperatureRange": {
"min": -18,
}
}]
I can't find any documentation on this and it isn't mentioned in any restrictions. What is the intended behavior?
Looks like this is functionality that has been requested but has not been implemented: https://feedback.azure.com/forums/248703-api-management/suggestions/17369008-schema-validation-in-apim

ARANGODB ensureIndex to create full text not working

I have events collection inserted with a below record in ARANGODB. ( I am new to Arango )
INSERT {
"source": "ABC",
"target": "ZYX",
"tranno": "ABCDEF",
"type": "REST",
"attributes" : { "myID" : "12345"}
} INTO events
But trying to create full text index on attributes, resulting in error as given below. It would be great if you could help with this.
events.createIndex ({ type: "fulltext", fields: [ "attributes" ], minLength: 3 })
Query: AQL: syntax error, unexpected identifier near 'events.createIndex ({ type: "ful...' at position 1:1 (while parsing)
Unlike SQL, AQL is a language used for data selection and data manipulation.
It is not a data definition language, so you can't use AQL to create indexes.
In order to create an index, please use ArangoDB's web interface (Collections => target collection => Indexes => "+" icon) or the ArangoShell. The ArangoShell is a separate executable that is shipped with all ArangoDB packages.
In the ArangoShell you can use the command
db.events.createIndex ({ type: "fulltext", fields: [ "attributes" ], minLength: 3 })
to create the index.

How to do field mapping in azure search for complex json objects for example nested array

I have following problem
I have a field mapping update to an index .Payload is complex where
I have:
{
"type": "abc",
"Party": [{
"Type": "abc",
"Id": "123",
"Name": "manasa",
"Phone": [{
"Type": "Office",
"Number": "12345"
}]
}]
}
And now I want to create a field for an index. The field name is phonenumber of type Collection(Edm.String)
where mapping is
{
"sourceFieldName" : "/Party/Phone/Number",
"targetFieldName" : "phonenumber",
"mappingFunction" : { "name" : "jsonArrayToStringCollection" }
}
In http post body
But still after indexing i get phone number result as null.That means the mapping went wrong.If you see the phone number in source json, it is inside a json array and it itself is an array and result needs to get stored inside a collection of a string.Is it possible how can I achieve this?
If this is not possible I atleast want field mapping till phone array ie., /Party/Phone/
If i index complete party array as a text, I get an error while running the index saying:
"Field 'partydetails' contains a term that is too large to process. The max length for UTF-8 encoded terms is 32766 bytes. The most likely cause of this error is that filtering, sorting, and/or faceting are enabled on this field, which causes the entire field value to be indexed as a single term. Please avoid the use of these options for large fields."
Can someone please help!
If party would have been a Json object than an array and phone would have been only a string array for example
{
"type": "abc",
"Party": {
"Type": "abc",
"Id": "123",
"Name": "manasa",
"Phone": [{
"12345",
"23463"
}]
}
}
Then I could have mapped
{
"sourceFieldName" : "Party/Phonenumber",
"targetFieldName" : "phonenumbers",
"mappingFunction" : { "name" : "jsonArrayToStringCollection" }
}
It map as collection of type odata EDM.string.
So to put this in better and straight forward way,
Either transform your json to something flatter (the example that I
gave above) or
Use the proper index incase if you know before inhand as
#Luis Cabrera said,
“sourceFieldName”: “/Party/0/Phone/0/Type
It is a limitation from azure search side.
Note that Party and Phone are arrays, so the field mapping you mention won't work.
You will need to index into the specific element. For example:
{
"sourceFieldName": "/Party/0/Phone/0/Type",
"targetFieldName": "firstPhoneNumberTypeOfFirstParty"
}
You may want to give that a shot.
Thanks!
Luis Cabrera | Program Manager | Azure Search

Mongoose query altering object order

I have a query that is generated in my Node backend - if I log it out and run it in Mongo shell then all is fine, however, if I use mongoose to do Model.find(query), then some strange property re-ordering takes place and the query breaks.
The query in question is:
{
"attributes": {
"$all": [
{
"attribute": "an id",
"value": "a value",
"deletedOn": null
},
{
"attribute": "an id again",
"value": "a value",
"deletedOn": null
}
]
}
}
However, the output from mongoose debug is:
users.find({
attributes: {
'$all': [
{
deletedOn: null,
attribute: 'an id',
value: 'a value'
},
{
deletedOn: null,
attribute: 'an id again',
value: 'a value'
}
]
}
},
{ fields: {} }
)
The only change is the shifting of the deletedOn field from last position to first position in the object. This means the query returns no results.
Are there any solutions to this issue?
Object properties in JavaScript are not ordered. You cannot ensure the order of properties on a JavaScript object and different implementations may order them differently. See this answer on a related question for some other info.
The essential key is that from the spec (ECMAScript) we get: "An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method."
There is no "solution", because this is expected behavior. So the real question is, why does the order matter to you? What are you trying to do?
Adding on the previous answer, if order is important to you, you should use array instead of objects.
for example:
"$all": [
[
{"attribute": "an id"},
{"value": "a value"},
{"deletedOn": null},
],
...etc.
]

Resources