Skip to content

Commit

Permalink
update product subgraph test schema with additional @key test cases
Browse files Browse the repository at this point in the history
Update `product` subgraph with additional entites to separate testing for various `@key` test cases. Previously we were testing single entity that was supposed to define multiple `@key` directives. This was problematic as not all implementations support repeatable directives and we never checked whether given `@key` test case was actually present in the schema (test was executing `_entities` query only).

Schema changes (existing fields and types are omitted for clarity):

```graphql
type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") {
  # new field
  research: [ProductResearch!]!
}

type DeprecatedProduct @key(fields: "sku package") {
  sku: String!
  package: String!
  reason: String
  createdBy: User
}

type ProductResearch @key(fields: "study { caseNumber }") {
  study: CaseStudy!
  outcome: String
}

type CaseStudy {
  caseNumber: ID!
  description: String
}

extend type Query {
  # new query
  deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
}
```

Update `@key` tests cases to verify:

* single field `@key` functionality against `User` type
* multiple field `@key` functionality against `DeprecatedProduct` type
* composite object `@key` functionality against `ProductResearch` type
* repeatable `@key` functionality against `Product` type (this test combines old tests into a single one)

Related Issues:

* resolves apollographql#144
* resolves apollographql#149
  • Loading branch information
dariuszkuc committed Aug 11, 2022
1 parent d189a9a commit 1172cb5
Show file tree
Hide file tree
Showing 9 changed files with 432 additions and 128 deletions.
64 changes: 43 additions & 21 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,47 @@ in your server (it is okay to return hardcoded results, this is what is done in
`apollo-server` and `federation-jvm`).

```javascript
const dimensions = [
const dimension = {
size: "small",
weight: 1,
unit: "kg"
}

const user = {
averageProductsCreatedPerYear: if (totalProductsCreated) {
Math.round(totalProductsCreated / yearsOfEmployment)
} else {
null
},
email: "support@apollographql.com",
name: "Jane Smith",
totalProductsCreated: 1337,
yearsOfEmployment: 10
};

const deprecatedProduct = {
sku: "apollo-federation-v1",
package: "@apollo/federation-v1",
reason: "Migrate to Federation V2",
createdBy: user
};

const productsResearch = [
{
size: "small",
weight: 1,
unit: "kg"
}
]

const users = [
study: {
caseNumber: "1234",
description: "Federation Study"
},
outcome: null
},
{
averageProductsCreatedPerYear: if (totalProductsCreated) {
Math.round(totalProductsCreated / yearsOfEmployment)
} else {
null
study: {
caseNumber: "1235",
description: "Studio Study"
},
email: "support@apollographql.com",
name: "Jane Smith",
totalProductsCreated: 1337,
yearsOfEmployment: 10
outcome: null
},
];
]

const products = [
{
Expand All @@ -120,8 +140,9 @@ const products = [
variation: {
id: "OSS"
},
dimensions: dimensions[0],
createdBy: users[0],
dimensions: dimension,
research: [productsResearch[0]]
createdBy: user,
notes: null
},
{
Expand All @@ -131,8 +152,9 @@ const products = [
variation: {
id: "platform"
},
dimensions: dimensions[0],
createdBy: users[0],
dimensions: dimension,
research: [productsResearch[1]]
createdBy: user,
notes: null
},
];
Expand Down
92 changes: 73 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,34 +206,53 @@ extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.0",
import: [
"@key",
"@shareable",
"@provides",
"@external",
"@tag",
"@extends",
"@external",
"@key",
"@inaccessible",
"@override",
"@inaccessible"
"@provides",
"@requires",
"@shareable",
"@tag"
]
)

type Product
@key(fields: "id")
@key(fields: "sku package")
@key(fields: "sku variation { id }") {
id: ID!
sku: String
package: String
variation: ProductVariation
dimensions: ProductDimension
createdBy: User @provides(fields: "totalProductsCreated")
notes: String @tag(name: "internal")
id: ID!
sku: String
package: String
variation: ProductVariation
dimensions: ProductDimension
createdBy: User @provides(fields: "totalProductsCreated")
notes: String @tag(name: "internal")
research: [ProductResearch!]!
}

type DeprecatedProduct @key(fields: "sku package") {
sku: String!
package: String!
reason: String
createdBy: User
}

type ProductVariation {
id: ID!
}

type ProductResearch @key(fields: "study { caseNumber }") {
study: CaseStudy!
outcome: String
}

type CaseStudy {
caseNumber: ID!
description: String
}

type ProductDimension @shareable {
size: String
weight: Float
Expand All @@ -242,6 +261,7 @@ type ProductDimension @shareable {

extend type Query {
product(id: ID!): Product
deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
}

extend type User @key(fields: "email") {
Expand All @@ -264,13 +284,13 @@ This is a minimum set of functionality to allow for API-side joins and use of en
- `_service` - support a `rover subgraph introspect` command (this is the Apollo Federation equivalent of Introspection for subgraphs)
- executes `query { _service { sdl } }` and verifies the contents of the SDL
- `@key` and `_entities` - support defining a single `@key`
- Below is an example of the single `@key` query that is sent from the graph router to the implementing `products` subgraph (the variables will be changed to test all `@key` definitions):
- Below is an example of the single `@key` query that is sent from the graph router to the implementing `products` subgraph:

```graphql
query ($representations: [_Any!]!) {
_entities(representations: [{ "__typename": "Product", "id": "apollo-federation" }]) {
...on Product {sku package variation { id } dimensions { size weight }
}
query {
_entities(representations: [{ "__typename": "User", "email": "support@apollographql.com" }]) {
...on User { email name }
}
}
}
```
Expand All @@ -280,7 +300,41 @@ query ($representations: [_Any!]!) {

#### Additional functionality to fully support Apollo Federation

- `@key` and `_entities` - multiple `@key` definitions, multiple-fields `@key` and a complex fields `@key`.
- `@key` and `_entities` - multiple `@key` definitions, multiple-fields `@key` and a composite object fields `@key`
- Below is an example of a multiple fields `@key` query that is sent from the graph router to the implementing `products` subgraph:

```graphql
query {
_entities(representations: [{ "__typename": "DeprecatedProduct", "sku": "apollo-federation-v1", "package": "@apollo/federation-v1" }]) {
...on DeprecatedProduct { sku package reason }
}
}
```

- Below is an example of a composite object fields `@key` query that is sent from the graph router to the implementing `products` subgraph:

```graphql
query {
_entities(representations: [{ "__typename": "ProductResearch", "study": { "caseNumber": "1234" } }]) {
...on ProductResearch { study { caseNumber description } }
}
}
```

- Below is an example of a multiple `@key` query that is sent from the graph router to the implementing `products` subgraph:

```graphql
query {
_entities(representations: [
{ "__typename": "Product", "id: "apollo-federation" },
{ "__typename": "Product", "sku": "federation", "package": "@apollo/federation" },
{ "__typename": "Product", "sku": "studio", "variation": { "id": "platform" } }
]) {
...on Product { id sku }
}
}
```
- `@requires` - directive used to provide additional non-key information from one subgraph to the computed fields in another subgraph, should support defining complex fields
- - This will be covered by the subgraph implementors at `Product.createdBy` where they will be expected to provide the `User.averageProductsCreatedPerYear` using `yearsOfEmployment` value provided by the `user` graph and the `totalProductsCreated` value from the implementing `products` subgraph. Example query that will be sent directly to `products` subgraph.
Expand Down
27 changes: 23 additions & 4 deletions implementations/_template_hosted_/products.graphql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible", "@requires"])

directive @override(from: String!) on FIELD_DEFINITION
@link(
url: "https://specs.apollo.dev/federation/v2.0",
import: ["@extends", "@external", "@inaccessible", "@key", "@override", "@provides", "@requires", "@shareable", "@tag"]
)

type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") {
id: ID!
Expand All @@ -12,12 +12,30 @@ type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku va
dimensions: ProductDimension
createdBy: User @provides(fields: "totalProductsCreated")
notes: String @tag(name: "internal")
research: [ProductResearch!]!
}

type DeprecatedProduct @key(fields: "sku package") {
sku: String!
package: String!
reason: String
createdBy: User
}

type ProductVariation {
id: ID!
}

type ProductResearch @key(fields: "study { caseNumber }") {
study: CaseStudy!
outcome: String
}

type CaseStudy {
caseNumber: ID!
description: String
}

type ProductDimension @shareable {
size: String
weight: Float
Expand All @@ -26,6 +44,7 @@ type ProductDimension @shareable {

extend type Query {
product(id: ID!): Product
deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
}

extend type User @key(fields: "email") {
Expand Down
27 changes: 23 additions & 4 deletions implementations/_template_library_/products.graphql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible", "@requires"])

directive @override(from: String!) on FIELD_DEFINITION
@link(
url: "https://specs.apollo.dev/federation/v2.0",
import: ["@extends", "@external", "@inaccessible", "@key", "@override", "@provides", "@requires", "@shareable", "@tag"]
)

type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") {
id: ID!
Expand All @@ -12,12 +12,30 @@ type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku va
dimensions: ProductDimension
createdBy: User @provides(fields: "totalProductsCreated")
notes: String @tag(name: "internal")
research: [ProductResearch!]!
}

type DeprecatedProduct @key(fields: "sku package") {
sku: String!
package: String!
reason: String
createdBy: User
}

type ProductVariation {
id: ID!
}

type ProductResearch @key(fields: "study { caseNumber }") {
study: CaseStudy!
outcome: String
}

type CaseStudy {
caseNumber: ID!
description: String
}

type ProductDimension @shareable {
size: String
weight: Float
Expand All @@ -26,6 +44,7 @@ type ProductDimension @shareable {

extend type Query {
product(id: ID!): Product
deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
}

extend type User @key(fields: "email") {
Expand Down
1 change: 1 addition & 0 deletions src/testRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const TESTS = [
{ assertion: "@key single", column: "@key (single)", fedVersion: 1, required: true },
{ assertion: "@key multiple", column: "@key (multi)", fedVersion: 1, required: false },
{ assertion: "@key composite", column: "@key (composite)", fedVersion: 1, required: false },
{ assertion: "repeatable @key", column: "repeatable @key", fedVersion: 1, required: false },
{ assertion: "@requires", column: "@requires", fedVersion: 1, required: false },
{ assertion: "@provides", column: "@provides", fedVersion: 1, required: false },
{ assertion: "ftv1", column: "@ftv1", fedVersion: 1, required: false },
Expand Down
5 changes: 2 additions & 3 deletions src/tests/inaccessible.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { productsRequest, graphqlRequest, ROUTER_URL } from "../utils/client";
import { productsRequest } from "../utils/client";
import { stripIgnoredCharacters } from "graphql";

describe("@inaccessible", () => {
Expand All @@ -7,9 +7,8 @@ describe("@inaccessible", () => {
query: "query { _service { sdl } }",
});


const { sdl } = response.data._service;
const normalizedSDL = stripIgnoredCharacters(sdl);
const normalizedSDL = stripIgnoredCharacters(sdl);
expect(normalizedSDL).not.toContain("@federation__inaccessible");
expect(normalizedSDL).toContain("unit:String@inaccessible");
});
Expand Down

0 comments on commit 1172cb5

Please sign in to comment.