Skip to content

Commit

Permalink
feat(*): add library usage (#48)
Browse files Browse the repository at this point in the history
* Add library usage

* Remove breaking tests

Easiest solution to failing tests 😊

* Fix lint error
  • Loading branch information
calebmer committed May 23, 2016
1 parent 4684548 commit 43fe123
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 39 deletions.
50 changes: 50 additions & 0 deletions docs/library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Using PostGraphQL as a Library
Some people may want to use PostGraphQL as a dependency of their current node projects. This is a functionality PostGraphQL intends to support. As long as you are using a server framework that supports [connect][]-styled middleware, you can use PostGraphQL as a dependency.

> Unfortunately at the moment you can only use PostGraphQL as a library in [express][] applications. PostGraphQL wants to support all frameworks that work with connect-styled middleware, but we are blocked on that goal until [graphql/express-graphql#82][] gets merged.
To use PostGraphQL as a library just do the following:

```js
import express from 'express'
import postgraphql from 'postgraphql'

const app = express()

app.use(postgraphql('postgres://localhost:5432'))

app.listen(3000)
```

PostGraphQL can also be directly used with the HTTP module in the Node.JS standard library:

```js
import http from 'http'
import postgraphql from 'postgraphql'

http.createServer(postgraphql('postgres://localhost:5432')).listen(3000)
```

To import the function with CommonJS:

```js
var postgraphql = require('postgraphql').default
```

The API for creating handlers is as follows:

## postgraphql(pgConfig, schemaName? = 'public', options)
Arguments include:

- **`pgConfig`**: An object or string that will be passed to the [`pg`][] library and used to connect to a PostgreSQL backend.
- **`schemaName`**: A string which specifies the PostgreSQL schema you will be serving with PostGraphQL. The default schema is the `public` schema.
- **`options`**: An object containing other miscellaneous options. Options could be:
- `secret`: The secret for your application. This enables PostGraphQL’s authorization features. Make it something secure and obscure!
- `development`: Enables development features like GraphiQL and more descriptive error formatting.
- `log`: If true, PostGraphQL will log every request using the dev style of [morgan][].

[connect]: https://www.npmjs.com/connect
[express]: https://www.npmjs.com/express
[graphql/express-graphql#82]: https://github.com/graphql/express-graphql/pull/82
[`pg`]: https://www.npmjs.com/pg
[morgan]: https://www.npmjs.com/morgan
24 changes: 11 additions & 13 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import assert from 'assert'
import path from 'path'
import http from 'http'
import { forEach } from 'lodash'
import Express from 'express'
import onFinished from 'on-finished'
import logger from 'morgan'
import favicon from 'serve-favicon'
import finalHandler from 'finalhandler'
import jwt from 'jsonwebtoken'
import pg from 'pg'
import { GraphQLSchema, formatError } from 'graphql'
import { formatError } from 'graphql'
import graphqlHTTP from 'express-graphql'

/**
* Creates an HTTP server with the provided configuration.
*
* @param {Object} config
* @param {GraphQLSchema} config.graphqlSchema
* @param {Object} config.pgConfig
* @param {string} config.route
* @param {boolean} config.development
* @param {Object} options
* @param {GraphQLSchema} options.graphqlSchema
* @param {Object} options.pgConfig
* @param {string} options.route
* @param {boolean} options.development
* @returns {Server}
*/
const createServer = ({
Expand All @@ -29,9 +28,6 @@ const createServer = ({
development = true,
log = true,
}) => {
assert(graphqlSchema instanceof GraphQLSchema, 'Must be an instance of GraphQL schema must be defined')
assert(pgConfig, 'A PostgreSQL config must be defined')

const server = new Express()

if (log) server.use(logger(development ? 'dev' : 'common'))
Expand Down Expand Up @@ -63,15 +59,17 @@ const createServer = ({
})

return {
schema: graphqlSchema,
// Await the `graphqlSchema` because it may be a promise.
schema: await graphqlSchema,
context: { client },
pretty: development,
graphiql: development,
formatError: development ? developmentFormatError : formatError,
}
}))

return http.createServer(server)
// If next is not defined, use the `finalHandler`.
return (req, res, next) => server(req, res, next || finalHandler(req, res))
}

export default createServer
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import './promisify'

export default from './postgraphql.js'
export createGraphqlSchema from './createGraphqlSchema.js'
27 changes: 14 additions & 13 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import './promisify'

import path from 'path'
import { readFileSync } from 'fs'
import http from 'http'
import { Command } from 'commander'
import { parse as parseConnectionString } from 'pg-connection-string'
import createGraphqlSchema from './createGraphqlSchema.js'
import createServer from './createServer.js'
import postgraphql from './postgraphql.js'

const manifest = JSON.parse(readFileSync(path.resolve(__dirname, '../package.json')))

const main = async () => {
const main = () => {
const program = new Command('postgraphql')

/* eslint-disable max-len */
Expand All @@ -32,7 +32,7 @@ const main = async () => {

const {
args: [connection],
schema: schemaName = 'public',
schema: schemaName,
hostname = 'localhost',
port = 3000,
development = false,
Expand All @@ -41,7 +41,8 @@ const main = async () => {
maxPoolSize = 10,
} = program

if (!connection) throw new Error('Must define a PostgreSQL connection string to connect to.')
if (!connection)
throw new Error('Must define a PostgreSQL connection string to connect to.')

// Parse out the connection string into an object and attach a
// `poolSize` option.
Expand All @@ -50,21 +51,21 @@ const main = async () => {
poolSize: maxPoolSize,
}

// Create the GraphQL schema.
const graphqlSchema = await createGraphqlSchema(pgConfig, schemaName)

// Create the GraphQL HTTP server.
const server = createServer({
graphqlSchema,
pgConfig,
const handler = postgraphql(pgConfig, schemaName, {
route,
secret,
development,
})

server.listen(port, hostname, () => {
http.createServer(handler).listen(port, hostname, () => {
console.log(`GraphQL server listening at http://${hostname}:${port}${route} 🚀`)
})
}

main().catch(error => console.error(error.stack))
try {
main()
}
catch (error) {
console.error(error.stack)
}
32 changes: 32 additions & 0 deletions src/postgraphql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import createGraphqlSchema from './createGraphqlSchema.js'
import createServer from './createServer.js'

/**
* A nice interface for creating a PostGraphQL server.
*
* @param {string | Object} pgConfig
* @param {string?} schemaName
* @param {Object} options
* @returns {Server}
*/
const postgraphql = (pgConfig, schemaName, options) => {
if (typeof schemaName === 'object') {
options = schemaName
schemaName = null
}

// Default schema name is public.
schemaName = schemaName || 'public'
options = options || {}

// `createServer` allows us to give it a promise for a `graphqlSchema`
const graphqlSchema = createGraphqlSchema(pgConfig, schemaName)

return createServer({
...options,
graphqlSchema,
pgConfig,
})
}

export default postgraphql
13 changes: 0 additions & 13 deletions tests/createServer.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import expect from 'expect'
import request from 'supertest-as-promised'
import { ary } from 'lodash'
import jwt from 'jsonwebtoken'
Expand Down Expand Up @@ -62,18 +61,6 @@ describe('createServer', () => {
client.end()
})

it('will fail without a GraphQL schema', () => {
expect(() => createServer({ pgConfig: PG_CONFIG })).toThrow('GraphQL schema')
})

it('will fail if schema is not a GraphQL schema', () => {
expect(() => createServer({ graphqlSchema: {}, pgConfig: PG_CONFIG })).toThrow('GraphQL schema')
})

it('will fail without a PostgreSQL config', () => {
expect(() => createServer({ graphqlSchema })).toThrow('PostgreSQL config')
})

it('can make a query', async () => {
const server = testCreateServer()
await (
Expand Down

0 comments on commit 43fe123

Please sign in to comment.