import { json } from 'co-body' ; import { DocumentNode , GraphQLSchema , parse as gqlParse , validate } from 'graphql' ; import { parse } from 'url' ; import { ExecutableSchema } from './../typings' ; import { BODY_HASH } from '../../../../../constants' ; import { GraphQLServiceContext , Query } from '../typings' ; import { LRUCache } from './../../../../../caches/LRUCache' ; const documentStorage = new LRUCache < string , DocumentNode > ( { max : 500 , } ) ; const queryFromUrl = ( url ) => { const parsedUrl = parse ( url , true ) ; const { query : querystringObj } = parsedUrl ; if ( querystringObj && querystringObj [ BODY_HASH ] ) { return null ; } if ( querystringObj && typeof querystringObj . variables === 'string' ) { querystringObj . variables = JSON . parse ( querystringObj . variables ) ; } return querystringObj ; } ; const parseAndValidateQueryToSchema = ( query , schema ) => { const document = gqlParse ( query ) ; const validation = validate ( schema , document ) ; if ( Array . isArray ( validation ) && validation . length > 0 ) { throw validation ; } return document ; } ; export const extractQuery = ( executableSchema ) => async function parseAndValidateQuery ( ctx , next ) { const { request , req } = ctx ; let query ; if ( request . is ( 'multipart/form-data' ) ) { query = ( request as any ) . body ; } else if ( request . method . toUpperCase ( ) === 'POST' ) { query = await json ( req , { limit : '3mb' } ) ; } else { query = queryFromUrl ( request . url ) || ( await json ( req , { limit : '3mb' } ) ) ; } ctx . graphql . query = query ; query . document = ( await documentStorage . getOrSet ( query . query , async ( ) => ( { value : parseAndValidateQueryToSchema ( query . query , executableSchema . schema ) , } ) ) ) as DocumentNode ; await next ( ) ; } ;