From 8140f42e916ed534924145a198329b20537dbf9a Mon Sep 17 00:00:00 2001 From: David Glasser Date: Mon, 8 Aug 2022 15:17:12 -0700 Subject: [PATCH] New package @apollo/server-gateway-interface This package was reviewed in https://github.com/apollographql/apollo-server/pull/6771 --- package-lock.json | 104 +++++++++++++- packages/server-gateway-interface/.npmignore | 7 + packages/server-gateway-interface/README.md | 11 ++ .../server-gateway-interface/package.json | 31 +++++ .../server-gateway-interface/src/index.ts | 128 ++++++++++++++++++ .../server-gateway-interface/tsconfig.json | 9 ++ tsconfig.build.json | 1 + 7 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 packages/server-gateway-interface/.npmignore create mode 100644 packages/server-gateway-interface/README.md create mode 100644 packages/server-gateway-interface/package.json create mode 100644 packages/server-gateway-interface/src/index.ts create mode 100644 packages/server-gateway-interface/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 47d4c060..5905ca16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,6 +87,48 @@ "version": "10.17.60", "license": "MIT" }, + "node_modules/@apollo/server-gateway-interface": { + "resolved": "packages/server-gateway-interface", + "link": true + }, + "node_modules/@apollo/usage-reporting-protobuf": { + "version": "4.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@apollo/usage-reporting-protobuf/-/usage-reporting-protobuf-4.0.0-alpha.1.tgz", + "integrity": "sha512-5pN8CQGxvGbpm58VK7EguR5d6rwZ+v2B9MddKM4DWnh87DuUEbu2xzcSBGaj2Yk2kVzro9YJ1J0vrQrQn8ESYQ==", + "dependencies": { + "@apollo/protobufjs": "1.2.4" + } + }, + "node_modules/@apollo/usage-reporting-protobuf/node_modules/@apollo/protobufjs": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.4.tgz", + "integrity": "sha512-npVJ9NVU/pynj+SCU+fambvTneJDyCnif738DnZ7pCxdDtzeEz7WkpSIq5wNUmWm5Td55N+S2xfqZ+WP4hDLng==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "bin": { + "apollo-pbjs": "bin/pbjs", + "apollo-pbts": "bin/pbts" + } + }, + "node_modules/@apollo/usage-reporting-protobuf/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + }, "node_modules/@apollo/utils.createhash": { "resolved": "packages/createHash", "link": true @@ -8495,7 +8537,7 @@ }, "packages/cache-control-types": { "name": "@apollo/cache-control-types", - "version": "1.0.1", + "version": "1.0.2", "license": "MIT", "peerDependencies": { "graphql": "14.x || 15.x || 16.x" @@ -8621,6 +8663,22 @@ "graphql": "14.x || 15.x || 16.x" } }, + "packages/server-gateway-interface": { + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@apollo/usage-reporting-protobuf": "^4.0.0-alpha.1", + "@apollo/utils.fetcher": "^1.0.0", + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/utils.logger": "^1.0.0" + }, + "engines": { + "node": ">=14.0" + }, + "peerDependencies": { + "graphql": "^16.5.0" + } + }, "packages/sortAST": { "name": "@apollo/utils.sortast", "version": "1.1.0", @@ -8706,6 +8764,50 @@ } } }, + "@apollo/server-gateway-interface": { + "version": "file:packages/server-gateway-interface", + "requires": { + "@apollo/usage-reporting-protobuf": "^4.0.0-alpha.1", + "@apollo/utils.fetcher": "^1.0.0", + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/utils.logger": "^1.0.0" + } + }, + "@apollo/usage-reporting-protobuf": { + "version": "4.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/@apollo/usage-reporting-protobuf/-/usage-reporting-protobuf-4.0.0-alpha.1.tgz", + "integrity": "sha512-5pN8CQGxvGbpm58VK7EguR5d6rwZ+v2B9MddKM4DWnh87DuUEbu2xzcSBGaj2Yk2kVzro9YJ1J0vrQrQn8ESYQ==", + "requires": { + "@apollo/protobufjs": "1.2.4" + }, + "dependencies": { + "@apollo/protobufjs": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.4.tgz", + "integrity": "sha512-npVJ9NVU/pynj+SCU+fambvTneJDyCnif738DnZ7pCxdDtzeEz7WkpSIq5wNUmWm5Td55N+S2xfqZ+WP4hDLng==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + } + } + }, "@apollo/utils.createhash": { "version": "file:packages/createHash", "requires": { diff --git a/packages/server-gateway-interface/.npmignore b/packages/server-gateway-interface/.npmignore new file mode 100644 index 00000000..65ccfbfa --- /dev/null +++ b/packages/server-gateway-interface/.npmignore @@ -0,0 +1,7 @@ +* +!src/**/* +!dist/**/* +dist/**/*.test.* +!package.json +!README.md +!LICENSE \ No newline at end of file diff --git a/packages/server-gateway-interface/README.md b/packages/server-gateway-interface/README.md new file mode 100644 index 00000000..05db0544 --- /dev/null +++ b/packages/server-gateway-interface/README.md @@ -0,0 +1,11 @@ +# Apollo Server/Gateway interface + +This package defines TypeScript types for the interface between Apollo Server and Apollo Gateway. It contains no runtime code. + +The types in this package describe the API as of Gateway 0.35.0 (ie, with onSchemaLoadOrUpdate). It is extracted from the Apollo Server 3 `apollo-server-types` package. Most of the type names have been changed to start with `Gateway`, so that they coexist better with similarly-named types. (Because TypeScript is generally structurally typed, this is OK.) + +Note that the cache scope field (eg, on `requestContext.overallCachePolicy.scope`) is defined as `any` in this package. That's because in AS3 this type is an enum, and enums in TypeScript are *not* structurally typed. So we can't actually create an object of this type without depending on AS3 (or updating AS3 to get its definition from somewhere shared). + +We have updated `@apollo/gateway` (v0 and v2) to define its types from this package rather than `apollo-server-types`. This allows Gateway to be compatible with both AS3 and AS4 (and even AS2, for Gateway 0.x) without needing to pull either package's code into the TypeScript build. + +Apollo Server 4 directly depends on this package and uses its types to construct its calls to the Gateway. diff --git a/packages/server-gateway-interface/package.json b/packages/server-gateway-interface/package.json new file mode 100644 index 00000000..3420f300 --- /dev/null +++ b/packages/server-gateway-interface/package.json @@ -0,0 +1,31 @@ +{ + "name": "@apollo/server-gateway-interface", + "version": "0.0.0", + "description": "Interface used to connect Apollo Gateway to Apollo Server", + "type": "module", + "types": "dist/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/apollographql/apollo-utils", + "directory": "packages/server-gateway-interface" + }, + "keywords": [], + "author": "Apollo ", + "license": "MIT", + "bugs": { + "url": "https://github.com/apollographql/apollo-utils/issues" + }, + "homepage": "https://github.com/apollographql/apollo-utils#readme", + "engines": { + "node": ">=14.0" + }, + "dependencies": { + "@apollo/utils.fetcher": "^1.0.0", + "@apollo/utils.logger": "^1.0.0", + "@apollo/utils.keyvaluecache": "^1.0.1", + "@apollo/usage-reporting-protobuf": "^4.0.0-alpha.1" + }, + "peerDependencies": { + "graphql": "^16.5.0" + } +} diff --git a/packages/server-gateway-interface/src/index.ts b/packages/server-gateway-interface/src/index.ts new file mode 100644 index 00000000..f6b22f76 --- /dev/null +++ b/packages/server-gateway-interface/src/index.ts @@ -0,0 +1,128 @@ +// NOTE: Once Apollo Server 4 is released, move this package into the +// apollo-server repo. We're placing it in the apollo-utils repo for now to +// enable us to make non-alpha releases that can be used on the apollo-server +// version-4 branch. + +import type { KeyValueCache } from "@apollo/utils.keyvaluecache"; +import type { + DocumentNode, + ExecutionResult, + GraphQLError, + GraphQLFormattedError, + GraphQLSchema, + OperationDefinitionNode, +} from "graphql"; +import type { Logger } from "@apollo/utils.logger"; +import type { Trace } from "@apollo/usage-reporting-protobuf"; +import type { FetcherHeaders } from "@apollo/utils.fetcher"; + +export interface GatewayInterface { + onSchemaLoadOrUpdate( + callback: GatewaySchemaLoadOrUpdateCallback, + ): GatewayUnsubscriber; + load(options: { apollo: GatewayApolloConfig }): Promise; + stop(): Promise; +} + +export type GatewaySchemaLoadOrUpdateCallback = (schemaContext: { + apiSchema: GraphQLSchema; + coreSupergraphSdl: string; +}) => void; + +export type GatewayUnsubscriber = () => void; + +export interface GatewayApolloConfig { + key?: string; + keyHash?: string; + graphRef?: string; +} + +export interface GatewayLoadResult { + executor: GatewayExecutor | null; +} + +export type GatewayExecutor = ( + requestContext: GatewayGraphQLRequestContext, +) => Promise; + +export type GatewayExecutionResult = ExecutionResult< + Record, + Record +>; + +// Note that the default value for TContext is the same as in AS3, not +// BaseContext. +export interface GatewayGraphQLRequestContext> { + readonly request: GatewayGraphQLRequest; + readonly response?: GatewayGraphQLResponse; + logger: Logger; + readonly schema: GraphQLSchema; + readonly schemaHash: GatewaySchemaHash; + readonly context: TContext; + readonly cache: KeyValueCache; + readonly queryHash: string; + readonly document: DocumentNode; + readonly source: string; + readonly operationName: string | null; + readonly operation: OperationDefinitionNode; + readonly errors?: ReadonlyArray; + readonly metrics: GatewayGraphQLRequestMetrics; + debug?: boolean; + readonly overallCachePolicy: GatewayCachePolicy; +} + +export interface GatewayGraphQLRequest { + query?: string; + operationName?: string; + variables?: Record; + extensions?: Record; + http?: GatewayHTTPRequest; +} + +export interface GatewayHTTPRequest { + readonly method: string; + readonly url: string; + readonly headers: FetcherHeaders; +} + +export interface GatewayGraphQLResponse { + data?: Record | null; + errors?: ReadonlyArray; + extensions?: Record; + http?: GatewayHTTPResponse; +} + +export interface GatewayHTTPResponse { + readonly headers: FetcherHeaders; + status?: number; +} + +export type GatewaySchemaHash = string & { __fauxpaque: "SchemaHash" }; + +export interface GatewayGraphQLRequestMetrics { + captureTraces?: boolean; + persistedQueryHit?: boolean; + persistedQueryRegister?: boolean; + responseCacheHit?: boolean; + forbiddenOperation?: boolean; + registeredOperation?: boolean; + startHrTime?: [number, number]; + queryPlanTrace?: Trace.QueryPlanNode; +} + +export interface GatewayCachePolicy extends GatewayCacheHint { + replace(hint: GatewayCacheHint): void; + restrict(hint: GatewayCacheHint): void; + policyIfCacheable(): Required | null; +} + +export interface GatewayCacheHint { + maxAge?: number; + // In AS3, this field is an enum. In TypeScript, enums are not structurally + // typed: you need to actually refer directly to the enum's definition to + // produce a value of its type in a typesafe way. Doing that would prevent us + // from severing the dependency on apollo-server-types (AS3), so instead we + // just use 'any'. The legal runtime values of this fields are the strings + // `PUBLIC` and `PRIVATE`. + scope?: any; +} diff --git a/packages/server-gateway-interface/tsconfig.json b/packages/server-gateway-interface/tsconfig.json new file mode 100644 index 00000000..2820e18f --- /dev/null +++ b/packages/server-gateway-interface/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["src/**/*"], + "exclude": ["**/__tests__"], +} diff --git a/tsconfig.build.json b/tsconfig.build.json index 7198ddbd..a7ba4a66 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -17,6 +17,7 @@ { "path": "packages/operationRegistrySignature" }, { "path": "packages/printWithReducedWhitespace" }, { "path": "packages/removeAliases" }, + { "path": "packages/server-gateway-interface" }, { "path": "packages/sortAST" }, { "path": "packages/stripSensitiveLiterals" }, { "path": "packages/usageReporting" },