Skip to content

Commit 840d2ac

Browse files
authored
feat(handler): handler/middleware all only take ctx as its argument (#30)
1 parent 528c643 commit 840d2ac

19 files changed

+179
-226
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Logs
2-
2+
.DS_Store
33
logs
44
_.log
55
npm-debug.log_

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type Query {
1717
hello: String
1818
}
1919
`
20-
app.register(schema, () => 'world')
20+
app.handle(schema, (ctx: Context) => 'world')
2121

2222
export default app
2323
```
@@ -48,6 +48,10 @@ const helloworld: GraphQLSchema = new GraphQLSchema({
4848
},
4949
})
5050
})
51+
52+
app.handle(helloworld)
53+
54+
export default app
5155
```
5256

5357
### Middlewares

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "edgeql",
3-
"version": "0.0.10",
3+
"version": "0.1.0",
44
"license": "MIT",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/app.test.ts

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GraphQLObjectType, GraphQLString, GraphQLSchema } from 'graphql'
22
import { describe, expect, it } from 'vitest'
33
import { EdgeQL } from './app'
4+
import type { Context } from './context/context'
45

56
describe('App', () => {
67
it('should fail when no schema registered', async () => {
@@ -43,7 +44,7 @@ describe('App', () => {
4344
},
4445
},
4546
})
46-
app.register(new GraphQLSchema({ query: queryType }))
47+
app.handle(new GraphQLSchema({ query: queryType }))
4748

4849
const req = new Request('http://localhost', {
4950
method: 'POST',
@@ -81,7 +82,7 @@ describe('App', () => {
8182
},
8283
},
8384
})
84-
app.register(new GraphQLSchema({ query: queryType }))
85+
app.handle(new GraphQLSchema({ query: queryType }))
8586

8687
const req = new Request('http://localhost', {
8788
method: 'POST',
@@ -111,15 +112,15 @@ type Query {
111112
hello: String
112113
}
113114
`
114-
app.register(schema, () => 'world')
115+
app.handle(schema, (ctx: Context) => 'world')
115116

116-
app.register(
117+
app.handle(
117118
`
118119
type Query {
119120
hi: String
120121
}
121122
`,
122-
() => 'world'
123+
(ctx: Context) => 'world'
123124
)
124125

125126
let req = new Request('http://localhost', {
@@ -165,7 +166,7 @@ type Query {
165166

166167
it('should work when schema string mulitiple query registered', async () => {
167168
const app = new EdgeQL()
168-
app.register(
169+
app.handle(
169170
`
170171
type Query {
171172
hi: String
@@ -174,9 +175,9 @@ type Query {
174175
}
175176
`,
176177
{
177-
hello: () => 'world',
178-
hi: () => 'world',
179-
ping: () => 'pong',
178+
hello: async (ctx: Context) => 'world',
179+
hi: async (ctx: Context) => 'world',
180+
ping: async (ctx: Context) => 'pong',
180181
}
181182
)
182183

@@ -251,8 +252,8 @@ type Query {
251252
hello: String
252253
}
253254
`
254-
app.register(schema, (parent, args, ctx) => {
255-
return `${ctx.env.db} world`
255+
app.handle(schema, (ctx: Context) => {
256+
return `${ctx.runtime?.env?.db} world`
256257
})
257258
const req = new Request('http://localhost', {
258259
method: 'POST',

src/app.ts

+49-35
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { mergeSchemas } from '@graphql-tools/schema'
2-
import type { GraphQLFieldResolver, GraphQLField, GraphQLSchema } from 'graphql'
2+
import type { GraphQLField, GraphQLSchema } from 'graphql'
33
import { buildSchema, validateSchema, GraphQLObjectType, execute, GraphQLError } from 'graphql'
44
import { compose } from './compose'
5-
import { Context } from './context'
6-
import type { ExecutionContext, Environment, Middleware } from './types'
5+
import { Context } from './context/context'
6+
import type { ExecutionContext, Environment, Middleware, Handler } from './types'
77

88
export class EdgeQL {
99
private schemas: GraphQLSchema[] = []
@@ -24,7 +24,7 @@ export class EdgeQL {
2424

2525
let ctx: Context
2626
try {
27-
ctx = await Context.create(request, env, exeContext, this.graph)
27+
ctx = new Context(request, env, exeContext)
2828
} catch (e) {
2929
return new Response(
3030
JSON.stringify({
@@ -40,15 +40,18 @@ export class EdgeQL {
4040
)
4141
}
4242

43-
await compose([...this.middlewares, this.handle])(ctx)
43+
await ctx.graphql.init(ctx.http.request)
44+
ctx.graphql.schema = this.graph
45+
46+
await compose([...this.middlewares, this.execute])(ctx)
4447

4548
return ctx.json()
4649
}
4750

48-
async handle(ctx: Context) {
49-
if (!ctx.req?.query) {
50-
ctx.res.status = 400
51-
ctx.res.body = {
51+
async execute(ctx: Context) {
52+
if (!ctx.graphql.query) {
53+
ctx.http.status = 400
54+
ctx.http.body = {
5255
data: null,
5356
errors: [
5457
new GraphQLError('Must provide query string', {
@@ -61,12 +64,12 @@ export class EdgeQL {
6164
return
6265
}
6366

64-
if (!ctx.req?.document) {
65-
ctx.res.status = 400
66-
ctx.res.body = {
67+
if (!ctx.graphql.document) {
68+
ctx.http.status = 400
69+
ctx.http.body = {
6770
data: null,
6871
errors: [
69-
new GraphQLError(`could not generate document from query: ${ctx.req?.query}`, {
72+
new GraphQLError(`could not generate document from query: ${ctx.graphql.query}`, {
7073
extensions: {
7174
status: 400,
7275
},
@@ -76,9 +79,9 @@ export class EdgeQL {
7679
return
7780
}
7881

79-
if (!ctx.schema) {
80-
ctx.res.status = 400
81-
ctx.res.body = {
82+
if (!ctx.graphql.schema) {
83+
ctx.http.status = 400
84+
ctx.http.body = {
8285
data: null,
8386
errors: [
8487
new GraphQLError('no schem registerred yet', {
@@ -93,19 +96,19 @@ export class EdgeQL {
9396

9497
try {
9598
const res = await execute({
96-
schema: ctx.schema!,
97-
document: ctx.req?.document ?? null,
99+
schema: ctx.graphql.schema!,
100+
document: ctx.graphql.document ?? null,
98101
rootValue: null,
99102
contextValue: ctx,
100-
variableValues: ctx.req?.variables,
101-
operationName: ctx.req?.operationName,
103+
variableValues: ctx.graphql.variables,
104+
operationName: ctx.graphql.operationName,
102105
})
103-
ctx.res.status = 200
104-
ctx.res.body = res
106+
ctx.http.status = 200
107+
ctx.http.body = res
105108
return
106109
} catch (contextError: unknown) {
107-
ctx.res.status = 500
108-
ctx.res.body = {
110+
ctx.http.status = 500
111+
ctx.http.body = {
109112
data: null,
110113
errors: [
111114
new GraphQLError(`GraphQL execution context error: ${contextError}`, {
@@ -122,15 +125,10 @@ export class EdgeQL {
122125
this.middlewares.push(fn)
123126
}
124127

125-
register(schema: GraphQLSchema): void
126-
register(schema: string, resolve: GraphQLFieldResolver<any, any, any, any>): void
127-
register(schema: string, resolves: Record<string, GraphQLFieldResolver<any, any, any, any>>): void
128-
register(
129-
...args:
130-
| [GraphQLSchema]
131-
| [string, GraphQLFieldResolver<any, any, any, any>]
132-
| [string, Record<string, GraphQLFieldResolver<any, any, any, any>>]
133-
): void {
128+
handle(schema: GraphQLSchema): void
129+
handle(schema: string, handler: Handler): void
130+
handle(schema: string, handlers: Record<string, Handler>): void
131+
handle(...args: [GraphQLSchema] | [string, Handler] | [string, Record<string, Handler>]): void {
134132
if (args.length === 1 && typeof args[0] === 'object') {
135133
const schemaValidationErrors = validateSchema(args[0])
136134
if (schemaValidationErrors.length > 0) {
@@ -153,7 +151,12 @@ export class EdgeQL {
153151
if (fields.length !== 1) {
154152
throw new Error('only one of Query, Mutuation, Subscription is allowed')
155153
} else {
156-
fields[0].resolve = args[1]
154+
fields[0].resolve = async (parents: any, arg: any, ctx: Context, info: any) => {
155+
ctx.graphql.args = arg
156+
ctx.graphql.parents = parents
157+
ctx.graphql.info = info
158+
return await (args[1] as Handler)(ctx)
159+
}
157160
}
158161

159162
this.schemas.push(s)
@@ -166,7 +169,18 @@ export class EdgeQL {
166169
if (obj instanceof GraphQLObjectType) {
167170
for (const f of Object.keys(obj.getFields())) {
168171
if (args[1][f]) {
169-
obj.getFields()[f].resolve = args[1][f]
172+
obj.getFields()[f].resolve = async (
173+
parents: any,
174+
arg: any,
175+
ctx: Context,
176+
info: any
177+
) => {
178+
ctx.graphql.parents = parents
179+
ctx.graphql.args = arg
180+
ctx.graphql.info = info
181+
const fn = (args[1] as any)[f] as Handler
182+
return await fn(ctx)
183+
}
170184
} else {
171185
throw new Error(`no resolve function for ${obj.getFields()[f]}`)
172186
}

src/compose.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Context } from './context'
1+
import type { Context } from './context/context'
22
import type { Middleware, Next } from './types'
33

44
export function compose(middleware: Middleware[]) {

src/context.ts

-63
This file was deleted.
File renamed without changes.

src/context/context.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { ExecutionContext, Environment } from '../types'
2+
import { GraphQLContext } from './graphql'
3+
import { HttpContext } from './http'
4+
import { RuntimeContext } from './runtime'
5+
6+
export class Context {
7+
public readonly runtime: RuntimeContext
8+
public readonly http: HttpContext
9+
public readonly graphql: GraphQLContext
10+
11+
constructor(request: Request, env?: Environment, exeContext?: ExecutionContext) {
12+
this.runtime = new RuntimeContext(env, exeContext)
13+
this.http = new HttpContext(request)
14+
this.graphql = new GraphQLContext()
15+
}
16+
17+
json(): Response {
18+
return this.http.toJSON()
19+
}
20+
}

0 commit comments

Comments
 (0)