Skip to content

Commit

Permalink
update @requires test to verify the functionality
Browse files Browse the repository at this point in the history
Updating `users` and `products` subgraph schemas to allow for testing the support of `@requires` functionality in the implementing subgraph. This is a breaking change as we modify the schema so all the existing implementations will be impacted.

Changes:
* `users` subgraph
```graphql
type User @key(fields:"email") {
  email:ID!
  name: String
  totalProductsCreated: Int
  yearsOfEmployment: Int! # <-- new field
}
```
* `products` subgraph
```graphql
extend type User @key(fields: "email") {
  averageProductsCreatedPerYear: Int @requires(fields: "yearsOfEmployment") # <-- test `@requires` functionality
  email: ID! @external
  name: String @OverRide(from: "users")
  totalProductsCreated: Int @external
  yearsOfEmployment: Int! @external # <-- field from the users subgraph used by @requires
}
```

Updated implementations:

- [x] apollo-server
- [x] federation-jvm
- [x] graphql-kotlin

Related Issues:

* resolves #128
  • Loading branch information
dariuszkuc committed Aug 4, 2022
1 parent 971ff00 commit 6adf888
Show file tree
Hide file tree
Showing 12 changed files with 42 additions and 19 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ type User @key(fields: "email") {
email: ID!
name: String
totalProductsCreated: Int
yearsOfEmployment: Int!
}
```

Expand Down Expand Up @@ -244,9 +245,11 @@ extend type Query {
}

extend type User @key(fields: "email") {
averageProductsCreatedPerYear: Int @requires(fields: "yearsOfEmployment")
email: ID! @external
name: String @override(from: "users")
totalProductsCreated: Int @external
yearsOfEmployment: Int! @external
}
```

Expand Down Expand Up @@ -279,14 +282,14 @@ query ($representations: [_Any!]!) {

- `@key` and `_entities` - multiple `@key` definitions, multiple-fields `@key` and a complex fields `@key`.
- `@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 tested through a query covering [Product.delivery](http://product.delivery) where the library implementors `dimensions { size weight }` will need to be an expected `{ size: "1", weight: 1 }` to pass. Example query that will be sent directly to `products` subgraph.
- - 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.

```graphql
query ($id: ID!) {
product(id: $id) {
dimensions {
size
weight
createdBy {
averageProductsCreatedPerYear
email
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions implementations/_template_hosted_/products.graphql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"])
import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible", "@requires"])

directive @override(from: String!) on FIELD_DEFINITION

Expand Down Expand Up @@ -29,7 +29,9 @@ extend type Query {
}

extend type User @key(fields: "email") {
averageProductsCreatedPerYear: Int @requires(fields: "yearsOfEmployment")
email: ID! @external
name: String @shareable @override(from: "users")
name: String @override(from: "users")
totalProductsCreated: Int @external
yearsOfEmployment: Int! @external
}
6 changes: 4 additions & 2 deletions implementations/_template_library_/products.graphql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"])
import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible", "@requires"])

directive @override(from: String!) on FIELD_DEFINITION

Expand Down Expand Up @@ -29,7 +29,9 @@ extend type Query {
}

extend type User @key(fields: "email") {
averageProductsCreatedPerYear: Int @requires(fields: "yearsOfEmployment")
email: ID! @external
name: String @shareable @override(from: "users")
name: String @override(from: "users")
totalProductsCreated: Int @external
yearsOfEmployment: Int! @external
}
1 change: 1 addition & 0 deletions implementations/apollo-server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ const server = new ApolloServer({
server
.listen({ port })
.then(({ url }) => console.log(`Products subgraph ready at ${url}`));

2 changes: 1 addition & 1 deletion router.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
server:
listen: 0.0.0.0:4000
cors:
allow_credentials: true
allow_credentials: true
4 changes: 2 additions & 2 deletions src/tests/override.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, routerRequest } from "../utils/client";
import { compareSchemas } from "../utils/schemaComparison";
import { stripIgnoredCharacters } from "graphql";

Expand All @@ -15,7 +15,7 @@ describe("@override", () => {
});

it("should return overridden user name", async () => {
const resp = await graphqlRequest(ROUTER_URL, {
const resp = await routerRequest({
query: `
query GetProduct($id: ID!) {
product(id: $id) {
Expand Down
12 changes: 6 additions & 6 deletions src/tests/requires.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { productsRequest } from "../utils/client";
import { routerRequest } from "../utils/client";

test("@requires", async () => {
const resp = await productsRequest({
const resp = await routerRequest({
query: `#graphql
query ($id: ID!) {
product(id: $id) { dimensions { size weight } }
product(id: $id) { createdBy { averageProductsCreatedPerYear email } }
}`,
variables: { id: "apollo-federation" },
});

expect(resp).toMatchObject({
data: {
product: {
dimensions: {
size: "small",
weight: 1,
createdBy: {
averageProductsCreatedPerYear: expect.any(Number),
email: "support@apollographql.com",
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions src/tests/shareable.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, routerRequest } from "../utils/client";
import { compareSchemas } from "../utils/schemaComparison";
import { stripIgnoredCharacters } from "graphql";

Expand All @@ -17,7 +17,7 @@ describe("@shareable", () => {
});

it("should be able to resolve @shareable ProductDimension types", async () => {
const resp = await graphqlRequest(ROUTER_URL, {
const resp = await routerRequest({
query: `
query GetProduct($id: ID!) {
product(id: $id) {
Expand Down
11 changes: 11 additions & 0 deletions src/utils/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ export async function graphqlRequest(
return resp.text();
}

export function routerRequest(
req: {
query: string;
variables?: { [key: string]: any };
operationName?: string;
},
headers?: { [key: string]: any }
) {
return graphqlRequest(ROUTER_URL, req, headers);
}

export function productsRequest(
req: {
query: string;
Expand Down
1 change: 1 addition & 0 deletions subgraphs/users/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const users = [
email: "support@apollographql.com",
name: "Apollo Studio Support",
totalProductsCreated: 4,
yearsOfEmployment: 4
},
];

Expand Down
1 change: 1 addition & 0 deletions subgraphs/users/users.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ type User @key(fields:"email") {
email:ID!
name: String
totalProductsCreated: Int
yearsOfEmployment: Int!
}
2 changes: 2 additions & 0 deletions supergraph.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ type User
@join__type(graph: PRODUCTS, key: "email", extension: true)
@join__type(graph: USERS, key: "email")
{
averageProductsCreatedPerYear: Int @join__field(graph: PRODUCTS, requires: "yearsOfEmployment")
email: ID!
name: String @join__field(graph: PRODUCTS, override: "users")
totalProductsCreated: Int @join__field(graph: PRODUCTS, external: true) @join__field(graph: USERS)
yearsOfEmployment: Int! @join__field(graph: PRODUCTS, external: true) @join__field(graph: USERS)
}

0 comments on commit 6adf888

Please sign in to comment.