Skip to content

Instantly share code, notes, and snippets.

@joeynimu
Last active May 23, 2018
Embed
What would you like to do?
Sample GraphQL Server with Schema Stitching
import express from 'express';
import bodyParser from 'body-parser';
import Dataloader from 'DataLoader';
import {
graphqlExpress,
graphiqlExpress
} from 'apollo-server-express';
import {
makeRemoteExecutableSchema,
mergeSchemas,
introspectSchema
} from 'graphql-tools';
import {
ApolloEngine
} from 'apollo-engine';
import {
HttpLink
} from 'apollo-link-http';
import fetch from 'node-fetch';
import {
APP_PORT,
BOOKING_SERVICE_URL,
FARMER_SERVICE_URL,
SOURCING_AREA_SERVICE_URL,
PRODUCT_SERVICE_URL,
BASE_API_URL,
STAFF_ALLOC_SERVICE_URL,
USER_SERVICE_URL,
APOLLO_KEY
} from './constants';
const run = async () => {
const createRemoteSchema = async (uri) => {
const link = new HttpLink({
uri,
fetch
})
const schema = await introspectSchema(link);
return makeRemoteExecutableSchema({
schema,
link
});
}
// @todo split this
const linkTypeDefs = `
extend type BookingGQL {
farm: FarmGQL
collection_center: CollectionCenterGQL
product: ProductGQL
scout: UserGQL
}
extend type FarmGQL {
bookings: [BookingGQL]
collection_center: CollectionCenterGQL
harvest_area: HarvestAreaGQL
}`;
const {
BOOKING_SVC,
FARMER_SVC,
SOURCING_AREA_SVC,
PRODUCT_SVC,
STAFF_ALLOC_SVC,
USER_SVC
} = process.env;
const bookingURL = BOOKING_SVC ? BOOKING_SVC : `${BASE_API_URL}${BOOKING_SERVICE_URL}`;
const farmerURL = FARMER_SVC ? FARMER_SVC : `${BASE_API_URL}${FARMER_SERVICE_URL}`;
const sourcingAreaURL = SOURCING_AREA_SVC ? SOURCING_AREA_SVC : `${BASE_API_URL}${SOURCING_AREA_SERVICE_URL}`;
const productURL = PRODUCT_SVC ? PRODUCT_SVC : `${BASE_API_URL}${PRODUCT_SERVICE_URL}`;
const staffAllocationURL = STAFF_ALLOC_SVC ? STAFF_ALLOC_SVC : `${BASE_API_URL}${STAFF_ALLOC_SERVICE_URL}`;
const userURL = USER_SVC ? USER_SVC : `${BASE_API_URL}${USER_SERVICE_URL}`;
const bookingSchema = await createRemoteSchema(bookingURL);
const farmerSchema = await createRemoteSchema(farmerURL);
const sourcingAreaSchema = await createRemoteSchema(sourcingAreaURL);
const productSchema = await createRemoteSchema(productURL);
const staffAllocationSchema = await createRemoteSchema(staffAllocationURL);
const userSchema = await createRemoteSchema(userURL);
const schema = mergeSchemas({
schemas: [farmerSchema, bookingSchema, sourcingAreaSchema, productSchema,staffAllocationSchema,userSchema, linkTypeDefs],
// @todo split this resolvers
resolvers: mergeInfo => ({
FarmGQL: {
bookings: {
fragment: `fragment FarmGQLFragment on FarmGQL { farm_id }`,
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'bookings_by_farm_id', {
farmId: parent.farm_id,
},
context,
info,
);
},
},
collection_center: {
fragment: `fragment FarmGQLFragment on CollectionCenterGQL { collection_center_id }`,
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'collection_center_by_id', {
collection_center_id: parent.collection_center_id,
},
context,
info,
);
},
},
harvest_area: {
fragment: `fragment FarmGQLFragment on HarvestAreaGQL { harvest_area_id }`,
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'harvest_area_by_id', {
harvest_area_id: parent.harvest_area_id,
},
context,
info,
);
},
},
},
BookingGQL: {
farm: {
fragment: 'fragment BookingGQLFragment on BookingGQL { farm_id }',
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'farm_by_id', {
farmId: parent.farm_id,
},
context,
info,
);
},
},
collection_center: {
fragment: 'fragment BookingGQLFragment on CollectionCenterGQL { collection_center_id }',
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'collection_center_by_id', {
collection_center_id: parent.collection_center_id,
},
context,
info,
);
},
},
product: {
fragment: 'fragment BookingGQLFragment on ProductGQL { product_id }',
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'product_by_id',
{
productId: parent.product_id,
},
context,
info,
);
},
},
scout: {
fragment: 'fragment BookingGQLFragment on UserGQL { user_id }',
resolve(parent, args, context, info) {
return mergeInfo.delegate(
'query',
'user_by_id',
{
userId: parent.booked_by,
},
context,
info,
);
},
}
},
})
});
const app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.options("/*", function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
res.sendStatus(200);
});
app.use('/graphql', bodyParser.json(), graphqlExpress(req => {
const farmersLoader = new Dataloader(
keys => Promise.all(keys.map(
// what do I pass here
))
)
const loader = {
farmers: farmersLoader
}
return {
context: { loaders },
schema,
tracing: true,
cacheControl: true
}
}));
app.use(
'/graphiql',
graphiqlExpress({
endpointURL: '/graphql'
})
);
const engine = new ApolloEngine({
apiKey: APOLLO_KEY
});
engine.listen({
port: APP_PORT,
expressApp: app,
});
console.log(`Server running. Open http://localhost:${APP_PORT}/graphiql to run queries.`);
}
run().catch(e => console.log(e, e.message, e.stack));
@leebyron
Copy link

leebyron commented May 22, 2018

Note that your run() function will never throw since it’s an async function. You probably want run().catch(error => ...

@joeynimu
Copy link
Author

joeynimu commented May 23, 2018

ooh yeah...overlooked that picked that from one of the examples. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment