diff --git a/README.md b/README.md index 12fc2eae9..c5b53236f 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ const query = `{ } } }` - + request('https://api.graph.cool/simple/v1/movies', query).then(data => console.log(data)) ``` @@ -44,7 +44,7 @@ request(endpoint, query, variables).then(data => console.log(data)) // ... or create a GraphQL client instance to send requests const client = new GraphQLClient(endpoint, { headers: {} }) -client.request(query, variables).then(data => console.log(data)) +client.request(query, variables).then(data => console.log(data)) ``` ## Examples @@ -69,7 +69,7 @@ const query = `{ } }` -client.request(query).then(data => console.log(data)) +client.request(query).then(data => console.log(data)) ``` ### Passing more options to fetch @@ -91,7 +91,7 @@ const query = `{ } }` -client.request(query).then(data => console.log(data)) +client.request(query).then(data => console.log(data)) ``` ### Using variables @@ -145,7 +145,7 @@ const query = `{ } } }` - + request('my-endpoint', query).then(data => console.log(data)) ``` @@ -175,6 +175,26 @@ const query = `{ client.request(query).then(data => console.log(data)) ``` +### Receiving a raw response + +The `request` method will return the `data` or `errors` key from the response. +If you need to access the `extensions` key you can use the `rawRequest` method: + +```js +import { rawRequest } from 'graphql-request' + +const query = `{ + Movie(title: "Inception") { + releaseDate + actors { + name + } + } +}` + +rawRequest('my-endpoint', query).then(({data, extensions}) => console.log(data, extensions)) +``` + ### More examples coming soon... * Fragments diff --git a/src/index.ts b/src/index.ts index 00f96e2e7..da4f56c1d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { ClientError, Headers, Options, Variables } from './types' +import { ClientError, GraphQLError, Headers, Options, Variables } from './types' export { ClientError } from './types' import 'cross-fetch/polyfill' @@ -11,6 +11,38 @@ export class GraphQLClient { this.options = options || {} } + async rawRequest( + query: string, + variables?: Variables, + ): Promise<{ data?: T, extensions?: any, errors?: GraphQLError[] }> { + const { headers, ...others } = this.options + + const body = JSON.stringify({ + query, + variables: variables ? variables : undefined, + }) + + const response = await fetch(this.url, { + method: 'POST', + headers: Object.assign({ 'Content-Type': 'application/json' }, headers), + body, + ...others, + }) + + const result = await getResult(response) + + if (response.ok && !result.errors && result.data) { + return result + } else { + const errorResult = + typeof result === 'string' ? { error: result } : result + throw new ClientError( + { ...errorResult, status: response.status }, + { query, variables }, + ) + } + } + async request( query: string, variables?: Variables, @@ -61,6 +93,16 @@ export class GraphQLClient { } } +export async function rawRequest( + url: string, + query: string, + variables?: Variables, +): Promise<{ data?: T, extensions?: any, errors?: GraphQLError[] }> { + const client = new GraphQLClient(url) + + return client.rawRequest(query, variables) +} + export async function request( url: string, query: string, diff --git a/src/types.ts b/src/types.ts index 8e6a98824..e982f6458 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,7 @@ export interface GraphQLError { export interface GraphQLResponse { data?: any errors?: GraphQLError[] + extensions?: any status: number [key: string]: any } diff --git a/tests/index.test.ts b/tests/index.test.ts index 8ba03a48c..a80629534 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,6 +1,6 @@ import test from 'ava' import * as fetchMock from 'fetch-mock' -import { ClientError, request, GraphQLClient } from '../src/index' +import { ClientError, rawRequest, request, GraphQLClient } from '../src/index' import { Options } from '../src/types' test('minimal query', async (t) => { @@ -15,6 +15,22 @@ test('minimal query', async (t) => { }) }) +test('minimal raw query', async (t) => { + const data = { + viewer: { + id: 'some-id', + }, + } + + const extensions = { + version: '1', + } + + await mock({body: {data, extensions}}, async () => { + t.deepEqual(await rawRequest('https://mock-api.com/graphql', `{ viewer { id } }`), {data, extensions}) + }) +}) + test('basic error', async (t) => { const errors = { message: "Syntax Error GraphQL request (1:1) Unexpected Name \"x\"\n\n1: x\n ^\n", @@ -32,6 +48,23 @@ test('basic error', async (t) => { }) }) +test('raw request error', async (t) => { + const errors = { + message: "Syntax Error GraphQL request (1:1) Unexpected Name \"x\"\n\n1: x\n ^\n", + locations: [ + { + line: 1, + column: 1 + } + ] + } + + await mock({body: {errors}}, async () => { + const err: ClientError = await t.throws(rawRequest('https://mock-api.com/graphql', `x`)) + t.deepEqual(err.response.errors, errors) + }) +}) + test('content-type with charset', async (t) => { const data = { viewer: {