Update extension docs

This commit is contained in:
Brian Beck 2021-04-15 23:12:41 -07:00
parent c020795b58
commit 94cf657f30

View file

@ -6,7 +6,8 @@ Extensions can define new GraphQL types and use the `extend type` syntax to add
new fields to any existing GraphBrainz type, including the root query. new fields to any existing GraphBrainz type, including the root query.
Several extensions are included by default, and you can install any number of Several extensions are included by default, and you can install any number of
additional extensions from a package manager or [write your own](#extension-api). additional extensions from a package manager or
[write your own](#extension-api).
## Contents ## Contents
@ -30,9 +31,9 @@ additional extensions from a package manager or [write your own](#extension-api)
## Loading Extensions ## Loading Extensions
The extensions to load are specified using the `extensions` option to the The extensions to load are specified using the `extensions` option to the
exported `graphbrainz()` middleware function. Each extension must be an object exported `middleware()` function. Each extension must be an object conforming to
conforming to the [Extension API](#extension-api), or the path to a module to the [Extension API](#extension-api), or the path to a module to load via
load via `require()` that exports such an object. `require()` that exports such an object.
If you are running GraphBrainz as a standalone server, you may specify If you are running GraphBrainz as a standalone server, you may specify
extensions via the `GRAPHBRAINZ_EXTENSIONS` environment variable, which will be extensions via the `GRAPHBRAINZ_EXTENSIONS` environment variable, which will be
@ -49,14 +50,14 @@ or environment variables. Check the documentation for each extension you use.
The default extensions configuration looks like this: The default extensions configuration looks like this:
```js ```js
graphbrainz({ middleware({
extensions: [ extensions: [
'graphbrainz/extensions/cover-art-archive', 'graphbrainz/extensions/cover-art-archive',
'graphbrainz/extensions/fanart-tv', 'graphbrainz/extensions/fanart-tv',
'graphbrainz/extensions/mediawiki', 'graphbrainz/extensions/mediawiki',
'graphbrainz/extensions/the-audio-db' 'graphbrainz/extensions/the-audio-db',
] ],
}) });
``` ```
## Built-in Extensions ## Built-in Extensions
@ -70,8 +71,8 @@ See their respective documentation pages for schema info and config options.
releases, and labels from fanart.tv. releases, and labels from fanart.tv.
- [MediaWiki](./mediawiki.md): Retrieve information from MediaWiki image pages, - [MediaWiki](./mediawiki.md): Retrieve information from MediaWiki image pages,
like the actual image file URL and EXIF metadata. like the actual image file URL and EXIF metadata.
- [TheAudioDB](./the-audio-db.md): Retrieve images and information about artists, - [TheAudioDB](./the-audio-db.md): Retrieve images and information about
releases, and recordings from TheAudioDB.com. artists, releases, and recordings from TheAudioDB.com.
## More Extensions ## More Extensions
@ -79,19 +80,21 @@ The following extensions are published separately, but can easily be added to
GraphBrainz by installing them: GraphBrainz by installing them:
- [Last.fm](https://github.com/exogen/graphbrainz-extension-lastfm): Retrieve - [Last.fm](https://github.com/exogen/graphbrainz-extension-lastfm): Retrieve
artist, release, and recording information from [Last.fm](https://www.last.fm/). artist, release, and recording information from
[Last.fm](https://www.last.fm/).
- [Discogs](https://github.com/exogen/graphbrainz-extension-discogs): Retrieve - [Discogs](https://github.com/exogen/graphbrainz-extension-discogs): Retrieve
artist, label, release, and release group information from artist, label, release, and release group information from
[Discogs](https://www.discogs.com/). [Discogs](https://www.discogs.com/).
- [Spotify](https://github.com/exogen/graphbrainz-extension-spotify): Retrieve - [Spotify](https://github.com/exogen/graphbrainz-extension-spotify): Retrieve
artist, release, and recording information from [Spotify](https://www.spotify.com/). artist, release, and recording information from
[Spotify](https://www.spotify.com/).
## Extension API ## Extension API
The core idea behind extensions comes from the [schema stitching][] feature The core idea behind extensions comes from the [schema stitching][] feature from
from [graphql-tools][], although GraphBrainz does not currently use the exact [graphql-tools][], although GraphBrainz does not currently use the exact
technique documented there. Instead, we call `parse` and `extendSchema` from technique documented there. Instead, we call `parse` and `extendSchema` from
[GraphQL.js][], followed by [addResolveFunctionsToSchema][]. [GraphQL.js][], followed by [addResolversToSchema][].
Extensions must export an object shaped like so: Extensions must export an object shaped like so:
@ -102,8 +105,8 @@ type Extension = {
extendContext?: (context: Context, options: Options) => Context, extendContext?: (context: Context, options: Options) => Context,
extendSchema?: extendSchema?:
| { schemas: Array<string | DocumentNode>, resolvers: ResolverMap } | { schemas: Array<string | DocumentNode>, resolvers: ResolverMap }
| ((schema: GraphQLSchema, options: Options) => GraphQLSchema) | ((schema: GraphQLSchema, options: Options) => GraphQLSchema),
} };
``` ```
### Properties ### Properties
@ -132,7 +135,7 @@ If it is an object, it should have a `schemas` array and a `resolvers` object.
Each schema must be a string (containing type definitions in GraphQL schema Each schema must be a string (containing type definitions in GraphQL schema
language) or a `DocumentNode` (if the type definitions have already been language) or a `DocumentNode` (if the type definitions have already been
parsed). The `resolvers` object should contain a mapping of type fields to new parsed). The `resolvers` object should contain a mapping of type fields to new
resolver functions for those fields. See [addResolveFunctionsToSchema][]. resolver functions for those fields. See [addResolversToSchema][].
If it is a function, it should accept `schema` and `options` arguments and If it is a function, it should accept `schema` and `options` arguments and
return a new schema. Use this if youd like to perform custom schema extension return a new schema. Use this if youd like to perform custom schema extension
@ -152,17 +155,17 @@ module.exports = {
extend type Query { extend type Query {
helloWorld: String! helloWorld: String!
} }
` `,
], ],
resolvers: { resolvers: {
Query: { Query: {
helloWorld: { helloWorld: {
resolve: () => 'It worked!' resolve: () => 'It worked!',
} },
} },
} },
} },
} };
``` ```
This will allow the following query to be made: This will allow the following query to be made:
@ -180,24 +183,24 @@ See the code for the [built-in extensions][] for more examples.
Extensions can load and resolve data in any manner they please, and you can Extensions can load and resolve data in any manner they please, and you can
write them in any way that conforms to the API. But if you want an extra feather write them in any way that conforms to the API. But if you want an extra feather
in your cap, there are a few guidelines you should follow in order to maintain in your cap, there are a few guidelines you should follow in order to maintain
consistency with GraphBrainz and the built-in extensions. Here are some tips consistency with GraphBrainz and the built-in extensions. Here are some tips for
for writing a good extension: writing a good extension:
- If you need to make HTTP requests, using a [Client][] subclass will get you - If you need to make HTTP requests, using a [Client][] subclass will get you
rate limiting, error handling, retrying, and a Promise-based API for free. rate limiting, error handling, retrying, and a Promise-based API for free.
- Default to following the rate limiting rules of any APIs you use. If there - Default to following the rate limiting rules of any APIs you use. If there are
are no guidelines on rate limiting, consider playing nice anyway and limiting no guidelines on rate limiting, consider playing nice anyway and limiting your
your client to around 1 to 10 requests per second. client to around 1 to 10 requests per second.
- Use a [DataLoader][dataloader] instance to batch and cache requests. Even if - Use a [DataLoader][dataloader] instance to batch and cache requests. Even if
the data source doesnt support batching, DataLoader will help by deduping the data source doesnt support batching, DataLoader will help by deduping
in-flight requests for the same key, preventing unnecessary requests. in-flight requests for the same key, preventing unnecessary requests.
- Use a configurable cache and make sure you arent caching everything - Use a configurable cache and make sure you arent caching everything
indefinitely by accident. The `cacheMap` option to DataLoader is a good place indefinitely by accident. The `cacheMap` option to DataLoader is a good place
to put it. to put it.
- Get as much configuration from environment variables as possible so that - Get as much configuration from environment variables as possible so that users
users can just run the standalone server instead of writing any code. If you can just run the standalone server instead of writing any code. If you need
need more complex configuration, use a single field on the `options` object more complex configuration, use a single field on the `options` object as a
as a namespace for your extensions options. namespace for your extensions options.
- Dont hesitate to rename fields returned by third-party APIs when translating - Dont hesitate to rename fields returned by third-party APIs when translating
them to the GraphQL schema. Consistency with GraphQL conventions and the them to the GraphQL schema. Consistency with GraphQL conventions and the
GraphBrainz schema is more desirable than consistency with the original API GraphBrainz schema is more desirable than consistency with the original API
@ -235,14 +238,18 @@ for writing a good extension:
with the built-in extensions. with the built-in extensions.
[graphql-tools]: http://dev.apollodata.com/tools/graphql-tools/index.html [graphql-tools]: http://dev.apollodata.com/tools/graphql-tools/index.html
[schema stitching]: http://dev.apollodata.com/tools/graphql-tools/schema-stitching.html [schema stitching]:
[mergeschemas]: http://dev.apollodata.com/tools/graphql-tools/schema-stitching.html#mergeSchemas http://dev.apollodata.com/tools/graphql-tools/schema-stitching.html
[mergeschemas]:
http://dev.apollodata.com/tools/graphql-tools/schema-stitching.html#mergeSchemas
[dataloader]: https://github.com/facebook/dataloader [dataloader]: https://github.com/facebook/dataloader
[built-in extensions]: ../../src/extensions [built-in extensions]: ../../src/extensions
[client]: ../../src/api/client.js [client]: ../../src/api/client.js
[graphql-markdown]: https://github.com/exogen/graphql-markdown [graphql-markdown]: https://github.com/exogen/graphql-markdown
[diffschema]: https://github.com/exogen/graphql-markdown#diffschemaoldschema-object-newschema-object-options-object [diffschema]:
https://github.com/exogen/graphql-markdown#diffschemaoldschema-object-newschema-object-options-object
[build-extension-docs]: ../../scripts/build-extension-docs.js [build-extension-docs]: ../../scripts/build-extension-docs.js
[relay]: https://facebook.github.io/relay/ [relay]: https://facebook.github.io/relay/
[graphql.js]: http://graphql.org/graphql-js/ [graphql.js]: http://graphql.org/graphql-js/
[addresolvefunctionstoschema]: http://dev.apollodata.com/tools/graphql-tools/resolvers.html#addResolveFunctionsToSchema [addresolverstoschema]:
http://dev.apollodata.com/tools/graphql-tools/resolvers.html#addResolversToSchema