Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supergraph Handler #5744

Merged
merged 9 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/@graphql-mesh_graphql-5744-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@graphql-mesh/graphql": patch
---
dependencies updates:
- Added dependency [`@graphql-tools/federation@^1.1.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/federation/v/1.1.0) (to `dependencies`)
- Removed dependency [`@graphql-tools/wrap@^10.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/wrap/v/10.0.0) (from `dependencies`)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphql-mesh/merger-stitching": patch
---
dependencies updates:
- Removed dependency [`@graphql-tools/stitching-directives@^3.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/stitching-directives/v/3.0.0) (from `dependencies`)
5 changes: 5 additions & 0 deletions .changeset/@graphql-mesh_runtime-5744-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphql-mesh/runtime": patch
---
dependencies updates:
- Removed dependency [`@graphql-tools/batch-execute@^9.0.0` ↗︎](https://www.npmjs.com/package/@graphql-tools/batch-execute/v/9.0.0) (from `dependencies`)
6 changes: 6 additions & 0 deletions .changeset/ninety-llamas-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphql-mesh/merger-stitching': patch
'@graphql-mesh/graphql': patch
---

New strategy to handle Federation
6 changes: 6 additions & 0 deletions .changeset/three-toes-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphql-mesh/supergraph': patch
'@graphql-mesh/types': patch
---

New Supergraph handler
11 changes: 11 additions & 0 deletions examples/federation-example/gateway-supergraph/.meshrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
sources:
- name: Supergraph
handler:
supergraph:
source: ./supergraph.graphql

documents:
- example-query.graphql

serve:
playground: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
fragment User on User {
id
username
name
}

fragment Review on Review {
id
body
}

fragment Product on Product {
inStock
name
price
shippingEstimate
upc
weight
}

query TestQuery {
users {
...User
reviews {
...Review
product {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}
}
topProducts {
...Product
reviews {
...Review
author {
...User
reviews {
...Review
product {
...Product
}
}
}
}
}
}
11 changes: 11 additions & 0 deletions examples/federation-example/gateway-supergraph/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "federation-supergraph-gateway",
"version": "0.0.0",
"license": "MIT",
"private": true,
"dependencies": {
"@graphql-mesh/cli": "0.86.0",
"@graphql-mesh/supergraph": "0.0.0",
"graphql": "16.7.1"
}
}
78 changes: 78 additions & 0 deletions examples/federation-example/gateway-supergraph/supergraph.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
schema
@core(feature: "https://specs.apollo.dev/core/v0.2")
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION) {
query: Query
}

directive @core(as: String, feature: String!, for: core__Purpose) repeatable on SCHEMA

directive @join__field(
graph: join__Graph
provides: join__FieldSet
requires: join__FieldSet
) on FIELD_DEFINITION

directive @join__graph(name: String!, url: String!) on ENUM_VALUE

directive @join__owner(graph: join__Graph!) on INTERFACE | OBJECT

directive @join__type(graph: join__Graph!, key: join__FieldSet) repeatable on INTERFACE | OBJECT

type Product
@join__owner(graph: PRODUCTS)
@join__type(graph: PRODUCTS, key: "upc")
@join__type(graph: INVENTORY, key: "upc")
@join__type(graph: REVIEWS, key: "upc") {
inStock: Boolean @join__field(graph: INVENTORY)
name: String @join__field(graph: PRODUCTS)
price: Int @join__field(graph: PRODUCTS)
reviews: [Review] @join__field(graph: REVIEWS)
shippingEstimate: Int @join__field(graph: INVENTORY, requires: "price weight")
upc: String! @join__field(graph: PRODUCTS)
weight: Int @join__field(graph: PRODUCTS)
}

type Query {
me: User @join__field(graph: ACCOUNTS)
topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCTS)
user(id: ID!): User @join__field(graph: ACCOUNTS)
users: [User] @join__field(graph: ACCOUNTS)
}

type Review @join__owner(graph: REVIEWS) @join__type(graph: REVIEWS, key: "id") {
author: User @join__field(graph: REVIEWS, provides: "username")
body: String @join__field(graph: REVIEWS)
id: ID! @join__field(graph: REVIEWS)
product: Product @join__field(graph: REVIEWS)
}

type User
@join__owner(graph: ACCOUNTS)
@join__type(graph: ACCOUNTS, key: "id")
@join__type(graph: REVIEWS, key: "id") {
id: ID! @join__field(graph: ACCOUNTS)
name: String @join__field(graph: ACCOUNTS)
reviews: [Review] @join__field(graph: REVIEWS)
username: String @join__field(graph: ACCOUNTS)
}

enum core__Purpose {
"""
`EXECUTION` features provide metadata necessary to for operation execution.
"""
EXECUTION

"""
`SECURITY` features provide metadata necessary to securely resolve fields.
"""
SECURITY
}

scalar join__FieldSet

enum join__Graph {
ACCOUNTS @join__graph(name: "accounts", url: "http://localhost:9880/graphql")
INVENTORY @join__graph(name: "inventory", url: "http://localhost:9872/graphql")
PRODUCTS @join__graph(name: "products", url: "http://localhost:9873/graphql")
REVIEWS @join__graph(name: "reviews", url: "http://localhost:9874/graphql")
}
17 changes: 17 additions & 0 deletions examples/federation-example/gateway-supergraph/supergraph.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
subgraphs:
accounts:
routing_url: http://localhost:9880/graphql
schema:
file: ../services/accounts-subgraph/typeDefs.graphql
reviews:
routing_url: http://localhost:9874/graphql
schema:
file: ../services/reviews/typeDefs.graphql
products:
routing_url: http://localhost:9873/graphql
schema:
file: ../services/products/typeDefs.graphql
inventory:
routing_url: http://localhost:9872/graphql
schema:
file: ../services/inventory/typeDefs.graphql
1 change: 1 addition & 0 deletions examples/federation-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"start-gateway": "mesh dev --dir gateway",
"start-gateway-delayed": "delay 1 && npm run start-gateway",
"start-service-accounts": "ts-node services/accounts/index.ts",
"start-service-accounts-subgraph": "ts-node services/accounts-subgraph/index.ts",
"start-service-inventory": "ts-node services/inventory/index.ts",
"start-service-products": "ts-node services/products/index.ts",
"start-service-reviews": "ts-node services/reviews/index.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { accountsSubgraphServer } from './server';

accountsSubgraphServer().catch(error => {
console.error(error);
process.exit(1);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "accounts-subgraph",
"version": "0.0.0",
"license": "MIT",
"private": true,
"scripts": {
"start": "ts-node index.ts"
},
"dependencies": {
"@apollo/subgraph": "2.5.1",
"apollo-server": "3.12.0",
"graphql": "16.7.1",
"ts-node": "10.9.1",
"typescript": "5.1.6"
}
}
71 changes: 71 additions & 0 deletions examples/federation-example/services/accounts-subgraph/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ApolloServer, gql } from 'apollo-server';
import { buildSubgraphSchema } from '@apollo/subgraph';

const typeDefs = gql`
extend type Query {
me: User
user(id: ID!): User
users: [User]
}

type User @key(fields: "id") {
id: ID!
name: String
username: String
}
`;

const resolvers = {
User: {
__resolveReference(object, context) {
return {
...object,
...context.users.find(user => user.id === object.id),
};
},
},
Query: {
me(_root, _args, context) {
return context.users[0];
},
users(_root, _args, context) {
return context.users;
},
user(_root, args, context) {
return context.users.find(user => user.id === args.id);
},
},
};

const server = new ApolloServer({
schema: buildSubgraphSchema([
{
typeDefs,
resolvers,
},
]),
context: {
users: [
{
id: '1',
name: 'Ada Lovelace',
birthDate: '1815-12-10',
username: '@ada',
},
{
id: '2',
name: 'Alan Turing',
birthDate: '1912-06-23',
username: '@complete',
},
],
},
});

export const accountsSubgraphServer = () =>
server.listen({ port: 9880 }).then(({ url }) => {
if (!process.env.CI) {
console.log(`🚀 Server ready at ${url}`);
}
return server;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
extend type Query {
me: User
user(id: ID!): User
users: [User]
}

type User @key(fields: "id") {
id: ID!
name: String
username: String
}
4 changes: 4 additions & 0 deletions examples/federation-example/services/inventory/server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { inspect } from 'node:util';
import { ApolloServer, gql } from 'apollo-server';
import { buildSubgraphSchema } from '@apollo/subgraph';

Expand All @@ -20,6 +21,9 @@ const resolvers = {
};
},
shippingEstimate(object) {
if (object.price == null || object.weight == null) {
throw new Error(`${inspect(object)} doesn't have required fields; "price" and "weight".`);
}
// free for expensive items
if (object.price > 1000) return 0;
// estimate is based on weight
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extend type Product @key(fields: "upc") {
upc: String! @external
weight: Int @external
price: Int @external
inStock: Boolean
shippingEstimate: Int @requires(fields: "price weight")
}
10 changes: 10 additions & 0 deletions examples/federation-example/services/products/typeDefs.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extend type Query {
topProducts(first: Int = 5): [Product]
}

type Product @key(fields: "upc") {
upc: String!
name: String
price: Int
weight: Int
}
17 changes: 17 additions & 0 deletions examples/federation-example/services/reviews/typeDefs.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
type Review @key(fields: "id") {
id: ID!
body: String
author: User @provides(fields: "username")
product: Product
}

extend type User @key(fields: "id") {
id: ID! @external
username: String @external
reviews: [Review]
}

extend type Product @key(fields: "upc") {
upc: String! @external
reviews: [Review]
}
Loading