2016-12-21 02:04:08 +00:00
# GraphBrainz
2016-08-20 05:59:32 +00:00
2017-04-06 01:19:43 +00:00
[](https://travis-ci.org/exogen/graphbrainz)
2016-12-14 05:21:07 +00:00
[](https://codecov.io/gh/exogen/graphbrainz)
2017-04-06 01:19:43 +00:00
[](https://greenkeeper.io/)
2016-12-14 05:21:07 +00:00
[](https://www.npmjs.com/package/graphbrainz)
2016-12-03 01:47:46 +00:00
[](https://github.com/exogen/graphbrainz/blob/master/LICENSE)
2016-12-02 08:38:41 +00:00
2016-12-21 02:04:08 +00:00
A [GraphQL][] schema, [Express][] server, and middleware for querying the
[MusicBrainz][] API.
2016-11-26 02:18:41 +00:00
2016-11-29 03:36:29 +00:00
```sh
npm install graphbrainz --save
```
2016-11-29 03:33:52 +00:00
2016-11-29 03:37:44 +00:00
**[Try out the live demo!][demo]** :bulb: Use the “Docs” sidebar, the
[schema][], or the [types][] docs to help construct your query.
2016-11-26 02:31:06 +00:00
2016-11-26 02:18:41 +00:00
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE - RUN doctoc TO UPDATE -->
## Contents
- [Usage ](#usage )
- [As a standalone server ](#as-a-standalone-server )
- [As middleware ](#as-middleware )
2016-12-21 02:07:24 +00:00
- [As a client ](#as-a-client )
2016-11-26 02:18:41 +00:00
- [Environment Variables ](#environment-variables )
- [Debugging ](#debugging )
- [Example Queries ](#example-queries )
2016-11-26 20:03:46 +00:00
- [Pagination ](#pagination )
2016-11-26 07:08:54 +00:00
- [Questions ](#questions )
2016-11-26 02:18:41 +00:00
- [Schema ](#schema )
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Usage
This package can be used both as a standalone GraphQL server and as Express
middleware supplying a GraphQL endpoint.
### As a standalone server
Run the included `graphbrainz` executable to start the server. The server
is configured using [environment variables ](#environment-variables ).
```sh
$ graphbrainz
Listening on port 3000.
```
2016-11-26 02:25:27 +00:00
Development mode features like JSON pretty printing and the [GraphiQL][]
interface will be enabled unless the server is run with `NODE_ENV=production` .
2016-11-26 02:18:41 +00:00
2016-11-26 02:24:49 +00:00
Note that if you are not running the standalone server within another Node
project, you may wish to install this package globally so that the `graphbrainz`
script is globally available:
```sh
npm install -g graphbrainz
```
2016-11-26 02:18:41 +00:00
### As middleware
If you have an existing Express server and want to add this GraphQL service as
an endpoint, or you just want more customization, use the middleware.
```js
import express from 'express';
import graphbrainz from 'graphbrainz';
const app = express();
// Use the default options:
app.use('/graphbrainz', graphbrainz());
2016-11-26 02:27:40 +00:00
2016-11-26 02:18:41 +00:00
// or, pass some options:
app.use('/graphbrainz', graphbrainz({
2016-11-26 02:27:16 +00:00
client: new MusicBrainz({ ... }),
graphiql: true,
...
2016-11-26 02:18:41 +00:00
}));
app.listen(3000);
```
The `graphbrainz` middleware function accepts the following options:
* **`client`**: A custom API client instance to use. See the
2016-11-27 19:29:13 +00:00
[client submodule ](src/api.js ) for help with creating a custom instance. You
probably only need to do this if you want to adjust the rate limit and retry
behavior.
2016-11-26 02:18:41 +00:00
* Any remaining options are passed along to the standard GraphQL middleware.
See the [express-graphql][] documentation for more information.
2016-12-21 02:04:08 +00:00
### As a client
If you just want to make queries from your app without running a separate server
or exposing a GraphQL endpoint, use the GraphBrainz schema with a library like
[GraphQL.js][graphql-js]. You just need to create the `context` object that the
GraphBrainz resolvers expect, like so:
```js
import { graphql } from 'graphql';
import { MusicBrainz, CoverArtArchive } from 'graphbrainz/api';
import createLoaders from 'graphbrainz/loaders';
import schema from 'graphbrainz/schema';
const client = new MusicBrainz();
const coverArtClient = new CoverArtArchive();
const loaders = createLoaders(client, coverArtClient);
const context = { client, coverArtClient, loaders };
graphql(schema, `
{
lookup {
releaseGroup(mbid: "99599db8-0e36-4a93-b0e8-350e9d7502a9") {
title
}
}
}
`, null, context).then(result => {
const { releaseGroup } = result.data.lookup;
console.log(`The album title is “${releaseGroup.title}”.`);
}).catch(err => {
console.error(err);
});
```
2016-11-26 02:18:41 +00:00
### Environment Variables
* **`MUSICBRAINZ_BASE_URL`**: The base MusicBrainz API URL to use. Change this
if you are running your own MusicBrainz mirror. Defaults to `http://musicbrainz.org/ws/2/` .
* **`GRAPHBRAINZ_PATH`**: The URL route at which to expose the GraphQL endpoint,
if running the standalone server. Defaults to `/` .
2016-11-28 13:49:04 +00:00
* **`GRAPHBRAINZ_CACHE_SIZE`**: The maximum number of REST API responses to
cache. Increasing the cache size and TTL will greatly lower query execution
time for complex queries involving frequently accessed entities. Defaults to
`8192` .
* **`GRAPHBRAINZ_CACHE_TTL`**: The maximum age of REST API responses in the
cache, in milliseconds. Responses older than this will be disposed of (and
re-requested) the next time they are accessed. Defaults to `86400000` (one
day).
2016-11-26 02:18:41 +00:00
* **`GRAPHBRAINZ_GRAPHIQL`**: Set this to `true` if you want to force the
[GraphiQL][] interface to be available even in production mode.
* **`PORT`**: Port number to use, if running the standalone server.
When running the standalone server, [dotenv][] is used to load these variables
2016-11-27 19:29:13 +00:00
from a `.env` file, if one exists in the current working directory. This just
makes it more convenient to launch the server with certain settings. See the
2016-11-26 02:18:41 +00:00
[dotenv][] package for more information.
### Debugging
The `DEBUG` environment variable can be used to enable logging for all (or just
some) of this package’ s submodules:
```sh
$ DEBUG=graphbrainz:* graphbrainz
```
See the [debug][] package for more information.
## Example Queries
2016-11-26 20:23:23 +00:00
Nirvana albums and each album’ s singles ([try it](https://graphbrainz.herokuapp.com/?query=query%20NirvanaAlbumSingles%20%7B%0A%20%20lookup%20%7B%0A%20%20%20%20artist(mbid%3A%20%225b11f4ce-a62d-471e-81fc-a69a8278c7da%22)%20%7B%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20releaseGroups(type%3A%20ALBUM)%20%7B%0A%20%20%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20title%0A%20%20%20%20%20%20%20%20%20%20%20%20firstReleaseDate%0A%20%20%20%20%20%20%20%20%20%20%20%20relationships%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20releaseGroups(type%3A%20%22single%20from%22)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20target%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...%20on%20ReleaseGroup%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20firstReleaseDate%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A& operationName=NirvanaAlbumSingles)):
2016-11-26 02:18:41 +00:00
```graphql
2016-11-26 20:23:23 +00:00
query NirvanaAlbumSingles {
2016-11-26 02:18:41 +00:00
lookup {
artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") {
name
releaseGroups(type: ALBUM) {
edges {
node {
title
firstReleaseDate
relationships {
releaseGroups(type: "single from") {
edges {
node {
target {
... on ReleaseGroup {
title
firstReleaseDate
}
}
}
}
}
}
}
}
}
}
}
}
```
2016-08-20 05:59:32 +00:00
2016-11-26 20:03:46 +00:00
### Pagination
2016-11-26 20:50:37 +00:00
The first five labels with “Apple” in the name ([try it](https://graphbrainz.herokuapp.com/?query=query%20AppleLabels%20%7B%0A%20%20search%20%7B%0A%20%20%20%20labels(query%3A%20%22Apple%22%2C%20first%3A%205)%20%7B%0A%20%20%20%20%20%20...labelResults%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0Afragment%20labelResults%20on%20LabelConnection%20%7B%0A%20%20pageInfo%20%7B%0A%20%20%20%20endCursor%0A%20%20%7D%0A%20%20edges%20%7B%0A%20%20%20%20cursor%0A%20%20%20%20node%20%7B%0A%20%20%20%20%20%20mbid%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20type%0A%20%20%20%20%20%20area%20%7B%0A%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A& operationName=AppleLabels)):
2016-11-26 20:03:46 +00:00
```graphql
2016-11-26 20:50:37 +00:00
query AppleLabels {
2016-11-26 20:03:46 +00:00
search {
labels(query: "Apple", first: 5) {
...labelResults
}
}
}
fragment labelResults on LabelConnection {
pageInfo {
endCursor
}
edges {
cursor
node {
mbid
name
type
area {
name
}
}
}
}
```
2016-11-26 20:51:19 +00:00
…and the next five, using the `endCursor` from the previous result ([try it](https://graphbrainz.herokuapp.com/?query=query%20AppleLabels%20%7B%0A%20%20search%20%7B%0A%20%20%20%20labels(query%3A%20%22Apple%22%2C%20first%3A%205%2C%20after%3A%20%22YXJyYXljb25uZWN0aW9uOjQ%3D%22)%20%7B%0A%20%20%20%20%20%20...labelResults%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0Afragment%20labelResults%20on%20LabelConnection%20%7B%0A%20%20pageInfo%20%7B%0A%20%20%20%20endCursor%0A%20%20%7D%0A%20%20edges%20%7B%0A%20%20%20%20cursor%0A%20%20%20%20node%20%7B%0A%20%20%20%20%20%20mbid%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20type%0A%20%20%20%20%20%20area%20%7B%0A%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A& operationName=AppleLabels)):
2016-11-26 20:03:46 +00:00
```graphql
2016-11-26 20:51:19 +00:00
query AppleLabels {
2016-11-26 20:03:46 +00:00
search {
labels(query: "Apple", first: 5, after: "YXJyYXljb25uZWN0aW9uOjQ=") {
...labelResults
}
}
}
```
2016-11-26 21:10:17 +00:00
Who the members of the band on an Apple Records release married, and when
2016-11-27 02:15:00 +00:00
([try it](https://graphbrainz.herokuapp.com/?query=query%20AppleRecordsMarriages%20%7B%0A%20%20search%20%7B%0A%20%20%20%20labels(query%3A%20%22Apple%20Records%22%2C%20first%3A%201)%20%7B%0A%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20disambiguation%0A%20%20%20%20%20%20%20%20%20%20country%0A%20%20%20%20%20%20%20%20%20%20releases(first%3A%201)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20date%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20artists%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...bandMembers%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0Afragment%20bandMembers%20on%20Artist%20%7B%0A%20%20relationships%20%7B%0A%20%20%20%20artists(direction%3A%20%22backward%22%2C%20type%3A%20%22member%20of%20band%22)%20%7B%0A%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20type%0A%20%20%20%20%20%20%20%20%20%20target%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20...%20on%20Artist%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20...marriages%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0Afragment%20marriages%20on%20Artist%20%7B%0A%20%20relationships%20%7B%0A%20%20%20%20artists(type%3A%20%22married%22)%20%7B%0A%20%20%20%20%20%20edges%20%7B%0A%20%20%20%20%20%20%20%20node%20%7B%0A%20%20%20%20%20%20%20%20%20%20type%0A%20%20%20%20%20%20%20%20%20%20direction%0A%20%20%20%20%20%20%20%20%20%20begin%0A%20%20%20%20%20%20%20%20%20%20end%0A%20%20%20%20%20%20%20%20%20%20target%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20...%20on%20Artist%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A& operationName=AppleRecordsMarriages)):
2016-11-26 21:10:17 +00:00
```graphql
query AppleRecordsMarriages {
search {
labels(query: "Apple Records", first: 1) {
edges {
node {
name
disambiguation
country
releases(first: 1) {
edges {
node {
title
date
artists {
edges {
node {
name
2016-11-27 02:15:00 +00:00
...bandMembers
2016-11-26 21:10:17 +00:00
}
}
}
}
}
}
}
}
}
}
}
2016-11-27 02:15:00 +00:00
fragment bandMembers on Artist {
relationships {
artists(direction: "backward", type: "member of band") {
edges {
node {
type
target {
... on Artist {
name
...marriages
}
}
}
}
}
}
}
fragment marriages on Artist {
relationships {
artists(type: "married") {
edges {
node {
type
direction
begin
end
target {
... on Artist {
name
}
}
}
}
}
}
}
2016-11-26 21:10:17 +00:00
```
2016-12-10 03:42:13 +00:00
You can find more example queries in the [schema tests][].
2016-11-26 07:08:54 +00:00
## Questions
2016-11-26 19:55:06 +00:00
**What’ s with the cumbersome `edges` /`node` nesting? Why `first` /`after`
instead of `limit` /`offset`? Why `mbid` instead of `id` ?**
2016-11-26 07:10:39 +00:00
You can thank [Relay][] for that; these are properties of a Relay-compliant
2016-11-26 19:55:06 +00:00
schema. The schema was originally designed to be more user-friendly, but in the
2016-11-27 19:33:43 +00:00
end I decided that being compatible with Relay was a worthwhile feature. I
agree, it’ s ugly.
2016-11-26 07:08:54 +00:00
2016-12-03 01:47:46 +00:00
Don’ t forget, though, that you can use [GraphQL aliases][aliases] to rename
fields to your liking. For example, the following query renames `edges` , `node` ,
and `mbid` to `results` , `releaseGroup` , and `id` , respectively:
```graphql
query ChristmasAlbums {
search {
releaseGroups(query: "Christmas") {
results: edges {
releaseGroup: node {
id: mbid
title
}
}
}
}
}
```
2016-12-01 07:24:19 +00:00
**Why does my query take so long?**
It’ s likely that your query requires multiple round trips to the MusicBrainz
REST API, which is subject to [rate limiting][]. While the query resolver tries
very hard to fetch only the data necessary, and with the smallest number of
API requests, it is not 100% optimal (yet). Make sure you are only requesting
the fields you need and a reasonable level of nested entities – unless you are
willing to wait.
You can also set up a [local MusicBrainz mirror][mirror] and configure
2016-12-21 02:04:08 +00:00
GraphBrainz to use that with no rate limiting.
2016-12-01 07:24:19 +00:00
2016-08-20 05:59:32 +00:00
## Schema
2016-11-29 03:33:52 +00:00
See the [GraphQL schema][schema] or the [types][] documentation.
2016-11-26 02:18:41 +00:00
2016-11-26 02:31:06 +00:00
[demo]: https://graphbrainz.herokuapp.com/
2016-11-26 02:18:41 +00:00
[Express]: http://expressjs.com/
[MusicBrainz]: https://musicbrainz.org/
[GraphQL]: http://graphql.org/
[express-graphql]: https://www.npmjs.com/package/express-graphql
[dotenv]: https://www.npmjs.com/package/dotenv
[debug]: https://www.npmjs.com/package/debug
[GraphiQL]: https://github.com/graphql/graphiql
2016-12-21 02:04:08 +00:00
[graphql-js]: https://github.com/graphql/graphql-js
2016-11-26 07:08:54 +00:00
[Relay]: https://facebook.github.io/relay/
2016-11-29 03:33:52 +00:00
[schema]: docs/schema.md
[types]: docs/types.md
2016-12-01 07:24:19 +00:00
[rate limiting]: https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting
[mirror]: https://musicbrainz.org/doc/MusicBrainz_Server/Setup
2016-12-03 01:47:46 +00:00
[aliases]: http://graphql.org/learn/queries/#aliases
2016-12-10 03:42:54 +00:00
[schema tests]: test/schema.js