From 449d32230cc71f0a6d7fcb972ff044f2ced25e67 Mon Sep 17 00:00:00 2001 From: "alexander.sokolov" Date: Fri, 12 Jun 2020 02:48:23 +0300 Subject: [PATCH] added middleware support --- src/index.ts | 30 +++++++++++++++++++----------- src/types.ts | 7 +++++++ tests/index.test.ts | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9689043c..fd3f451f 100644 --- a/src/index.ts +++ b/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 || {} } @@ -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) @@ -52,20 +56,24 @@ export class GraphQLClient { } async request(query: string, variables?: Variables): Promise { - 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) { diff --git a/src/types.ts b/src/types.ts index 5a51e188..76e99812 100644 --- a/src/types.ts +++ b/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 }[] diff --git a/tests/index.test.ts b/tests/index.test.ts index 4ebcd2e5..f439f372 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -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 () => {