OAS3: How to constrain the keys of JSON objects to a particular enum definition? - enums

In JSON, I have an object for which the possible values of the keys are constrained to an enum:
{
"res1" : { ... },
"res2" : { ... },
"res3" : { ... }
}
How do I represent in OAS3 that the key itself must be a member of the following enum?
restriction-types:
enum:
- res1
- res2
- res3
I get the impression that this should be propertyNames from the json schema core definition: https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-00#section-10.3.2.4
The swagger 3.0 documentation says propertyNames is an unsupported keyword. Is this true for the OAS 3.0 specification? https://swagger.io/docs/specification/data-models/keywords

Related

Dynamic field or field of type (Struct, Map, Any) for custom options

Assuming I need to define a custom option for a method, for example:
message MessageBusOptions {
string namespace = 1;
optional string queue = 2;
}
extend google.protobuf.MethodOptions {
optional MessageBusOptions message_bus_options = 50000;
}
So far everything works as expected. I can define my service the following way:
services TestServices {
rpc SendMessage(MessageReq) returns(MessageRes) {
option (message_bus_options) = {
namespace: "abc",
queue: "default"
}
}
}
Now, how I can I add a dynamic field to the MessageBusOptions so that I can provide a dynamic value, for example:
services TestServices {
rpc SendMessage(MessageReq) returns(MessageRes) {
option (message_bus_options) = {
namespace: "abc",
queue: "default",
dynamic_field: {
a: "a",
b: "b"
}
}
}
}
I tried the following types (Map, Any, Struct) but all of them led to this error
Error while parsing option value for "xxx": Message type "xxx" has no field named "xxx".
How can I define such dynamic field in the custom option?

Apollo client's codegen adds unwanted "or null" in my types

Apollo client's codegen adds | null in the generated types, and I don't understand why they are there and how to get rid of them.
I see no reason why the API would return an array of null, so I don't want to check in my code weather the oject is null or not everytime.
Offending generated types from apollo codegen:
export interface MusicGenres_musicGenres {
name: string;
}
export interface MusicGenres {
musicGenres: (MusicGenres_musicGenres | null)[];
^^^^^^
WHY ?
}
My Graphql Schema:
type Query {
musicGenres: [MusicGenre]!
}
type MusicGenre {
id: ID!
name: String!
}
Query in my TypeScript code from which are generated the types:
gql`
query MusicGenres {
musicGenres { name }
}
`
In your schema, you have the following field definition:
musicGenres: [MusicGenre]!
This means that while musicGenres will be a list and will itself never be null, any item in the list could be null. If you want to indicate that all items in the list are also non-nullable, your field definition should instead be:
musicGenres: [MusicGenre!]!
See this post for an extended explanation.

Single value vs Array in GraphQL Enum input types

How do you define an input type that either accepts a single enum value or an array of values in GraphQL?
According to GitHub GraphQL API,
{
securityVulnerabilities(first: 3, ecosystem: RUBYGEMS) {
nodes {
advisory {
description
}
}
}
}
But I think array can be good because user can search across ecosystem.
{
securityVulnerabilities(first: 3, ecosystem: [RUBYGEMS, NPM]) {
nodes {
advisory {
description
}
}
}
}
You can do this by defining the input value as an array [] of your defined Enum, something like:
enum MyEnum {
RUBYGEMS
NPM
}
type Query {
securityVulnerabilities(ecosystem: [MyEnum!]): MyReturnObject
}
And then you can query it like:
{
securityVulnerabilities(ecosystem: [RUBYGEMS, NPM]) {
....
}
}
And it works with both an array or a single value:
{
securityVulnerabilities(ecosystem: RUBYGEMS) {
....
}
}
The GraphQL spec explains the following:
If the value passed as an input to a list type is not a list and not
the null value, then the result of input coercion is a list of size
one [...]

How to pass GraphQLEnumType in mutation as a string value

I have following GraphQLEnumType
const PackagingUnitType = new GraphQLEnumType({
name: 'PackagingUnit',
description: '',
values: {
Carton: { value: 'Carton' },
Stack: { value: 'Stack' },
},
});
On a mutation query if i pass PackagingUnit value as Carton (without quotes) it works. But If i pass as string 'Carton' it throws following error
In field "packagingUnit": Expected type "PackagingUnit", found "Carton"
Is there a way to pass the enum as a string from client side?
EDIT:
I have a form in my front end, where i collect the PackagingUnit type from user along with other fields. PackagingUnit type is represented as a string in front end (not the graphQL Enum type), Since i am not using Apollo Client or Relay, i had to construct the graphQL query string by myself.
Right now i am collecting the form data as JSON and then do JSON.stringify() and then remove the double Quotes on properties to get the final graphQL compatible query.
eg. my form has two fields packagingUnitType (An GraphQLEnumType) and noOfUnits (An GraphQLFloat)
my json structure is
{
packagingUnitType: "Carton",
noOfUnits: 10
}
convert this to string using JSON.stringify()
'{"packagingUnitType":"Carton","noOfUnits":10}'
And then remove the doubleQuotes on properties
{packagingUnitType:"Carton",noOfUnits:10}
Now this can be passed to the graphQL server like
newStackMutation(input: {packagingUnitType:"Carton", noOfUnits:10}) {
...
}
This works only if the enum value does not have any quotes. like below
newStackMutation(input: {packagingUnitType:Carton, noOfUnits:10}) {
...
}
Thanks
GraphQL queries can accept variables. This will be easier for you, as you will not have to do some tricky string-concatenation.
I suppose you use GraphQLHttp - or similar. To send your variables along the query, send a JSON body with a query key and a variables key:
// JSON body
{
"query": "query MyQuery { ... }",
"variables": {
"variable1": ...,
}
}
The query syntax is:
query MyMutation($input: NewStackMutationInput) {
newStackMutation(input: $input) {
...
}
}
And then, you can pass your variable as:
{
"input": {
"packagingUnitType": "Carton",
"noOfUnits": 10
}
}
GraphQL will understand packagingUnitType is an Enum type and will do the conversion for you.

How to return nested objects in GraphQL schema language

I was going through the documentation for GraphQl and realized that the new Schema Langugage supports only default resolvers. Is there a way I can add custom resolvers while using the new Schema Language?
let userObj = {
id: 1,
name: "A",
homeAddress: {
line1: "Line1",
line2: "Line2",
city: "City"
}
};
let schema = buildSchema(`
type Query {
user(id: ID): User
}
type User {
id: ID
name: String
address: String
}
`);
//I would like User.address to be resolved from the fields in the json response eg. address = Line1, Line2, City
This is the schema that I have defined. I would like to add some behavior here that would allow me to parse the address object and return a concatenated string value.
As mentioned by HagaiCo and in this github issue, the right way would be to go with graphql-tools.
It has a function called makeExecutableSchema, which takes a schema and resolve functions, and then returns an executable schema
It seems like you have a confusion in here, since you defined that address is String but you send a dictionary to resolve it.
what you can do, is to define a scalar address type:
scalar AddressType if you use buildSchema and then attach parse functions to it. (or use graphql-tools to do it easily)
or build the type from scratch like shown in the official documentations:
var OddType = new GraphQLScalarType({
name: 'Odd',
serialize: oddValue,
parseValue: oddValue,
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
return oddValue(parseInt(ast.value, 10));
}
return null;
}
});
function oddValue(value) {
return value % 2 === 1 ? value : null;
}
and then you can parse the dictionary into a string (parseValue) and otherwise

Resources