-
-
Notifications
You must be signed in to change notification settings - Fork 674
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(examples): add Apollo Federation v2 example (#1448)
Co-authored-by: Michał Lytek <michal.wojciech.lytek@gmail.com>
- Loading branch information
1 parent
615680e
commit 9841e0f
Showing
33 changed files
with
615 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { User } from "./user"; | ||
|
||
function createUser(userData: Partial<User>) { | ||
return Object.assign(new User(), userData); | ||
} | ||
|
||
export const users: User[] = [ | ||
createUser({ | ||
id: "1", | ||
name: "Ada Lovelace", | ||
birthDate: "1815-12-10", | ||
username: "@ada", | ||
}), | ||
createUser({ | ||
id: "2", | ||
name: "Alan Turing", | ||
birthDate: "1912-06-23", | ||
username: "@complete", | ||
}), | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { ApolloServer } from "@apollo/server"; | ||
import { startStandaloneServer } from "@apollo/server/standalone"; | ||
import { AccountsResolver } from "./resolver"; | ||
import { User } from "./user"; | ||
import { resolveUserReference } from "./user.reference"; | ||
import { buildFederatedSchema } from "../helpers/buildFederatedSchema"; | ||
|
||
export async function listen(port: number): Promise<string> { | ||
const schema = await buildFederatedSchema( | ||
{ | ||
resolvers: [AccountsResolver], | ||
orphanedTypes: [User], | ||
}, | ||
{ | ||
User: { __resolveReference: resolveUserReference }, | ||
}, | ||
); | ||
|
||
const server = new ApolloServer({ schema }); | ||
|
||
const { url } = await startStandaloneServer(server, { listen: { port } }); | ||
console.log(`Accounts service ready at ${url}`); | ||
|
||
return url; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Query, Resolver } from "type-graphql"; | ||
import { users } from "./data"; | ||
import { User } from "./user"; | ||
|
||
@Resolver(_of => User) | ||
export class AccountsResolver { | ||
@Query(_returns => User) | ||
me(): User { | ||
return users[0]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { users } from "./data"; | ||
import { type User } from "./user"; | ||
|
||
export async function resolveUserReference(reference: Pick<User, "id">): Promise<User> { | ||
return users.find(u => u.id === reference.id)!; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Directive, Field, ID, ObjectType } from "type-graphql"; | ||
|
||
@Directive(`@key(fields: "id")`) | ||
@ObjectType() | ||
export class User { | ||
@Field(_type => ID) | ||
id!: string; | ||
|
||
@Directive("@shareable") | ||
@Field() | ||
username!: string; | ||
|
||
@Field() | ||
name!: string; | ||
|
||
@Field() | ||
birthDate!: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
query { | ||
topProducts { | ||
__typename | ||
name | ||
price | ||
shippingEstimate | ||
inStock | ||
reviews { | ||
body | ||
author { | ||
name | ||
birthDate | ||
reviews { | ||
product { | ||
__typename | ||
name | ||
} | ||
body | ||
} | ||
} | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
examples/apollo-federation-2/helpers/buildFederatedSchema.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { buildSubgraphSchema } from "@apollo/subgraph"; | ||
import { type IResolvers, printSchemaWithDirectives } from "@graphql-tools/utils"; | ||
import gql from "graphql-tag"; | ||
import deepMerge from "lodash.merge"; | ||
import { type BuildSchemaOptions, buildSchema, createResolversMap } from "type-graphql"; | ||
|
||
export async function buildFederatedSchema( | ||
options: Omit<BuildSchemaOptions, "skipCheck">, | ||
referenceResolvers?: IResolvers, | ||
) { | ||
// build TypeGraphQL schema | ||
const schema = await buildSchema({ | ||
...options, | ||
skipCheck: true, // disable check to allow schemas without query, etc. | ||
}); | ||
|
||
// build Apollo Subgraph schema | ||
const federatedSchema = buildSubgraphSchema({ | ||
typeDefs: gql` | ||
extend schema | ||
@link( | ||
url: "https://specs.apollo.dev/federation/v2.3" | ||
import: [ | ||
"@key" | ||
"@shareable" | ||
"@provides" | ||
"@extends" | ||
"@requires" | ||
"@external" | ||
"@interfaceObject" | ||
] | ||
) | ||
${printSchemaWithDirectives(schema)} | ||
`, | ||
// merge schema's resolvers with reference resolvers | ||
resolvers: deepMerge(createResolversMap(schema) as any, referenceResolvers), | ||
}); | ||
|
||
return federatedSchema; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import "reflect-metadata"; | ||
import path from "path"; | ||
import { ApolloGateway, IntrospectAndCompose } from "@apollo/gateway"; | ||
import { ApolloServer } from "@apollo/server"; | ||
import { startStandaloneServer } from "@apollo/server/standalone"; | ||
import { emitSchemaDefinitionFile } from "type-graphql"; | ||
import * as accounts from "./accounts"; | ||
import * as inventory from "./inventory"; | ||
import * as products from "./products"; | ||
import * as reviews from "./reviews"; | ||
|
||
const startGraph = async (name: string, urlOrPromise: string | Promise<string>) => { | ||
const url = await urlOrPromise; | ||
return { name, url }; | ||
}; | ||
|
||
async function bootstrap() { | ||
const subgraphs = await Promise.all([ | ||
startGraph("accounts", accounts.listen(4001)), | ||
startGraph("reviews", reviews.listen(4002)), | ||
startGraph("products", products.listen(4003)), | ||
startGraph("inventory", inventory.listen(4004)), | ||
]); | ||
|
||
const schemaGateway = new ApolloGateway({ | ||
supergraphSdl: new IntrospectAndCompose({ | ||
subgraphs, | ||
}), | ||
}); | ||
const { schema } = await schemaGateway.load(); | ||
await emitSchemaDefinitionFile(path.resolve(__dirname, "schema.graphql"), schema); | ||
await schemaGateway.stop(); | ||
|
||
const gateway = new ApolloGateway({ | ||
supergraphSdl: new IntrospectAndCompose({ | ||
subgraphs, | ||
}), | ||
}); | ||
const server = new ApolloServer({ gateway }); | ||
|
||
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } }); | ||
|
||
console.log(`Apollo Gateway ready at ${url}`); | ||
} | ||
|
||
bootstrap().catch(console.error); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export interface Inventory { | ||
upc: string; | ||
inStock: boolean; | ||
} | ||
|
||
export const inventory: Inventory[] = [ | ||
{ upc: "1", inStock: true }, | ||
{ upc: "2", inStock: false }, | ||
{ upc: "3", inStock: true }, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { ApolloServer } from "@apollo/server"; | ||
import { startStandaloneServer } from "@apollo/server/standalone"; | ||
import { Product } from "./product"; | ||
import { resolveProductReference } from "./product.reference"; | ||
import { InventoryResolver } from "./resolver"; | ||
import { buildFederatedSchema } from "../helpers/buildFederatedSchema"; | ||
|
||
export async function listen(port: number): Promise<string> { | ||
const schema = await buildFederatedSchema( | ||
{ | ||
resolvers: [InventoryResolver], | ||
orphanedTypes: [Product], | ||
}, | ||
{ | ||
Product: { __resolveReference: resolveProductReference }, | ||
}, | ||
); | ||
|
||
const server = new ApolloServer({ schema }); | ||
|
||
const { url } = await startStandaloneServer(server, { listen: { port } }); | ||
console.log(`Inventory service ready at ${url}`); | ||
|
||
return url; | ||
} |
17 changes: 17 additions & 0 deletions
17
examples/apollo-federation-2/inventory/product.reference.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { inventory } from "./data"; | ||
import { Product } from "./product"; | ||
|
||
export async function resolveProductReference( | ||
reference: Pick<Product, "upc">, | ||
): Promise<Product | undefined> { | ||
const found = inventory.find(i => i.upc === reference.upc); | ||
|
||
if (!found) { | ||
return undefined; | ||
} | ||
|
||
return Object.assign(new Product(), { | ||
...reference, | ||
...found, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Directive, Field, ObjectType } from "type-graphql"; | ||
|
||
@ObjectType() | ||
@Directive("@extends") | ||
@Directive("@interfaceObject") | ||
@Directive(`@key(fields: "upc")`) | ||
export class Product { | ||
@Field() | ||
@Directive("@external") | ||
upc!: string; | ||
|
||
@Field() | ||
@Directive("@external") | ||
weight!: number; | ||
|
||
@Field() | ||
@Directive("@external") | ||
price!: number; | ||
|
||
@Field() | ||
inStock!: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Directive, FieldResolver, Resolver, Root } from "type-graphql"; | ||
import { Product } from "./product"; | ||
|
||
@Resolver(_of => Product) | ||
export class InventoryResolver { | ||
@Directive(`@requires(fields: "price weight")`) | ||
@FieldResolver(_returns => Number) | ||
async shippingEstimate(@Root() product: Product): Promise<number> { | ||
// free for expensive items | ||
if (product.price > 1000) { | ||
return 0; | ||
} | ||
|
||
// estimate is based on weight | ||
return product.weight * 0.5; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Dining } from "./dining"; | ||
import { type Product } from "./product"; | ||
import { Seating } from "./seating"; | ||
|
||
export const products: Product[] = [ | ||
Object.assign(new Dining(), { | ||
upc: "1", | ||
name: "Table", | ||
price: 899, | ||
weight: 100, | ||
height: "3ft", | ||
}), | ||
Object.assign(new Seating(), { | ||
upc: "2", | ||
name: "Couch", | ||
price: 1299, | ||
weight: 1000, | ||
seats: 2, | ||
}), | ||
Object.assign(new Seating(), { | ||
upc: "3", | ||
name: "Chair", | ||
price: 54, | ||
weight: 50, | ||
seats: 1, | ||
}), | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Directive, Field, ObjectType } from "type-graphql"; | ||
import { Product } from "./product"; | ||
|
||
@Directive(`@key(fields: "upc")`) | ||
@ObjectType({ implements: Product }) | ||
export class Dining extends Product { | ||
@Field() | ||
height!: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { ApolloServer } from "@apollo/server"; | ||
import { startStandaloneServer } from "@apollo/server/standalone"; | ||
import { Product } from "./product"; | ||
import { resolveProductReference } from "./product.reference"; | ||
import { ProductsResolver } from "./resolver"; | ||
import { buildFederatedSchema } from "../helpers/buildFederatedSchema"; | ||
|
||
export async function listen(port: number): Promise<string> { | ||
const schema = await buildFederatedSchema( | ||
{ | ||
resolvers: [ProductsResolver], | ||
orphanedTypes: [Product], | ||
}, | ||
{ | ||
Product: { __resolveReference: resolveProductReference }, | ||
}, | ||
); | ||
|
||
const server = new ApolloServer({ schema }); | ||
|
||
const { url } = await startStandaloneServer(server, { listen: { port } }); | ||
console.log(`Products service ready at ${url}`); | ||
|
||
return url; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { products } from "./data"; | ||
import { type Product } from "./product"; | ||
|
||
export async function resolveProductReference( | ||
reference: Pick<Product, "upc">, | ||
): Promise<Product | undefined> { | ||
return products.find(p => p.upc === reference.upc); | ||
} |
Oops, something went wrong.