UNPKG

apollo-language-server

Version:

A language server for Apollo GraphQL projects

198 lines (182 loc) 4.73 kB
// EngineSchemaProvider (engine schema reg => schema) import { NotificationHandler } from "vscode-languageserver"; import gql from "graphql-tag"; import { GraphQLSchema, buildClientSchema } from "graphql"; import { ApolloEngineClient, ClientIdentity } from "../../engine"; import { ClientConfig, keyEnvVar, parseServiceSpecifier } from "../../config"; import { getServiceFromKey, isServiceKey } from "../../config"; import { GraphQLSchemaProvider, SchemaChangeUnsubscribeHandler, SchemaResolveConfig, } from "./base"; import { GetSchemaByTag } from "../../graphqlTypes"; import { Debug } from "../../utilities"; export class EngineSchemaProvider implements GraphQLSchemaProvider { private schema?: GraphQLSchema; private client?: ApolloEngineClient; constructor( private config: ClientConfig, private clientIdentity?: ClientIdentity ) {} async resolveSchema(override: SchemaResolveConfig) { if (this.schema && (!override || !override.force)) return this.schema; const { engine, client } = this.config; if (!this.config.graph) { throw new Error( `No graph ID found for client. Please specify a graph ID via the config or the --graph flag` ); } // create engine client if (!this.client) { if (!engine.apiKey) { throw new Error( `No API key found. Please set ${keyEnvVar} or use --key` ); } this.client = new ApolloEngineClient( engine.apiKey, engine.endpoint, this.clientIdentity ); } const { data, errors } = await this.client.execute<GetSchemaByTag>({ query: SCHEMA_QUERY, variables: { id: this.config.graph, tag: override && override.tag ? override.tag : this.config.variant, }, }); if (errors) { // XXX better error handling of GraphQL errors throw new Error(errors.map(({ message }: Error) => message).join("\n")); } if (!(data && data.service && data.service.__typename === "Service")) { throw new Error( `Unable to get schema from the Apollo registry for graph ${this.config.graph}` ); } // @ts-ignore // XXX Types of `data.service.schema` won't match closely enough with `IntrospectionQuery` this.schema = buildClientSchema(data.service.schema); return this.schema; } onSchemaChange( _handler: NotificationHandler<GraphQLSchema> ): SchemaChangeUnsubscribeHandler { throw new Error("Polling of Apollo not implemented yet"); return () => {}; } async resolveFederatedServiceSDL() { Debug.error( "Cannot resolve a federated service's SDL from Apollo. Use an endpoint or a file instead" ); return; } } export const SCHEMA_QUERY = gql` query GetSchemaByTag($tag: String!, $id: ID!) { service(id: $id) { ... on Service { __typename schema(tag: $tag) { hash __schema: introspection { queryType { name } mutationType { name } subscriptionType { name } types(filter: { includeBuiltInTypes: true }) { ...IntrospectionFullType } directives { name description locations args { ...IntrospectionInputValue } } } } } } } fragment IntrospectionFullType on IntrospectionType { kind name description fields { name description args { ...IntrospectionInputValue } type { ...IntrospectionTypeRef } isDeprecated deprecationReason } inputFields { ...IntrospectionInputValue } interfaces { ...IntrospectionTypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...IntrospectionTypeRef } } fragment IntrospectionInputValue on IntrospectionInputValue { name description type { ...IntrospectionTypeRef } defaultValue } fragment IntrospectionTypeRef on IntrospectionType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } } `;