diff --git a/examples/access-control-directives.ts b/examples/access-control-directives.ts index 3ea3d66..86e1990 100644 --- a/examples/access-control-directives.ts +++ b/examples/access-control-directives.ts @@ -1,10 +1,17 @@ -import { ApolloServer } from 'apollo-server'; -import type { ExpressContext } from 'apollo-server-express'; +import { ApolloServer } from '@apollo/server'; +import { startStandaloneServer } from '@apollo/server/standalone'; import { makeExecutableSchema } from '@graphql-tools/schema'; import gql from 'graphql-tag'; +import applyDirectiveMappersToSchema from 'lib/utils/applyDirectiveMappersToSchema'; + import type { MissingPermissionsResolverInfo } from '../lib'; -import { v3Auth, v3HasPermissions } from '../lib'; +import { + v3Auth, + v3HasPermissions, + authDirectiveMapper, + hasPermissionsDirectiveMapper, +} from '../lib'; const yourTypeDefs = [ gql` @@ -29,51 +36,54 @@ const state: { isAuthenticated: null, }; -const schema = makeExecutableSchema({ - resolvers: { - Mutation: { - setAuthenticated: ( - _, - { isAuthenticated }: { isAuthenticated: boolean | null }, - ): boolean | null => { - state.isAuthenticated = isAuthenticated; - return isAuthenticated; +const schema = applyDirectiveMappersToSchema( + [hasPermissionsDirectiveMapper, authDirectiveMapper], + makeExecutableSchema({ + resolvers: { + Mutation: { + setAuthenticated: ( + _, + { isAuthenticated }: { isAuthenticated: boolean | null }, + ): boolean | null => { + state.isAuthenticated = isAuthenticated; + return isAuthenticated; + }, + setPermissions: ( + _, + { permissions }: { permissions: string[] | null }, + ): string[] | null => { + state.grantedPermissions = permissions; + return permissions; + }, }, - setPermissions: ( - _, - { permissions }: { permissions: string[] | null }, - ): string[] | null => { - state.grantedPermissions = permissions; - return permissions; + Query: { + authenticated: (): boolean => state.isAuthenticated || false, + handleMissingPermissions: ( + _, + __, + ___, + { missingPermissions }: MissingPermissionsResolverInfo, + ): string[] | null => missingPermissions || null, + throwIfMissingPermissions: (): number => 123, }, }, - Query: { - authenticated: (): boolean => true, - handleMissingPermissions: ( - _, - __, - ___, - { missingPermissions }: MissingPermissionsResolverInfo, - ): string[] | null => missingPermissions || null, - throwIfMissingPermissions: (): number => 123, - }, - }, - schemaDirectives: { - v3Auth, - v3HasPermissions, - }, - typeDefs: [ - ...yourTypeDefs, - ...v3Auth.getTypeDefs(), - ...v3HasPermissions.getTypeDefs(), - ], -}); + typeDefs: [ + ...yourTypeDefs, + ...v3Auth.getTypeDefs(), + ...v3HasPermissions.getTypeDefs(), + ], + }), +); type Context = ReturnType & ReturnType; const server = new ApolloServer({ - context: (expressContext: ExpressContext): Context => { + schema, +}); + +startStandaloneServer(server, { + context: async (expressContext): Promise => { // This example allows for state to be passed in the headers: // - authorization: any value results in authenticated // - permissions: json-serialized array of strings or null @@ -102,9 +112,7 @@ const server = new ApolloServer({ }), }; }, - schema, -}); -server.listen().then(({ url }) => { - // eslint-disable-next-line no-console + listen: { port: 4000 }, +}).then(({ url }) => { console.log(`🚀 Server ready at ${url}`); }); diff --git a/examples/federation.ts b/examples/federation.ts index e0838cf..0bb5c37 100644 --- a/examples/federation.ts +++ b/examples/federation.ts @@ -3,13 +3,16 @@ import type { DocumentNode, GraphQLFieldResolver, } from 'graphql'; -import { ApolloServer, gql } from 'apollo-server'; +import { ApolloServer } from '@apollo/server'; +import { startStandaloneServer } from '@apollo/server/standalone'; import { ApolloGateway } from '@apollo/gateway'; -import { buildSubgraphSchema } from '@apollo/federation'; +import { buildSubgraphSchema } from '@apollo/subgraph'; import type { GraphQLResolverMap } from 'apollo-graphql'; -import { SchemaDirectiveVisitor } from '@graphql-tools/utils'; +import gql from 'graphql-tag'; import { ValidateDirectiveVisitor, range, stringLength } from '../lib'; +import { rangeDirectiveMapper } from 'lib/range'; +import { stringLengthDirectiveMapper } from 'lib/stringLength'; /* When using apollo federation all @@ -33,9 +36,14 @@ const buildSchema = ( [], ), ]; - const schema = buildSubgraphSchema({ resolvers, typeDefs: finalTypeDefs }); - SchemaDirectiveVisitor.visitSchemaDirectives(schema, directives); - ValidateDirectiveVisitor.addValidationResolversToSchema(schema); + const schema = stringLengthDirectiveMapper( + rangeDirectiveMapper( + buildSubgraphSchema({ + resolvers: resolvers as GraphQLResolverMap, + typeDefs: finalTypeDefs, + }), + ), + ); return schema; }; @@ -83,9 +91,12 @@ const services: ServicesSetup[] = [ const start = async (): Promise => { const runningString = await Promise.all( services.map(({ resolvers, typeDefs, port }) => - new ApolloServer({ - schema: buildSchema(resolvers, typeDefs), - }).listen({ port }), + startStandaloneServer( + new ApolloServer({ + schema: buildSchema(resolvers, typeDefs), + }), + { listen: { port } }, + ), ), ); // eslint-disable-next-line no-console @@ -106,7 +117,7 @@ const start = async (): Promise => { gateway: apolloGateway, }); - const { url } = await server.listen(); + const { url } = await startStandaloneServer(server); // eslint-disable-next-line no-console console.log(`🚀 Server ready at ${url}`); }; diff --git a/examples/value-validation-directives.ts b/examples/value-validation-directives.ts index 68cd53e..c7847c3 100644 --- a/examples/value-validation-directives.ts +++ b/examples/value-validation-directives.ts @@ -1,7 +1,7 @@ -import { ApolloServer } from 'apollo-server'; +import { ApolloServer } from '@apollo/server'; +import { startStandaloneServer } from '@apollo/server/standalone'; import { makeExecutableSchema } from '@graphql-tools/schema'; import gql from 'graphql-tag'; -import type { ValidationError } from 'apollo-server-errors'; import type { GraphQLResolveInfo } from 'graphql'; import { graphql, print } from 'graphql'; @@ -13,7 +13,14 @@ import { stringLength, ValidateDirectiveVisitor, trim, + listLengthDirectiveMapper, + patternDirectiveMapper, + rangeDirectiveMapper, + stringLengthDirectiveMapper, + trimDirectiveMapper, } from '../lib'; +import type ValidationError from '../lib/errors/ValidationError'; +import applyDirectiveMappersToSchema from 'lib/utils/applyDirectiveMappersToSchema'; interface ValidationErrorsResolverInfo extends GraphQLResolveInfo { validationErrors?: ValidationError[]; @@ -82,40 +89,39 @@ const argsResolver = ( { validationErrors }: ValidationErrorsResolverInfo, ): object => ({ arg, validationErrors }); -const schemaDirectives = { - listLength, - pattern, - range, - stringLength, - trim, -}; +const mappers = [ + listLengthDirectiveMapper, + patternDirectiveMapper, + rangeDirectiveMapper, + stringLengthDirectiveMapper, + trimDirectiveMapper, +]; -const schema = makeExecutableSchema({ - resolvers: { - Query: { - floatRangeExample: argsResolver, - intRangeExample: argsResolver, - listLengthExample: argsResolver, - patternExample: argsResolver, - stringLengthExample: argsResolver, - throwingIntRangeExample: argsResolver, - trimExample: argsResolver, +const schema = applyDirectiveMappersToSchema( + mappers, + makeExecutableSchema({ + resolvers: { + Query: { + floatRangeExample: argsResolver, + intRangeExample: argsResolver, + listLengthExample: argsResolver, + patternExample: argsResolver, + stringLengthExample: argsResolver, + throwingIntRangeExample: argsResolver, + trimExample: argsResolver, + }, }, - }, - schemaDirectives, - typeDefs: [ - ...yourTypeDefs, - ...ValidateDirectiveVisitor.getMissingCommonTypeDefs(), - ...listLength.getTypeDefs(), - ...pattern.getTypeDefs(), - ...range.getTypeDefs(), - ...stringLength.getTypeDefs(), - ...trim.getTypeDefs(), - ], -}); - -// needed to validate input fields! -ValidateDirectiveVisitor.addValidationResolversToSchema(schema); + typeDefs: [ + ...yourTypeDefs, + ...ValidateDirectiveVisitor.getMissingCommonTypeDefs(), + ...listLength.getTypeDefs(), + ...pattern.getTypeDefs(), + ...range.getTypeDefs(), + ...stringLength.getTypeDefs(), + ...trim.getTypeDefs(), + ], + }), +); // works as test and sample queries const tests = { @@ -333,7 +339,7 @@ const test = async (): Promise => Object.entries(tests).map( async ([name, { query, result: expected }]): Promise => { const source = print(query); - const result = await graphql(schema, source); + const result = await graphql({ schema, source }); if (JSON.stringify(result) !== JSON.stringify(expected)) { throw Error(`test ${name} failed`); } @@ -350,7 +356,7 @@ test().catch(error => { }); const server = new ApolloServer({ schema }); -server.listen().then(({ url }) => { +startStandaloneServer(server).then(({ url }) => { // eslint-disable-next-line no-console console.log(`🚀 Server ready at ${url}`); });