Skip to content

Commit

Permalink
proper generics for context, remove graphql interfaces from lib, more…
Browse files Browse the repository at this point in the history
… tests
  • Loading branch information
v1rtl committed Mar 14, 2021
1 parent 56ee69a commit 7a3a83d
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 38 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,14 @@

Universal [GraphQL](https://www.graphql.com/) HTTP middleware for Deno.

## Features

- supports vanilla, tinyhttp and any other backend framework
- re-exports GraphQL interfaces from `graphql_deno`

## Examples

### Vanilla

```ts
import { serve, ServerRequest } from 'https://deno.land/[email protected]/http/server.ts'
import { GraphQLHTTP, GraphQLSchema, GraphQLObjectType, GraphQLString } from 'https://deno.land/x/gql/mod.ts'
import { GraphQLHTTP } from 'https://deno.land/x/gql/mod.ts'
import { GraphQLSchema, GraphQLString, GraphQLObjectType } from 'https://deno.land/x/[email protected]/mod.ts'

const schema = new GraphQLSchema({
query: new GraphQLObjectType({
Expand All @@ -47,7 +43,8 @@ for await (const req of s) {

```ts
import { App, Request } from 'https://deno.land/x/tinyhttp/mod.ts'
import { GraphQLHTTP, GraphQLSchema, GraphQLObjectType, GraphQLString } from 'https://deno.land/x/gql/mod.ts'
import { GraphQLHTTP } from 'https://deno.land/x/gql/mod.ts'
import { GraphQLSchema, GraphQLString, GraphQLObjectType } from 'https://deno.land/x/[email protected]/mod.ts'

const schema = new GraphQLSchema({
query: new GraphQLObjectType({
Expand Down
33 changes: 15 additions & 18 deletions common.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Request } from './types.ts'
import { graphql, ExecutionResult, GraphQLSchema, GraphQLArgs } from './deps.ts'
import { graphql, GraphQLSchema, ExecutionResult } from 'https://deno.land/x/[email protected]/mod.ts'

export type GraphQLOptions = {
export type GraphQLOptions<Context = any, Request = any> = {
schema: GraphQLSchema
context?: (val: any) => any
context?: (val: Request) => Context | Promise<Context>
rootValue?: any
}

Expand All @@ -13,29 +12,27 @@ export type GraphQLParams = {
variables?: Record<string, unknown>
operationName?: string
}

export type ServerContext<T> = { request: Request } & T

/** Returns a GraphQL response. */
export async function runHttpQuery<Context = unknown>(
/**
* Execute a GraphQL query
* @param {GraphQLParams} params
* @param {GraphQLOptions} options
* @param context GraphQL context to use inside resolvers
*/
export async function runHttpQuery<Req extends any = any, Context extends { request: Req } = { request: Req }>(
params: GraphQLParams,
options: GraphQLOptions,
context?: ServerContext<Context>
options: GraphQLOptions<Context, Req>,
context?: Context | any
): Promise<ExecutionResult> {
if (!params) throw new Error('Bad Request')

const contextValue = options.context && context?.request ? await options.context?.(context?.request) : undefined
const source = params.query! || params.mutation!

// https://graphql.org/graphql-js/graphql/#graphql
const graphQLArgs: GraphQLArgs = {
return await graphql({
source,
schema: options.schema,
rootValue: options.rootValue,
...options,
contextValue: contextValue,
variableValues: params.variables,
operationName: params.operationName
}

return await graphql(graphQLArgs)
})
}
3 changes: 0 additions & 3 deletions deps.ts

This file was deleted.

4 changes: 2 additions & 2 deletions examples/tinyhttp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { App } from 'https://deno.land/x/tinyhttp/mod.ts'
import { GraphQLHTTP, GraphQLSchema, GraphQLObjectType, GraphQLString } from '../mod.ts'

import { GraphQLHTTP } from '../mod.ts'
import { GraphQLSchema, GraphQLString, GraphQLObjectType } from 'https://deno.land/x/[email protected]/mod.ts'
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
Expand Down
5 changes: 3 additions & 2 deletions examples/vanilla.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { serve, ServerRequest } from 'https://deno.land/[email protected]/http/server.ts'
import { GraphQLHTTP, GraphQLSchema, GraphQLObjectType, GraphQLString } from '../mod.ts'
import { serve } from 'https://deno.land/[email protected]/http/server.ts'
import { GraphQLHTTP } from '../mod.ts'
import { GraphQLSchema, GraphQLString, GraphQLObjectType } from 'https://deno.land/x/[email protected]/mod.ts'

const schema = new GraphQLSchema({
query: new GraphQLObjectType({
Expand Down
16 changes: 12 additions & 4 deletions http.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { Request } from './types.ts'
import { runHttpQuery, GraphQLParams, GraphQLOptions } from './common.ts'
import { runHttpQuery, GraphQLOptions } from './common.ts'

const dec = new TextDecoder()

export function GraphQLHTTP(options: GraphQLOptions) {
return async (request: Request) => {
/**
* Create a new GraphQL HTTP middleware with schema, context etc
* @param {GraphQLOptions} options
*/
export function GraphQLHTTP<Req extends Request = Request, Ctx extends { request: Req } = { request: Req }>(
options: GraphQLOptions<Ctx, Req>
) {
return async (request: Req) => {
if (!['PUT', 'POST', 'PATCH'].includes(request.method)) {
request.respond({
status: 405,
Expand All @@ -17,7 +23,9 @@ export function GraphQLHTTP(options: GraphQLOptions) {
try {
const params = JSON.parse(dec.decode(body))

const result = await runHttpQuery(params, options, { request })
const result = await runHttpQuery<Req, Ctx>(params, options, {
request
})

request.respond({ body: JSON.stringify(result, null, 2), status: 200 })
} catch (e) {
Expand Down
1 change: 0 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './http.ts'
export * from './common.ts'
export * from './deps.ts'
export * from './types.ts'
30 changes: 29 additions & 1 deletion test/mod.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { superdeno } from 'https://deno.land/x/[email protected]/mod.ts'
import { GraphQLHTTP } from '../http.ts'
import { runHttpQuery } from '../common.ts'
import { GraphQLSchema, GraphQLString, GraphQLObjectType, GraphQLError } from '../deps.ts'
import { GraphQLSchema, GraphQLString, GraphQLObjectType } from 'https://deno.land/x/[email protected]/mod.ts'
import { describe, it, run, expect } from 'https://deno.land/x/[email protected]/mod.ts'
import { ServerRequest } from 'https://deno.land/[email protected]/http/server.ts'

const schema = new GraphQLSchema({
query: new GraphQLObjectType({
Expand Down Expand Up @@ -39,6 +40,33 @@ describe('GraphQLHTTP(opts)', () => {
.send('{ "query": "{ hello }" }')
.expect(200, '{\n "data": {\n "hello": "Hello World!"\n }\n}')
})
it('should pass req obj to server context', async () => {
type Context = { request: ServerRequest }
const schema = new GraphQLSchema({
query: new GraphQLObjectType<unknown, Context>({
name: 'Query',
fields: {
hello: {
type: GraphQLString,
resolve(_1, _2, { request }) {
return `Request from ${request.url}`
}
}
}
})
})
const app = GraphQLHTTP<ServerRequest, Context>({
schema,
context: (request) => ({ request })
})

const request = superdeno(app)

await request
.post('/')
.send('{ "query": "{ hello }" }')
.expect(200, '{\n "data": {\n "hello": "Request from /"\n }\n}')
})
})

describe('runHttpQuery(params, options, context)', () => {
Expand Down

0 comments on commit 7a3a83d

Please sign in to comment.