Permalink
Browse files

Implements GraphQL server + sample schema for Artwork and Artist

  • Loading branch information...
dzucconi committed Oct 22, 2015
1 parent 9c3905b commit 50b23f1738b9fa9757ff83c2d1e0d265c70e4e90
Showing with 284 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +1 −0 Procfile.dev
  3. +2 −0 index.js
  4. +23 −0 lib/artsy.js
  5. +25 −0 package.json
  6. +18 −0 schema.js
  7. +47 −0 schema/artist.js
  8. +64 −0 schema/artwork.js
  9. +61 −0 schema/image.js
  10. +23 −0 schema/ping.js
  11. +17 −0 server.js
@@ -0,0 +1,3 @@
.env
.DS_Store
node_modules
@@ -0,0 +1 @@
web: node_modules/.bin/nodemon index.js
@@ -0,0 +1,2 @@
require('babel/register');
require('./server.js');
@@ -0,0 +1,23 @@
import request from 'request';

export default function(path, data) {
if (typeof path !== 'string') {
path = path.join('/');
};

return new Promise((resolve, reject) => {
let url = process.env.API_ENDPOINT + '/' + path;

console.log('requesting:', url);

request(url, {
headers: { 'X-AUTHENTICATION-TOKEN': process.env.AUTHENTICATION_TOKEN },
method: 'GET',
qs: data,
}, (err, response) => {
if (err) return reject(err);
let parsed = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
resolve(parsed);
});
});
};
@@ -0,0 +1,25 @@
{
"name": "metaphysics",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel": "^5.8.23",
"babel-core": "^5.8.25",
"express": "^4.13.3",
"express-graphql": "^0.4.0",
"graphiql": "^0.3.1",
"graphql": "^0.4.7",
"lodash": "^3.10.1",
"react": "^0.14.0",
"request": "^2.65.0"
},
"devDependencies": {
"nodemon": "^1.7.3"
}
}
@@ -0,0 +1,18 @@
import { GraphQLSchema, GraphQLObjectType } from 'graphql';

import Ping from './schema/ping';
import Artwork from './schema/artwork';
import Artist from './schema/artist';

var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
ping: Ping,
artwork: Artwork,
artist: Artist
}
})
});

export default schema;
@@ -0,0 +1,47 @@
import artsy from '../lib/artsy';
import Artwork from './artwork';
import {
GraphQLObjectType,
GraphQLBoolean,
GraphQLString,
GraphQLNonNull,
GraphQLList,
GraphQLInt
} from 'graphql';

let ArtistType = new GraphQLObjectType({
name: 'Artist',
fields: () => ({
id: { type: GraphQLString },
sortable_id: {
type: GraphQLString,
description: 'Use this attribute to sort by when sorting a collection of Artists'
},
name: { type: GraphQLString },
birthday: { type: GraphQLString },
artworks: {
type: new GraphQLList(Artwork.type),
args: { size: { type: GraphQLInt } },
resolve: ({ id }, { size }) => {
return artsy(['artist', id, 'artworks'], {
published: true,
size: size
});
}
}
})
});

let Artist = {
type: ArtistType,
description: 'An Artist',
args: {
id: {
description: 'The slug or ID of the Artist',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, { id }) => artsy(['artist', id])
};

export default Artist;
@@ -0,0 +1,64 @@
import _ from 'lodash';
import artsy from '../lib/artsy';
import Artist from './artist';
import Image from './image';
import {
GraphQLObjectType,
GraphQLBoolean,
GraphQLString,
GraphQLNonNull,
GraphQLList
} from 'graphql';

let ArtworkType = new GraphQLObjectType({
name: 'Artwork',
fields: () => ({
id: { type: GraphQLString },
title: { type: GraphQLString },
category: { type: GraphQLString },
medium: { type: GraphQLString },
date: { type: GraphQLString },
is_contactable: {
type: GraphQLBoolean,
description: 'Are we able to display a contact form on artwork pages?',
resolve: (artwork) => {
return artwork.forsale && !_.isEmpty(artwork.partner) && !artwork.acquireable;
}
},
artist: {
type: Artist.type,
resolve: ({ artist }) => {
return artsy(['artist', artist.id])
}
},
dimensions: {
type: new GraphQLObjectType({
name: 'dimensions',
fields: {
in: { type: GraphQLString },
cm: { type: GraphQLString }
}
})
},
images: {
type: new GraphQLList(Image.type),
resolve: ({ images }) => images
}
})
});

let Artwork = {
type: ArtworkType,
description: 'An Artwork',
args: {
id: {
description: 'The slug or ID of the Artwork',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, { id }) => {
return artsy(['artwork', id])
}
};

export default Artwork;
@@ -0,0 +1,61 @@
import _ from 'lodash';
import artsy from '../lib/artsy';
import {
GraphQLObjectType,
GraphQLString,
GraphQLList,
GraphQLFloat,
GraphQLInt
} from 'graphql';

let ResizedImageUrl = (image, options) => {
let factor = _.min(_.map(options, (value, attr) => {
return value / image[`original_${attr}`];
}));

let width = Math.floor(image.original_width * factor);
let height = Math.floor(image.original_height * factor);

let url = `http://some_caching_resizing_cdn.com/${width}/${height}/${encodeURIComponent(image.image_url.replace(':version', 'original'))}`;

return {
factor,
width,
height,
url
};
};

let ResizedImageUrlType = new GraphQLObjectType({
name: 'ResizedImageUrl',
fields: {
factor: { type: GraphQLFloat },
width: { type: GraphQLInt },
height: { type: GraphQLInt },
url: { type: GraphQLString }
}
});

let ImageType = new GraphQLObjectType({
name: 'Image',
fields: () => ({
id: { type: GraphQLString },
width: { type: GraphQLInt, resolve: ({ original_width }) => original_width },
height: { type: GraphQLInt, resolve: ({ original_height }) => original_height },
aspect_ratio: { type: GraphQLFloat },
url: {
args: {
width: { type: GraphQLInt },
height: { type: GraphQLInt }
},
type: ResizedImageUrlType,
resolve: (image, options) => ResizedImageUrl(image, options)
}
})
});

let Image = {
type: ImageType
};

export default Image;
@@ -0,0 +1,23 @@
import artsy from '../lib/artsy';
import {
GraphQLObjectType,
GraphQLString
} from 'graphql';

let PingType = new GraphQLObjectType({
name: 'Ping',
description: 'System ping',
fields: {
ping: {
type: GraphQLString,
description: 'Is the system up or down?'
}
}
});

let Ping = {
type: PingType,
resolve: () => artsy(['system', 'ping'])
};

export default Ping;
@@ -0,0 +1,17 @@
import path from 'path';
import express from 'express';
import graphqlHTTP from 'express-graphql';
import schema from './schema';

let app = express();
let port = process.env.PORT || 3000;

app.all('/graphql', (req, res) => res.redirect('/'));
app.use('/', graphqlHTTP(() => ({
schema: schema,
graphiql: true
})));

app.listen(port, () => {
console.log(`Listening on ${port}`);
});

0 comments on commit 50b23f1

Please sign in to comment.