Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Composeable graphql components

License

NotificationsYou must be signed in to change notification settings

ExpediaGroup/graphql-component

Repository files navigation

GraphQL schema components.

This project is designed to facilitate componentized or modularized development of GraphQL schemas.

Read more about the ideahere.

graphql-component lets you build a schema progressively through a tree (facilitated throughimports) of GraphQLComponent instances. Each GraphQLComponent instance encapsulates an executable GraphQL schema, specifically agraphql-js GraphQLSchema object. See the API below, but the encapsulated schema is accessible through a simpleschema getter on a givenGraphQLComponent instance.

Generally speaking, each instance ofGraphQLComponent has reference to an instance ofGraphQLSchema. This instance ofGraphQLSchema is built in a several ways, depending on the options passed to a givenGraphQLComponent's constructor.

  • when aGraphQLComponent instance hasimports (ie. otherGraphQLComponent instances or component configuration objects)graphql-tools stitchSchemas() is used to create a "gateway" or aggregate schema that is the combination of the underlying imported schemas, and the typeDefs/resolvers passed to the root or importingGraphQLComponent
  • when aGraphQLComponent has no imports, graphql-tools'makeExecuteableSchema({typeDefs, resolvers}) is used to generate an executable GraphQL schema using the passed/required inputs.

It's worth noting thatGraphQLComponent can also be used to construct componentized Apollo Federated schemas. That is, if you pass thefederation: true flag to a GraphQLComponent constructor,@apollo/federation'sbuildSubgraphSchema() is used in lieu of graphql-toolsmakeExecutableSchema({...}) and the above still schema construction rule applies. The general use case here might be to help modularize an individual federated subschema service implementation.

Running the examples

local schema composition:

  • can be run withnpm run start-composition

federation (2 subschema services implemented viaGraphQLComponent and a vanilla Apollo Gateway):

  • can be run withnpm run start-federation

Repository structure

  • lib - the graphql-component code.
  • examples/composition - a simple example of composition usinggraphql-component
  • examples/federation - a simple example of building a federated schema usinggraphql-component

Running examples:

  • composition:npm run start-composition
  • federation:npm run start-federation
  • go tolocalhost:4000/graphql
    • for composition this will bring up the GraphQL Playground for a plain old Apollo Server
    • for the federation example this will bring up the GraphQL Playground for an Apollo Federated Gateway

Debug output

GraphQLComponent usesdebug for local stdout based debug logging. Enable all debug logging with the node environment variableDEBUG=graphql-component:*. Generally speaking, most debug output occurs duringGraphQLComponent construction.

API

  • GraphQLComponent(options) - the component class, which may also be extended. Its options include:

    • types - a string or array of strings of GraphQL SDL defining the type definitions for this component
    • resolvers - a resolver map (ie. a two level map whose first level keys are types from the SDL, mapped to objects, whose keys are fields on those types and values are resolver functions)
    • imports - an optional array of imported components for the schema to be merged with.
    • context - an optional object { namespace, factory } for contributing to context.
    • directives - an optional object containing custom schema directives.
    • mocks - a boolean (to enable default mocks) or an object to pass in custom mocks
    • dataSources - an array of data sources instances to make available oncontext.dataSources .
    • dataSourceOverrides - overrides for data sources in the component tree.
    • federation - make this component's schema an Apollo Federated schema (default:false).
    • pruneSchema - (optional) prune the schema according topruneSchema in graphql-tools (default: false)
    • pruneSchemaOptions - (optional) schema options as perPruneSchemaOptions in graphql-tools
  • static GraphQLComponent.delegateToComponent(component, options) - a wrapper function that utilizesgraphql-toolsdelegateToSchema() to delegate the calling resolver's selection set to a root type field (Query,Mutuation) of anotherGraphQLComponent's schema

    • component (instance ofGraphQLComponent) - the component's whose schema will be the target of the delegated operation

    • options (object)

      • operation (optional, can be inferred frominfo):query ormutation
      • fieldName (optional, can be inferred if target field has same name as calling resolver's field): the target root type (Query,Mutation) field in the targetGraphQLComponent's schema
      • context (required) - thecontext object from resolver that callsdelegateToComponent
      • info (required) - theinfo object from the resolver that callsdelegateToComponent
      • args (object, optional) - an object literal whose keys/values are passed as args to the delegatee's target field resolver. By default, the resolver's args from whichdelegateToComponent is called will be passed if the target field has an argument of the same name. Otherwise, arguments passed via theargs object will override the calling resolver's args of the same name.
      • transforms (optionalArray<Transform>): Transform being a validgraphql-tools transform
    • please seegraphql-toolsdelegateToSchema documentation for more details on availableoptions since the delegateToComponent functions is simply an adapter for theGraphQLComponent API.

A GraphQLComponent instance (ie,new GraphQLComponent({...})) has the following API:

  • schema - getter that this component'sGraphQLSchema object (ie. the "executable" schema that is constructed as described above)
  • context - context function that builds context for all components in the tree.
  • types - this component's types.
  • resolvers - this component's resolvers.
  • imports - this component's imported components in the form of import configuration objects
  • mocks - custom mocks for this component.
  • directives - this component's directives.
  • dataSources - this component's data source(s), if any.

General usage

Creating a component using the GraphQLComponent class:

constGraphQLComponent=require('graphql-component');const{ schema, context}=newGraphQLComponent({ types, resolvers});

Encapsulating state

Typically the best way to make a re-useable component with instance data will be to extendGraphQLComponent.

constGraphQLComponent=require('graphql-component');constresolvers=require('./resolvers');consttypes=require('./types');constmocks=require('./mocks');classPropertyComponentextendsGraphQLComponent{constructor({ types, resolvers}){super({ types, resolvers});}}module.exports=PropertyComponent;

Aggregation

Example to merge multiple components:

const{ schema, context}=newGraphQLComponent({imports:[newProperty(),newReviews()]});constserver=newApolloServer({  schema,  context});

Import configuration

Imports can be a configuration object supplying the following properties:

  • component - the component instance to import.
  • exclude - fields on types to exclude from the component being imported, if any.

Exclude

You can exclude whole types or individual fields on types.

const{ schema, context}=newGraphQLComponent({imports:[{component:newProperty(),exclude:['Mutation.*']},{component:newReviews(),exclude:['Mutation.*']}]});

The excluded types will not appear in the aggregate or gateway schema exposed by the root component, but are still present in the schema encapsulated by the underlying component. This can keep from leaking unintended API surface area, if desired. You can still delegate calls to imported component's schema to utilize the excluded field under the covers.

Data Source support

Data sources ingraphql-component do not extendapollo-datasource'sDataSource class.

Instead, data sources in components will be injected into the context, but wrapped in a proxy such that the globalcontext will be injected as the first argument of any function implemented in a data source class.

This allows there to exist one instance of a data source for caching or other statefulness (like circuit breakers),while still ensuring that a data source will have the current context.

For example, a data source should be implemented like:

classPropertyDataSource{asyncgetPropertyById(context,id){//do some work...}}

This data source would be executed without passing thecontext manually:

constresolvers={Query:{property(_,{ id},{ dataSources}){returndataSources.PropertyDataSource.getPropertyById(id);}}}

Setting up a component to use a data source might look like:

newGraphQLComponent({//...dataSources:[newPropertyDataSource()]})

Override data sources

Since data sources are added to the context based on the constructor name, it is possible to simply override data sources by passing the same class name or overriding the constructor name:

const{ schema, context}=newGraphQLComponent({imports:[{component:newProperty(),exclude:['Mutation.*']},{component:newReviews(),exclude:['Mutation.*']}],dataSourceOverrides:[newclassPropertyMock{staticgetname(){return'PropertyDataSource';}//...etc}]});

Decorating the global context

Example context argument:

constcontext={namespace:'myNamespace',factory:function({ req}){return'my value';}};

After this, resolvercontext will contain{ ..., myNamespace: 'my value' }.

Context middleware

It may be necessary to transform the context before invoking component context.

const{ schema, context}=newGraphQLComponent({types, resolvers, context});context.use('transformRawRequest',({ request})=>{return{req:request.raw.req};});

Usingcontext now inapollo-server-hapi for example, will transform the context to one similar to defaultapollo-server.


[8]ページ先頭

©2009-2025 Movatter.jp