I'm submitting a ...
PostGraphile version: 4.0.0-beta.3
I was wondering what is the best way to integrate Apollo Engine with Postgraphile. Is there a recommended way of modifying Postgraphile's behavior or do I only have the option of the plugin system?
Please share what you've tried so far; given the example on their homepage I'd expect you to just be able to mount the middleware into an express app and use engine.
Just chiming in for others who come across this issue, since we tested this out successfully:
They've made it very straightforward in the latest versions. e.g. for our koa app:
const app = new koa();
// Replace your app.listen with engine.listen
engine.listen({
port: 3000,
koaApp: app,
});
https://www.apollographql.com/docs/engine/setup-node.html
馃槃
The downside is that you may not get all the trace details you would get otherwise, since it isn't instrumenting the graphql server itself, the way it would if you were using Apollo Server instead of the stock graphql server that Postgraphile uses. We haven't tried swapping in Apollo Server, since last we heard it was hard: https://github.com/graphile/postgraphile/issues/208
I have a very ugly hack that transforms postgraphile into a local-remoteExecutableSchema.
Given that the types have been downloaded beforehand with something like get-graphql-schema, the hack is this:
const { postgraphile } = require("postgraphile");
import { makeRemoteExecutableSchema } from "graphql-tools";
import * as fs from "fs";
import { FetcherOperation } from "graphql-tools/dist/stitching/makeRemoteExecutableSchema";
import { print } from "graphql/language/printer";
const pg = postgraphile(
process.env.DATABASE_URL
);
const fetcher = ({
query,
variables,
operationName,
context
}: FetcherOperation) => {
const graphqlContext = context ? context.graphqlContext : {};
const { Authorization } = graphqlContext;
return new Promise(resolve => {
pg(
{
url: "http://anything/graphql",
method: "POST",
headers: {
Authorization,
"Content-Type": "application/json"
},
body: { query: print(query), variables, operationName }
},
{
setHeader: () => {},
end: (result: string) => {
resolve(JSON.parse(result));
}
}
);
});
};
const typeDefs = fs.readFileSync("./src/generated/schema.graphql", "utf-8");
const schema = makeRemoteExecutableSchema({ schema: typeDefs, fetcher });
export default schema;
Using it with graphql-binding one could replicate what the Prisma docs and samples do to run with apollo-server.
To use it:
graphql-binding --language typescript --input theFileAbove.ts --outputBinding out.ts
utils.ts
import { Binding } from "./generated/binding";
import { ContextParameters } from "graphql-yoga/dist/types";
export interface Context extends ContextParameters {
db: Binding;
}
export const getBindingContext = (ctx: Context) => {
return {
context: { Authorization: ctx.request.get("Authorization") }
};
};
query.ts
import { Context, getBindingContext } from "../utils";
export const me = async (
_,
__,
ctx: Context,
info
) => {
return ctx.db.query.userById({ id: 1 }, info, getBindingContext(ctx));
};
This is also being very helpful because I want to implement Firebase Phone Auth without having to run another server in front of Postgraphile.
For context, the above comment also appears in https://github.com/graphile/postgraphile/issues/208#issuecomment-405457598
I've prepared a better sample than the one I'd posted above.
Check it out: https://github.com/degroote22/postgraphile-apollo
Continued work done by @degroote22 馃憤
Letting you know that I published starter project for backend development. It uses postgraphile as a library, based on Apollo Server 2.0 and leverages automated code generation and database schema migrations. Check it out here https://github.com/avkonst/graphql-postgraphile-typeorm-starter
Very cool; will take a look later in the week 馃憤
I would recommend not create remote-executable-schema, cause they increase one more steps of request, even if they are in same machine, it will still be a latency issue.
See my answer in another issue #208. It demonstrate how to create a schema and use it with apollo-server. Once you have apollo server working, you can add the apollo engine.
```
import { ApolloEngine } from 'apollo-engine';
import { createServer } from 'http';
import express from 'express';
// Initialize Apollo Engine.
const engine = new ApolloEngine({
apiKey: 'service:xxxxxxxxxxxxxxxxx',
});
// Create apollo server by put it in express.
const app = express();
app.use('/graphql', (req, res, next) => {
const handleGraphQL = graphqlExpress(() => ({
schema: s, // detail on how to get the s in my previous post
context: {
pgClient, // detail on this pgClient also in previous post
},
tracing: true,
cacheControl: true,
}));
// Hacky wrap res.end() to call next() so that we know the request finished
res.endbk = res.end;
res.end = () => {
res.endbk();
next({ name: 'NotError' });// This helps to wrap request in transactions etc. Not necessary for apollo engine purpose.
};
handleGraphQL(req, res, next);
});
const server = createServer(app); // create the http server
engine.listen({
port: process.env.PORT,
httpServer: server,
}, () => {
if (process.env.NODE_ENV !== 'production') {
logger.info(GraphQL Server is now running on http://localhost:${process.env.PORT}/graphql);
logger.info(View GraphiQL at http://localhost:${process.env.PORT}/graphiql);
}
});
@benjie and I have agreed on that the the stitched schema (the above approach that I proposed) needs a lot of attention and have several issues that needs to be fixed, it is not a generic solution for every body.
But generating a remoteExecutableSchema will work nicely. So here I would recommend not using the schema
schema: s, // detail on how to get the s in my previous post
But use a remoteExecutableSchema, (it will work nicely with apollo server)
If you use the remoteExecutableSchema, you'll not have to do all these context stuff that I had wrapped around. So the code is simpler
import { ApolloEngine } from 'apollo-engine';
import { createServer } from 'http';
import express from 'express';
// Initialize Apollo Engine.
const engine = new ApolloEngine({
apiKey: 'service:xxxxxxxxxxxxxxxxx',
});
// Create apollo server by put it in express.
const app = express();
app.use('/graphql', (req, res, next) => {
const handleGraphQL = graphqlExpress(() => ({
schema: s, // use a remoteExecutableSchema, a tool provided by apollo team
context: {
//pgClient, // don't have to do this.
},
tracing: false, // tracing postGraphile does not make much sense
cacheControl: true, // this also may not be necessary because postGraphile does cache also. but I am not sure
}));
};
handleGraphQL(req, res, next);
});
const server = createServer(app); // create the http server
engine.listen({
port: process.env.PORT,
httpServer: server,
}, () => {
if (process.env.NODE_ENV !== 'production') {
logger.info(`GraphQL Server is now running on http://localhost:${process.env.PORT}/graphql`);
logger.info(`View GraphiQL at http://localhost:${process.env.PORT}/graphiql`);
}
});
You can now use PostGraphile directly with Apollo Server (which includes Apollo Engine), here鈥檚 a module to help:
Most helpful comment
You can now use PostGraphile directly with Apollo Server (which includes Apollo Engine), here鈥檚 a module to help:
https://github.com/graphile/postgraphile-apollo-server