在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):AEB-labs/graphql-weaver开源软件地址(OpenSource Url):https://github.com/AEB-labs/graphql-weaver开源编程语言(OpenSource Language):TypeScript 99.8%开源软件介绍(OpenSource Introduction):graphql-weaverA tool to combine, link and transform GraphQL schemas Use graphql-weaver if you have multiple GraphQL servers and want to combine them into one API. Features like namespacing, links and custom transformation modules allow you to augment the API as you like. Try it online in Apollo Launchpad How to usenpm install --save graphql-weaver Basic usage: const schema: GraphQLSchema = await weaveSchemas({
endpoints: [{
namespace: 'model',
typePrefix: 'Model',
url: 'http://localhost:8080/graphql' // url to a GraphQL endpoint
}, {
namespace: 'local',
schema: new GraphQLSchema(/* ... */) // use schema instance directly
}]
}) A woven schema is an executable GraphQL schema built from several endpoints. For each endpoint, you can either specify a URL to a GraphQL server, pass an executable GraphQL schema instance, or implement the In its basic configuration, LinksIn the spirit of GraphQL, this tool allows you to create links between objects of different endpoints. Suppose you have a music recommendation service and a music library service. You can make the whole properties of a song available in the recommendation API without the recommendation service knowing all song properties. const schema: GraphQLSchema = await weaveSchemas({
endpoints: [{
namespace: 'library',
url: 'http://example.com/library/graphql'
}, {
namespace: 'recommendations',
url: 'http://example.com/recommendations/graphql',
fieldMetadata: {
'Recommendation.song': { // Field song in type Recommendation
link: {
field: 'library.Song', // field Song in namespace library
argument: 'id', // argument of library.Song
batchMode: false,
}
}
}
}]
}); This assumes the library schema has a field query {
recommendations {
myRecommendations {
recommendedAt
song {
id
artist
title
year
}
}
}
} If there are many recommendations, this is ineficcient because all songs are queried independently. If the library schema supports querying multiple songs at once, you can set const schema: GraphQLSchema = await weaveSchemas({
endpoints: [{
namespace: 'library',
url: 'http://example.com/library/graphql'
}, {
namespace: 'recommendations',
url: 'http://example.com/recommendations/graphql',
fieldMetadata: {
'Recommendation.song': {
link: {
field: 'library.allSongs',
argument: 'filter.ids', // allSongs has an argument filter with an array field ids
batchMode: true,
keyField: 'id' // the name of a field in Song type that contains the id
}
}
}
}]
}); In the case where you want to perfom a link from a single id to a list of many related items, include const schema: GraphQLSchema = await weaveSchemas({
endpoints: [{
namespace: 'library',
url: 'http://example.com/library/graphql'
}, {
namespace: 'recommendations',
url: 'http://example.com/recommendations/graphql',
fieldMetadata: {
'Artist.name': { // Field name in type Artist
link: {
field: 'library.allSongs', // field allSongs in namespace library
argument: 'filter.artistName', // argument of library.Song
batchMode: false, // batchMode must be set to false
oneToMany: true,
linkFieldName: 'songsByThisArtist' // the "virtual" field that will be populated
}
}
}
}]
}); This assumes the library schema has a field query {
recommendations {
myFavoriteArtists {
name
genre
songsByThisArtist {
id
title
year
}
}
}
} JoinsWhat if you want to sort the recommendations by the song age, or filter by artist? The recommendation service currently does not know about these fields, so it does not offer an API to sort or order by any of them. Using graphql-weaver, this problem is easily solved: const schema: GraphQLSchema = await weaveSchemas({
endpoints: [{
namespace: 'library',
url: 'http://example.com/library/graphql'
}, {
namespace: 'recommendations',
url: 'http://example.com/recommendations/graphql',
fieldMetadata: {
'Recommendation.song': {
link: {
field: 'library.allSongs',
argument: 'filter.ids',
batchMode: true, // is now required
keyField: 'id' // this one too
}
},
'Query.myRecommendations': { // Field myRecommendations on type Query
join: {
linkField: 'song', // The field name song in the type Recommendation
}
}
}
}]
}); This assumes that the library service offers a way to filter and sort songs via the query {
recommendations {
myRecommendations(filter: { song: { artist: "Ed Sheeran" } }, orderBy: song_year_DESC) {
recommendedAt
song {
id
artist
title
year
}
}
}
} A note on efficiency: The list of recommendations should be relatively small (not more than a few hundred), as all recommendations need to be fetched so that their ids can be sent to the library for filtering and sorting. Custom transformationsAll four presented features (namespaces, type prefixes, links and joins) are implemented as independent modules. If you need something else, you can just write your own module: class MyModule implements PipelineModule {
transformExtendedSchema(schema: ExtendedSchema): ExtendedSchema {
// do something with the schema
return schema;
}
transformQuery(query: Query): Query {
// do something with the query
return query;
}
}
const schema: GraphQLSchema = weaveSchemas({
endpoints: [{
namespace: 'library',
url: 'http://example.com/library/graphql',
}],
pipelineConfig: {
transformPreMergePipeline(modules: PipelineModule[], context: PreMergeModuleContext): PipelineModule[] {
// These modules are executed for each endpoint
return [
...modules,
new MyModule()
]
},
transformPostMergePipeline(modules: PipelineModule[], context: PostMergeModuleContext): PipelineModule[] {
// These modules are executed once for the merged schema
return [
...modules,
new MyModule()
]
}
}
}); For a simple module, see To simplify modifications to a schema, graphql-weaver ships const transformedSchema = transformSchema(originalSchema, {
transformField(field: GraphQLNamedFieldConfig<any, any>, context) {
// Rename a field in a type
if (context.oldOuterType.name == 'MyType') {
return {
...field,
name: field.name + 'ButCooler'
}
}
return field;
},
transformObjectType(type: GraphQLObjectTypeConfig<any, any>) {
if (type.name == 'MyType') {
return {
...type,
name: 'MyCoolType'
};
}
return type;
},
transformFields(fields: GraphQLFieldConfigMap<any, any>, context) {
// You can even copy types on the fly and transform the copies
const type2 = context.copyType(context.oldOuterType, {
transformObjectType(typeConfig: GraphQLObjectTypeConfig<any, any>) {
return {
...typeConfig,
name: typeConfig.name + '2'
};
}
});
// This just adds a reflexive field "self" to all types, but its type does not have
// the "self" field (because it is a copy from the original type, see above)
// it also won't have the "cool" rename applied because the top-level transformers are not applied
return {
...fields,
self: {
type: type2,
resolve: (source: any) => source
}
}
}
}); For more information, refer to the graphql-transformer project. Schema error handlingBy default, weaveSchemas({
endpoints: [ /* ... */ ],
errorHandling: WeavingErrorHandlingMode.CONTINUE_AND_REPORT_IN_SCHEMA
}) There are four modes available:
Runtime error handlingSince version 0.11, graphql-weaver propagates runtime errors of endpoints transparently and in the most intuitive way.
For the most part, this means everything should work as expected. However, the mapping is more complex as it might seem, so if you find an error mapping that looks wrong, please open an issue. ContributingAfter cloning the repository, run npm install
npm start To run the test suite, run npm test To debug/run the application (or tests) in WebStorm, right-click on Release workflow
Architecturegraphql-weaver takes a set of GraphQL endpoints, transforms them through pipelines, merges them, transforms the merged schema again and exposes that as its woven schema.
The merge in the middle simply merges all the fields of the Query/Mutation types. All the other features, like type prefixing, field namespacing, even resolvers, is implemented by pipeline modules. You'll find the list of modules in Module structure
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论