Skip to content

Commit

Permalink
added middleware support
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander.sokolov committed Jun 11, 2020
1 parent 4b02516 commit 449d322
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 11 deletions.
30 changes: 19 additions & 11 deletions src/index.ts
@@ -1,14 +1,14 @@
import fetch from 'cross-fetch'
import { ClientError, GraphQLError, Variables } from './types'
import { Request, RequestInit, Response } from './types.dom'
import { ClientError, GraphQLClientOptions, GraphQLError, Variables } from './types'
import { Request, Response } from './types.dom'

export { ClientError } from './types'

export class GraphQLClient {
private url: string
private options: RequestInit
private options: GraphQLClientOptions

constructor(url: string, options?: RequestInit) {
constructor(url: string, options?: GraphQLClientOptions) {
this.url = url
this.options = options || {}
}
Expand All @@ -23,19 +23,23 @@ export class GraphQLClient {
status: number
errors?: GraphQLError[]
}> {
const { headers, ...others } = this.options
const { headers, requestMiddleware, responseMiddleware, ...others } = this.options

const body = JSON.stringify({
query,
variables: variables ? variables : undefined,
})

const response = await fetch(this.url, {
const request = {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...headers },
body,
...others,
})
}

const response = await fetch(this.url, requestMiddleware ? requestMiddleware(request) : request)
if (responseMiddleware) {
responseMiddleware(response);
}

const result = await getResult(response)

Expand All @@ -52,20 +56,24 @@ export class GraphQLClient {
}

async request<T = any>(query: string, variables?: Variables): Promise<T> {
const { headers, ...others } = this.options
const { headers, requestMiddleware, responseMiddleware, ...others } = this.options

const body = JSON.stringify({
query,
variables: variables ? variables : undefined,
})

const response = await fetch(this.url, {
const request = {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...headers },
body,
...others,
})
};

const response = await fetch(this.url, requestMiddleware ? requestMiddleware(request) : request)
if (responseMiddleware) {
responseMiddleware(response);
}
const result = await getResult(response)

if (response.ok && !result.errors && result.data) {
Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
@@ -1,5 +1,12 @@
import { RequestInit, Response } from "./types.dom"

export type Variables = { [key: string]: any }

export interface GraphQLClientOptions extends RequestInit {
requestMiddleware?: (request: RequestInit) => RequestInit
responseMiddleware?: (response: Response) => void
}

export interface GraphQLError {
message: string
locations: { line: number; column: number }[]
Expand Down
36 changes: 36 additions & 0 deletions tests/index.test.ts
Expand Up @@ -117,6 +117,42 @@ test('basic error with raw request', async () => {
)
})

describe('middleware', () => {
let client: GraphQLClient
let requestMiddleware: jest.Mock
let responseMiddleware: jest.Mock

beforeEach(() => {
ctx.mock({
body: {
data: {
result: 123,
},
},
}).body

requestMiddleware = jest.fn(req => req)
responseMiddleware = jest.fn()
client = new GraphQLClient(ctx.url, { requestMiddleware, responseMiddleware })
})

it('request', async () => {
const requestPromise = client.request<{ result: number }>(`x`)
expect(requestMiddleware).toBeCalled()
const res = await requestPromise
expect(responseMiddleware).toBeCalled()
expect(res.result).toBe(123)
})

it('rawRequest', async () => {
const requestPromise = client.rawRequest<{ result: number }>(`x`)
expect(requestMiddleware).toBeCalled()
const res = await requestPromise
expect(responseMiddleware).toBeCalled()
expect(res.data?.result).toBe(123)
})
})

// todo needs to be tested in browser environment
// the options under test here aren't used by node-fetch
test.skip('extra fetch options', async () => {
Expand Down

0 comments on commit 449d322

Please sign in to comment.