-
-
Notifications
You must be signed in to change notification settings - Fork 677
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 example using
@Directive
- Loading branch information
Showing
6 changed files
with
451 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { | ||
ObjectType, | ||
Field, | ||
Resolver, | ||
Query, | ||
buildSchema, | ||
ID, | ||
FieldResolver, | ||
Root, | ||
Directive, | ||
} from "../../../src"; | ||
import federationDirectives from "@apollo/federation/dist/directives"; | ||
import { buildFederatedSchema } from "@apollo/federation"; | ||
import { specifiedDirectives } from "graphql"; | ||
import { ApolloServer } from "apollo-server"; | ||
import { plainToClass } from "class-transformer"; | ||
import { getMetadataStorage } from "../../../src/metadata/getMetadataStorage"; | ||
|
||
const buildTypeSchema = async () => { | ||
getMetadataStorage().clear(); | ||
|
||
@ObjectType() | ||
@Directive("key", { fields: "id" }) | ||
class User { | ||
@Field(() => ID) | ||
id: string; | ||
|
||
@Field() | ||
username: string; | ||
|
||
@Field() | ||
name: string; | ||
|
||
@Field() | ||
birthDate: string; | ||
} | ||
|
||
const users: User[] = plainToClass(User, [ | ||
{ | ||
id: "1", | ||
name: "Ada Lovelace", | ||
birthDate: "1815-12-10", | ||
username: "@ada", | ||
}, | ||
{ | ||
id: "2", | ||
name: "Alan Turing", | ||
birthDate: "1912-06-23", | ||
username: "@complete", | ||
}, | ||
]); | ||
|
||
@Resolver(() => User) | ||
class AccountsResolver { | ||
@Query(() => User) | ||
me(): User { | ||
return users[0]; | ||
} | ||
|
||
@FieldResolver(() => User, { nullable: true }) | ||
async __resolveReference(@Root() reference: Partial<User>): Promise<User | undefined> { | ||
return users.find(u => u.id === reference.id); | ||
} | ||
} | ||
|
||
return await buildSchema({ | ||
resolvers: [AccountsResolver], | ||
directives: [...specifiedDirectives, ...federationDirectives], | ||
skipCheck: true, | ||
}); | ||
}; | ||
|
||
export async function listen(port: number): Promise<string> { | ||
const schema = buildFederatedSchema(await buildTypeSchema()); | ||
|
||
const server = new ApolloServer({ | ||
schema, | ||
tracing: false, | ||
playground: true, | ||
}); | ||
|
||
const { url } = await 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,35 @@ | ||
import "reflect-metadata"; | ||
import { ApolloGateway } from "@apollo/gateway"; | ||
import { ApolloServer } from "apollo-server"; | ||
import * as accounts from "./accounts"; | ||
import * as reviews from "./reviews"; | ||
import * as products from "./products"; | ||
import * as inventory from "./inventory"; | ||
|
||
async function bootstrap() { | ||
const serviceList = [ | ||
{ name: "accounts", url: await accounts.listen(3001) }, | ||
{ name: "reviews", url: await reviews.listen(3002) }, | ||
{ name: "products", url: await products.listen(3003) }, | ||
{ name: "inventory", url: await inventory.listen(3004) }, | ||
]; | ||
|
||
const gateway = new ApolloGateway({ | ||
serviceList, | ||
}); | ||
|
||
const { schema, executor } = await gateway.load(); | ||
|
||
const server = new ApolloServer({ | ||
schema, | ||
executor, | ||
tracing: false, | ||
playground: true, | ||
}); | ||
|
||
server.listen({ port: 3000 }).then(({ url }) => { | ||
console.log(`🚀 Apollo Gateway ready at ${url}`); | ||
}); | ||
} | ||
|
||
bootstrap(); |
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,101 @@ | ||
import federationDirectives from "@apollo/federation/dist/directives"; | ||
import { buildFederatedSchema } from "@apollo/federation"; | ||
import { specifiedDirectives } from "graphql"; | ||
import { ApolloServer } from "apollo-server"; | ||
import { plainToClass } from "class-transformer"; | ||
import { | ||
ObjectType, | ||
Field, | ||
Resolver, | ||
buildSchema, | ||
FieldResolver, | ||
Root, | ||
Directive, | ||
} from "../../../src"; | ||
import { getMetadataStorage } from "../../../src/metadata/getMetadataStorage"; | ||
|
||
const buildTypeSchema = async () => { | ||
getMetadataStorage().clear(); | ||
|
||
@ObjectType() | ||
@Directive("extends") | ||
@Directive("key", { fields: "upc" }) | ||
class Product { | ||
@Field() | ||
@Directive("external") | ||
upc: string; | ||
|
||
@Field() | ||
@Directive("external") | ||
weight: number; | ||
|
||
@Field() | ||
@Directive("external") | ||
price: number; | ||
|
||
@Field() | ||
inStock: boolean; | ||
} | ||
|
||
interface Inventory { | ||
upc: string; | ||
inStock: boolean; | ||
} | ||
|
||
const inventory: Inventory[] = [ | ||
{ upc: "1", inStock: true }, | ||
{ upc: "2", inStock: false }, | ||
{ upc: "3", inStock: true }, | ||
]; | ||
|
||
@Resolver(() => Product) | ||
class InventoryResolver { | ||
@FieldResolver(() => Number) | ||
@Directive("requires", { fields: "price weight" }) | ||
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; | ||
} | ||
|
||
@FieldResolver(() => Product, { nullable: true }) | ||
async __resolveReference(@Root() reference: Partial<Product>): Promise<Product | undefined> { | ||
const found = inventory.find(i => i.upc === reference.upc); | ||
|
||
if (!found) { | ||
return; | ||
} | ||
|
||
return plainToClass(Product, { | ||
...reference, | ||
...found, | ||
}); | ||
} | ||
} | ||
|
||
return await buildSchema({ | ||
resolvers: [InventoryResolver], | ||
directives: [...specifiedDirectives, ...federationDirectives], | ||
skipCheck: true, | ||
}); | ||
}; | ||
|
||
export async function listen(port: number): Promise<string> { | ||
const schema = buildFederatedSchema(await buildTypeSchema()); | ||
|
||
const server = new ApolloServer({ | ||
schema, | ||
tracing: false, | ||
playground: true, | ||
}); | ||
|
||
const { url } = await server.listen({ port }); | ||
|
||
console.log(`🚀 Inventory 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,93 @@ | ||
import federationDirectives from "@apollo/federation/dist/directives"; | ||
import { buildFederatedSchema } from "@apollo/federation"; | ||
import { specifiedDirectives } from "graphql"; | ||
import { ApolloServer } from "apollo-server"; | ||
import { plainToClass } from "class-transformer"; | ||
import { | ||
ObjectType, | ||
Field, | ||
Resolver, | ||
Query, | ||
buildSchema, | ||
FieldResolver, | ||
Arg, | ||
Root, | ||
Directive, | ||
} from "../../../src"; | ||
import { getMetadataStorage } from "../../../src/metadata/getMetadataStorage"; | ||
|
||
const buildTypeSchema = async () => { | ||
getMetadataStorage().clear(); | ||
|
||
@ObjectType() | ||
@Directive("key", { fields: "upc" }) | ||
class Product { | ||
@Field() | ||
upc: string; | ||
|
||
@Field() | ||
name: string; | ||
|
||
@Field() | ||
price: number; | ||
|
||
@Field() | ||
weight: number; | ||
} | ||
|
||
const products: Product[] = plainToClass(Product, [ | ||
{ | ||
upc: "1", | ||
name: "Table", | ||
price: 899, | ||
weight: 100, | ||
}, | ||
{ | ||
upc: "2", | ||
name: "Couch", | ||
price: 1299, | ||
weight: 1000, | ||
}, | ||
{ | ||
upc: "3", | ||
name: "Chair", | ||
price: 54, | ||
weight: 50, | ||
}, | ||
]); | ||
|
||
@Resolver(() => Product) | ||
class ProductsResolver { | ||
@Query(() => [Product]) | ||
async topProducts(@Arg("first", { defaultValue: 5 }) first: number): Promise<Product[]> { | ||
return products.slice(0, first); | ||
} | ||
|
||
@FieldResolver(() => Product, { nullable: true }) | ||
async __resolveReference(@Root() reference: Partial<Product>): Promise<Product | undefined> { | ||
return products.find(p => p.upc === reference.upc); | ||
} | ||
} | ||
|
||
return await buildSchema({ | ||
resolvers: [ProductsResolver], | ||
directives: [...specifiedDirectives, ...federationDirectives], | ||
skipCheck: true, | ||
}); | ||
}; | ||
|
||
export async function listen(port: number): Promise<string> { | ||
const schema = buildFederatedSchema(await buildTypeSchema()); | ||
|
||
const server = new ApolloServer({ | ||
schema, | ||
tracing: false, | ||
playground: true, | ||
}); | ||
|
||
const { url } = await server.listen({ port }); | ||
|
||
console.log(`🚀 Products service ready at ${url}`); | ||
|
||
return url; | ||
} |
Oops, something went wrong.