Skip to content

Commit 8bccd9a

Browse files
authored
fix(omnigraph/oas): handle discriminator mapping keys correctly even … (#7443)
* fix(omnigraph/oas): handle discriminator mapping keys correctly even if they are not valid per GQL spec * For transport, it is not breaking * Update snapshots
1 parent ab49b5b commit 8bccd9a

16 files changed

+352
-63
lines changed

.changeset/perfect-zoos-notice.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
'@omnigraph/json-schema': minor
3+
'@omnigraph/openapi': minor
4+
'@graphql-mesh/transport-rest': patch
5+
---
6+
7+
POSSIBLE BREAKING CHANGE WARNING:
8+
This change is breaking for OpenAPI schemas that have discriminator mapping.
9+
It fixes a bug when you have keys in the discriminator mapping that are invalid per GraphQL spec.
10+
Now in the artifacts `@discriminator` directive's `mapping` argument is `[String!]!` instead of `ObjMap`.
11+
You should make sure both the consumer and the producer of the artifacts are updated to this version.
12+
13+
```yaml
14+
discriminator:
15+
propertyName: petType
16+
mapping:
17+
"pet-cat": '#/components/schemas/Cat'
18+
"pet-dog": '#/components/schemas/Dog'
19+
```
20+
21+
This OpenAPI used to be translated into;
22+
23+
```graphql
24+
@directive(mapping: { "pet-cat": "#/components/schemas/Cat", "pet-dog": "#/components/schemas/Dog" })
25+
```
26+
27+
But this is invalid in GraphQL spec, so now it's translated into;
28+
29+
```graphql
30+
@directive(mapping: [["pet-cat", "#/components/schemas/Cat"], ["pet-dog", "#/components/schemas/Dog"]])
31+
```

packages/loaders/json-schema/src/directives.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const DiscriminatorDirective = new GraphQLDirective({
3737
type: GraphQLString,
3838
},
3939
mapping: {
40-
type: ObjMapScalar,
40+
type: new GraphQLList(new GraphQLList(GraphQLString)),
4141
},
4242
},
4343
});

packages/loaders/json-schema/src/getComposerFromJSONSchema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ export function getComposerFromJSONSchema({
869869
const discriminatorArgs: {
870870
subgraph: string;
871871
field: string;
872-
mapping?: Record<string, string>;
872+
mapping?: [string, string][];
873873
} = {
874874
subgraph: subgraphName,
875875
field: subSchemaOnly.discriminator.propertyName,
@@ -880,7 +880,7 @@ export function getComposerFromJSONSchema({
880880
const discType = subSchemaOnly.discriminatorMapping[discriminatorValue];
881881
mappingByName[discriminatorValue] = discType.output.getTypeName();
882882
}
883-
discriminatorArgs.mapping = mappingByName;
883+
discriminatorArgs.mapping = Object.entries(mappingByName);
884884
}
885885
(subSchemaAndTypeComposers.output as InterfaceTypeComposer).setDirectiveByName(
886886
'discriminator',

packages/loaders/openapi/tests/__snapshots__/allof-properties.test.ts.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ exports[`Merge attributes correctly in allOfs should generate correct schema: al
66
mutation: Mutation
77
}
88
9-
directive @discriminator(subgraph: String, field: String, mapping: ObjMap) on INTERFACE | UNION
9+
directive @discriminator(subgraph: String, field: String, mapping: [[String]]) on INTERFACE | UNION
1010
1111
directive @length(subgraph: String, min: Int, max: Int) on SCALAR
1212
@@ -46,8 +46,6 @@ type Mutation {
4646
"""Represents empty values"""
4747
scalar Void
4848
49-
scalar ObjMap
50-
5149
enum HTTPMethod {
5250
GET
5351
HEAD
@@ -58,5 +56,7 @@ enum HTTPMethod {
5856
OPTIONS
5957
TRACE
6058
PATCH
61-
}"
59+
}
60+
61+
scalar ObjMap"
6262
`;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Discriminator with invalid key in the mapping should generate correct schema: discriminator-invalid-key 1`] = `
4+
"schema @transport(subgraph: "test", kind: "rest", location: "http://localhost") {
5+
query: Query
6+
}
7+
8+
directive @discriminator(subgraph: String, field: String, mapping: [[String]]) on INTERFACE | UNION
9+
10+
directive @httpOperation(subgraph: String, path: String, operationSpecificHeaders: [[String]], httpMethod: HTTPMethod, isBinary: Boolean, requestBaseBody: ObjMap, queryParamArgMap: ObjMap, queryStringOptionsByParam: ObjMap, jsonApiFields: Boolean, queryStringOptions: ObjMap) on FIELD_DEFINITION
11+
12+
directive @transport(subgraph: String, kind: String, location: String, headers: [[String]], queryStringOptions: ObjMap, queryParams: [[String]]) repeatable on SCHEMA
13+
14+
type Cat implements Pet {
15+
color: String
16+
name: String!
17+
petType: String
18+
}
19+
20+
interface Pet @discriminator(subgraph: "test", field: "petType", mapping: [["pet-cat", "Cat"], ["pet-dog", "Dog"]]) {
21+
name: String!
22+
petType: String
23+
}
24+
25+
type Dog implements Pet {
26+
age: String
27+
name: String!
28+
petType: String
29+
}
30+
31+
type Query {
32+
pets_by_id(id: String!): Pet @httpOperation(subgraph: "test", path: "/pets/{args.id}", operationSpecificHeaders: [["accept", "application/json"]], httpMethod: GET)
33+
}
34+
35+
enum HTTPMethod {
36+
GET
37+
HEAD
38+
POST
39+
PUT
40+
DELETE
41+
CONNECT
42+
OPTIONS
43+
TRACE
44+
PATCH
45+
}
46+
47+
scalar ObjMap"
48+
`;

packages/loaders/openapi/tests/__snapshots__/discriminator.test.ts.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ exports[`Discriminator Mapping should generate correct schema: discriminator-map
55
query: Query
66
}
77
8-
directive @discriminator(subgraph: String, field: String, mapping: ObjMap) on INTERFACE | UNION
8+
directive @discriminator(subgraph: String, field: String, mapping: [[String]]) on INTERFACE | UNION
99
1010
directive @httpOperation(subgraph: String, path: String, operationSpecificHeaders: [[String]], httpMethod: HTTPMethod, isBinary: Boolean, requestBaseBody: ObjMap, queryParamArgMap: ObjMap, queryStringOptionsByParam: ObjMap, jsonApiFields: Boolean, queryStringOptions: ObjMap) on FIELD_DEFINITION
1111
@@ -15,7 +15,7 @@ type Query {
1515
pets_by_id(id: String!): Pet @httpOperation(subgraph: "test", path: "/pets/{args.id}", operationSpecificHeaders: [["accept", "application/json"]], httpMethod: GET)
1616
}
1717
18-
union Pet @discriminator(subgraph: "test", field: "petType", mapping: "{\\"Dog\\":\\"DogDifferent\\",\\"Cat\\":\\"Cat\\"}") = Cat | DogDifferent
18+
union Pet @discriminator(subgraph: "test", field: "petType", mapping: [["Dog", "DogDifferent"], ["Cat", "Cat"]]) = Cat | DogDifferent
1919
2020
type Cat {
2121
petType: String
@@ -27,8 +27,6 @@ type DogDifferent {
2727
dog_exclusive: String
2828
}
2929
30-
scalar ObjMap
31-
3230
enum HTTPMethod {
3331
GET
3432
HEAD
@@ -39,5 +37,7 @@ enum HTTPMethod {
3937
OPTIONS
4038
TRACE
4139
PATCH
42-
}"
40+
}
41+
42+
scalar ObjMap"
4343
`;

packages/loaders/openapi/tests/__snapshots__/pet-union.test.ts.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ exports[`Pet should generate the correct schema: schema 1`] = `
55
query: Query
66
}
77
8-
directive @discriminator(subgraph: String, field: String, mapping: ObjMap) on INTERFACE | UNION
8+
directive @discriminator(subgraph: String, field: String, mapping: [[String]]) on INTERFACE | UNION
99
1010
directive @statusCodeTypeName(subgraph: String, typeName: String, statusCode: ID) repeatable on UNION
1111
@@ -19,7 +19,7 @@ type Dog implements Pet {
1919
petType: String
2020
}
2121
22-
interface Pet @discriminator(subgraph: "Pet", field: "petType", mapping: "{\\"Dog\\":\\"Dog\\",\\"Cat\\":\\"Cat\\"}") {
22+
interface Pet @discriminator(subgraph: "Pet", field: "petType", mapping: [["Dog", "Dog"], ["Cat", "Cat"]]) {
2323
name: String!
2424
petType: String
2525
}
@@ -46,8 +46,6 @@ The \`JSON\` scalar type represents JSON values as specified by [ECMA-404](http:
4646
"""
4747
scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
4848
49-
scalar ObjMap
50-
5149
enum HTTPMethod {
5250
GET
5351
HEAD
@@ -58,5 +56,7 @@ enum HTTPMethod {
5856
OPTIONS
5957
TRACE
6058
PATCH
61-
}"
59+
}
60+
61+
scalar ObjMap"
6262
`;

packages/loaders/openapi/tests/__snapshots__/pet.test.ts.snap

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ exports[`Pet should generate the correct schema: schema 1`] = `
55
query: Query
66
}
77
8-
directive @discriminator(subgraph: String, field: String, mapping: ObjMap) on INTERFACE | UNION
8+
directive @discriminator(subgraph: String, field: String, mapping: [[String]]) on INTERFACE | UNION
99
1010
directive @httpOperation(subgraph: String, path: String, operationSpecificHeaders: [[String]], httpMethod: HTTPMethod, isBinary: Boolean, requestBaseBody: ObjMap, queryParamArgMap: ObjMap, queryStringOptionsByParam: ObjMap, jsonApiFields: Boolean, queryStringOptions: ObjMap) on FIELD_DEFINITION
1111
@@ -17,7 +17,7 @@ type Dog implements Pet {
1717
petType: String
1818
}
1919
20-
interface Pet @discriminator(subgraph: "Pet", field: "petType", mapping: "{\\"Dog\\":\\"Dog\\",\\"Cat\\":\\"Cat\\"}") {
20+
interface Pet @discriminator(subgraph: "Pet", field: "petType", mapping: [["Dog", "Dog"], ["Cat", "Cat"]]) {
2121
name: String!
2222
petType: String
2323
}
@@ -32,8 +32,6 @@ type Query {
3232
pets_by_id(id: String!): Pet @httpOperation(subgraph: "Pet", path: "/pets/{args.id}", operationSpecificHeaders: [["accept", "application/json"]], httpMethod: GET)
3333
}
3434
35-
scalar ObjMap
36-
3735
enum HTTPMethod {
3836
GET
3937
HEAD
@@ -44,5 +42,7 @@ enum HTTPMethod {
4442
OPTIONS
4543
TRACE
4644
PATCH
47-
}"
45+
}
46+
47+
scalar ObjMap"
4848
`;

packages/loaders/openapi/tests/__snapshots__/required-allof.test.ts.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ exports[`Merge required attributes correctly in allOfs should generate correct s
55
query: Query
66
}
77
8-
directive @discriminator(subgraph: String, field: String, mapping: ObjMap) on INTERFACE | UNION
8+
directive @discriminator(subgraph: String, field: String, mapping: [[String]]) on INTERFACE | UNION
99
1010
directive @length(subgraph: String, min: Int, max: Int) on SCALAR
1111
@@ -46,8 +46,6 @@ type Query {
4646
getEditor: Editor @httpOperation(subgraph: "test", path: "/editor", operationSpecificHeaders: [["accept", "application/json"]], httpMethod: GET)
4747
}
4848
49-
scalar ObjMap
50-
5149
enum HTTPMethod {
5250
GET
5351
HEAD
@@ -58,5 +56,7 @@ enum HTTPMethod {
5856
OPTIONS
5957
TRACE
6058
PATCH
61-
}"
59+
}
60+
61+
scalar ObjMap"
6262
`;

0 commit comments

Comments
 (0)