Skip to content

Commit

Permalink
Merge branch 'main' of github.com:coratgerl/wobe
Browse files Browse the repository at this point in the history
  • Loading branch information
coratgerl committed Jun 5, 2024
2 parents 55640db + a20a443 commit 4a04ef4
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 95 deletions.
Binary file modified bun.lockb
Binary file not shown.
95 changes: 76 additions & 19 deletions packages/wobe-graphql-apollo/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import getPort from 'get-port'
import { WobeGraphqlApolloPlugin } from '.'

describe('Wobe GraphQL Apollo plugin', () => {
it('should query graphql request', async () => {
it("should use the graphql middleware if it's provided", async () => {
const port = await getPort()

const wobe = new Wobe()
Expand All @@ -13,16 +13,28 @@ describe('Wobe GraphQL Apollo plugin', () => {
await WobeGraphqlApolloPlugin({
options: {
typeDefs: `#graphql
type Query {
hello: String
}
`,
type Query {
hello: String
}
`,
resolvers: {
Query: {
hello: () => 'Hello from Apollo!',
},
},
},
context: async () => {
return { tata: 'test' }
},
graphqlMiddleware: async (resolve, res) => {
res.setCookie('before', 'before')

const response = await resolve()

res.setCookie('after', 'after')

return response
},
}),
)

Expand All @@ -35,14 +47,17 @@ describe('Wobe GraphQL Apollo plugin', () => {
},
body: JSON.stringify({
query: `
query {
hello
}
`,
query {
hello
}
`,
}),
})

expect(res.status).toBe(200)
expect(res.headers.get('set-cookie')).toBe(
'before=before;, after=after;',
)
expect(await res.json()).toEqual({
data: { hello: 'Hello from Apollo!' },
})
Expand All @@ -56,10 +71,58 @@ describe('Wobe GraphQL Apollo plugin', () => {
const wobe = new Wobe()

wobe.usePlugin(
WobeGraphqlApolloPlugin({
context: {
tata: 'test',
await WobeGraphqlApolloPlugin({
options: {
typeDefs: `#graphql
type Query {
hello: String
}
`,
resolvers: {
Query: {
hello: () => 'Hello from Apollo!',
},
},
},
context: async (request) => {
expect(request.method).toBe('POST')

return { tata: 'test' }
},
}),
)

wobe.listen(port)

const res = await fetch(`http://127.0.0.1:${port}/graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `
query {
hello
}
`,
}),
})

expect(res.status).toBe(200)
expect(await res.json()).toEqual({
data: { hello: 'Hello from Apollo!' },
})

wobe.stop()
})

it('should query graphql request', async () => {
const port = await getPort()

const wobe = new Wobe()

wobe.usePlugin(
await WobeGraphqlApolloPlugin({
options: {
typeDefs: `#graphql
type Query {
Expand All @@ -68,13 +131,7 @@ describe('Wobe GraphQL Apollo plugin', () => {
`,
resolvers: {
Query: {
hello: (_, __, context) => {
expect(context.request).toBeDefined()
expect(context.request.method).toBe('POST')
expect(context.tata).toBe('test')

return 'Hello from Apollo!'
},
hello: () => 'Hello from Apollo!',
},
},
},
Expand Down
149 changes: 86 additions & 63 deletions packages/wobe-graphql-apollo/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { ApolloServer, type ApolloServerOptions } from '@apollo/server'
import {
ApolloServer,
type ApolloServerOptions,
type BaseContext,
} from '@apollo/server'
import {
ApolloServerPluginLandingPageLocalDefault,
ApolloServerPluginLandingPageProductionDefault,
} from '@apollo/server/plugin/landingPage/default'
import type { Wobe, WobePlugin } from 'wobe'
import type { MaybePromise, Wobe, WobePlugin, WobeResponse } from 'wobe'

const getQueryString = (url: string) => url.slice(url.indexOf('?', 11) + 1)

export interface GraphQLApolloPluginOptions {
graphqlMiddleware?: (
resolve: () => Promise<Response>,
res: WobeResponse,
) => Promise<Response>
}

export const WobeGraphqlApolloPlugin = async ({
options,
graphqlEndpoint = '/graphql',
graphqlMiddleware,
context,
}: {
options: ApolloServerOptions<any>
graphqlEndpoint?: string
context?: Record<string, any>
}): Promise<WobePlugin> => {
context?: (request: Request) => MaybePromise<BaseContext>
} & GraphQLApolloPluginOptions): Promise<WobePlugin> => {
const server = new ApolloServer({
...options,
plugins: [
Expand All @@ -33,66 +45,77 @@ export const WobeGraphqlApolloPlugin = async ({
await server.start()

return (wobe: Wobe) => {
wobe.get(graphqlEndpoint, async ({ request }) =>
server
.executeHTTPGraphQLRequest({
httpGraphQLRequest: {
method: request.method,
body: await request.json(),
// @ts-expect-error
headers: request.headers,
search: getQueryString(request.url),
},
context: () => Promise.resolve({ ...context, request }),
})
.then((res) => {
if (res.body.kind === 'complete') {
return new Response(res.body.string, {
status: res.status ?? 200,
// @ts-expect-error
headers: res.headers,
})
}

return new Response('')
})
.catch((error) => {
return new Response(error.message, {
status: error.statusCode,
})
}),
)

wobe.post(graphqlEndpoint, async ({ request }) =>
server
.executeHTTPGraphQLRequest({
httpGraphQLRequest: {
method: request.method.toUpperCase(),
body: await request.json(),
// @ts-expect-error
headers: request.headers,
search: getQueryString(request.url),
},
context: () => Promise.resolve({ ...context, request }),
})
.then((res) => {
if (res.body.kind === 'complete') {
return new Response(res.body.string, {
status: res.status ?? 200,
// @ts-expect-error
headers: res.headers,
})
}

return new Response('')
const fetchEndpoint = async (request: Request) => {
const res = await server.executeHTTPGraphQLRequest({
httpGraphQLRequest: {
method: request.method,
body: await request.json(),
// @ts-expect-error
headers: request.headers,
search: getQueryString(request.url),
},
context: context ? () => context(request) as any : () => ({}),
})

if (res.body.kind === 'complete') {
const response = new Response(res.body.string, {
status: res.status ?? 200,
// @ts-expect-error
headers: res.headers,
})
.catch((error) => {
if (error instanceof Error) throw error

return new Response(error.message, {
status: error.statusCode,
})
}),
)
return response
}

return new Response()
}

wobe.get(graphqlEndpoint, async ({ request, res: wobeResponse }) => {
if (!graphqlMiddleware) return fetchEndpoint(request)

const responseAfterMiddleware = await graphqlMiddleware(
async () => {
const response = await fetchEndpoint(request)

return response
},
wobeResponse,
)

for (const [key, value] of wobeResponse.headers.entries()) {
if (key === 'set-cookie') {
responseAfterMiddleware.headers.append('set-cookie', value)
continue
}

responseAfterMiddleware.headers.set(key, value)
}

return responseAfterMiddleware
})

wobe.post(graphqlEndpoint, async ({ request, res: wobeResponse }) => {
if (!graphqlMiddleware) return fetchEndpoint(request)

const responseAfterMiddleware = await graphqlMiddleware(
async () => {
const response = await fetchEndpoint(request)

return response
},
wobeResponse,
)

for (const [key, value] of wobeResponse.headers.entries()) {
if (key === 'set-cookie') {
responseAfterMiddleware.headers.append('set-cookie', value)
continue
}

responseAfterMiddleware.headers.set(key, value)
}

return responseAfterMiddleware
})
}
}
66 changes: 62 additions & 4 deletions packages/wobe-graphql-yoga/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,64 @@ import getPort from 'get-port'
import { WobeGraphqlYogaPlugin } from '.'

describe('Wobe GraphQL Yoga plugin', () => {
it("should use the graphql middleware if it's provided", async () => {
const port = await getPort()
const wobe = new Wobe()

wobe.usePlugin(
WobeGraphqlYogaPlugin({
graphqlMiddleware: async (resolve, res) => {
res.setCookie('before', 'before')

const response = await resolve()

res.setCookie('after', 'after')

return response
},
typeDefs: `
type Query {
hello: String
}
`,
resolvers: {
Query: {
hello: (_, __, context) => {
expect(context.request.headers).toBeDefined()
return 'Hello from Yoga!'
},
},
},
}),
)

wobe.listen(port)

const res = await fetch(`http://127.0.0.1:${port}/graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `
query {
hello
}
`,
}),
})

expect(res.status).toBe(200)
expect(res.headers.get('set-cookie')).toBe(
'before=before;, after=after;',
)
expect(await res.json()).toEqual({
data: { hello: 'Hello from Yoga!' },
})

wobe.stop()
})

it('should work with typedef and resolvers', async () => {
const port = await getPort()
const wobe = new Wobe()
Expand Down Expand Up @@ -119,10 +177,10 @@ describe('Wobe GraphQL Yoga plugin', () => {
},
},
}),
context: (req) => {
expect(req.request.method).toBe('POST')
expect(req.request.headers).toBeDefined()
expect(req.params).toBeDefined()
context: ({ request, params }) => {
expect(request.method).toBe('POST')
expect(request.headers).toBeDefined()
expect(params).toBeDefined()

return { tata: 'test' }
},
Expand Down
Loading

0 comments on commit 4a04ef4

Please sign in to comment.