import * as express from 'express' ; import * as bodyParser from 'body-parser' ; import axios , { AxiosInstance , AxiosRequestConfig } from 'axios' ; import { parse , DocumentNode , getOperationAST } from 'graphql' ; import Route from './Route' ; import traverseAndBuildOptimizedQuery from './traverseAndBuildOptimizedQuery' ; import { IGlobalConfiguration , IMountableItem , IConstructorRouteOptions } from './types' ; import { LogLevels } from './Logger' ; const version = require ( '../package.json' ) . version ; const DEFAULT_CONFIGURATION = { cacheEngine : undefined , logger : undefined , auth : undefined , proxy : undefined , defaultLogLevel : LogLevels . ERROR , defaultTimeoutInMs : 10000 , defaultCacheTimeInMs : 0 , autoDiscoverEndpoints : false , optimizeQueryRequest : false , headers : { 'x-graphql-rest-router-version' : version } , } ; export default class Router { private schema ? : DocumentNode ; private options : IGlobalConfiguration ; public routes : Route [ ] = [ ] ; public modules : IMountableItem [ ] = [ ] ; public axios : AxiosInstance ; private passThroughHeaders : string [ ] = [ ] ; constructor ( public endpoint , schema ? , assignedConfiguration ? ) { const { auth , proxy , defaultTimeoutInMs : timeout , passThroughHeaders , ... options } = { ... DEFAULT_CONFIGURATION , ... assignedConfiguration , headers : { ... ( assignedConfiguration || { } ) . headers , ... DEFAULT_CONFIGURATION . headers , } , } ; const axiosConfig = { baseURL : endpoint , method : 'post' , headers : options . headers , timeout , auth , proxy , responseType : 'json' , } ; this . axios = axios . create ( axiosConfig ) ; if ( schema ) { this . schema = parse ( schema ) ; } if ( passThroughHeaders ) { this . passThroughHeaders = passThroughHeaders ; } this . options = options ; } private queryForOperation ( operationName ) { const { schema , options } = this ; const { optimizeQueryRequest } = options ; if ( ! schema ) { console . warn ( 'optimizeQueryRequest has no effect when not using schema' ) ; return schema ; } if ( optimizeQueryRequest ) { try { return traverseAndBuildOptimizedQuery ( schema , operationName ) ; } catch ( e ) { console . error ( 'Failed to build optimized schema' , e ) ; } } return schema ; } mount ( operationName , options ? ) ; mount ( inlineOperation , options ? ) ; mount ( mountableItem , options ? ) ; mount ( operationOrMountableItem , options ? ) { if ( typeof operationOrMountableItem === 'string' ) { const { schema : defaultSchema , axios , options : { logger , defaultLogLevel , cacheEngine , defaultCacheTimeInMs , cacheKeyIncludedHeaders } , } = this ; const isOperationName = defaultSchema && Boolean ( getOperationAST ( defaultSchema , operationOrMountableItem ) ) ; const operationName = isOperationName ? operationOrMountableItem : undefined ; const schema = isOperationName ? this . queryForOperation ( operationOrMountableItem ) : parse ( operationOrMountableItem ) ; const passThroughHeaders = Boolean ( options ) ? [ ... this . passThroughHeaders , ... options . passThroughHeaders ] : [ ... this . passThroughHeaders ] ; const routeOptions = { ... options , operationName , axios , schema , cacheEngine , cacheTimeInMs : defaultCacheTimeInMs , cacheKeyIncludedHeaders , logger , logLevel : defaultLogLevel , passThroughHeaders , } ; const graphQLRoute = new Route ( routeOptions ) ; this . routes . push ( graphQLRoute ) ; return graphQLRoute ; } const mountedItem = operationOrMountableItem . withOptions ( options ) ; if ( mountedItem . onMount ) { mountedItem . onMount ( this ) ; } this . modules . push ( mountedItem ) ; return mountedItem ; } listen ( port , callback ? ) { const router = express ( ) ; router . use ( this . asExpressRouter ( ) ) ; router . listen ( port , callback ) ; } asExpressRouter ( ) { const router = express . Router ( ) ; router . use ( bodyParser . json ( ) ) ; [ ... this . modules , ... this . routes ] . forEach ( ( route ) => { const { path , httpMethod } = route ; const routeFn = route . asExpressRoute ( ) ; router [ httpMethod ] ( path , routeFn ) ; } ) ; return router ; } asKoaRouter ( ) { throw new Error ( 'Not Implemented' ) ; } }