Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/graphql / src / app.ts
Size: Mime:
/* eslint-disable import/first */
/* eslint-disable import/no-namespace */
// @hack @fixme
import './typings'
// ===
import './bootstrapper/setup'
import express from 'express'
import { makeExecutableSchema } from 'graphql-tools'
import compression from 'compression'
import cookieParser from 'cookie-parser'
import { formatError } from 'apollo-errors'
import { ApolloServer } from 'apollo-server-express'
import resolvers from './resolvers'
import proxyMiddleware from './proxy'
import * as endpoints from './endpoints'
import { toCorrelationId } from './bootstrapper/api/correlationId'
import { cookieMiddleware } from './deps/cookieMiddleware'
import { toHostWithProtocol } from './deps/security'
import { KeyValueCache } from './deps/keyValueCache'
import typeDefs from './schema.graphql'

const pino = require('express-pino-logger')()

const schema = makeExecutableSchema({ typeDefs, resolvers })

function createServer() {
  const debugCache = new KeyValueCache()
  return new ApolloServer({
    typeDefs,
    resolvers,
    playground: !!process.env.SHOULD_USE_PLAYGROUND,

    /**
     * @todo add `inspect` for better log?
     */
    context(apollo) {
      const { req, res } = apollo

      const correlationId = toCorrelationId(req)
      req.correlationId = correlationId
      const context = { 
        req, 
        res,
        log: req.log,
        correlationId,
      }

      Object.assign(context, endpoints)

      /**
       * @todo split this out
       */
      // Object
      //   .keys(endpoints)
      //   // example [catalog, cart, checkout]
      //   .forEach(key => {
      //     const bloatedEndpoint = endpoints[key]
      //     const endpoint = {}
      //     context[key] = endpoint
      //     // go through the REQUESTS for each ENDPOINT
      //     // (catalog.getProductList, etc)
      //     Object
      //       .keys(bloatedEndpoint)
      //       .filter(requestKey => !!bloatedEndpoint[requestKey].toApollo)
      //       // example: [getProductDetail, getProductList]
      //       .forEach(requestKey => {
      //         const request = bloatedEndpoint[requestKey]
      //         // could also scope here
      //         endpoint[requestKey] = request
      //       })
      //   })
        
      return context
    },

    /**
     * @see https://github.com/apollographql/apollo-server/blob/c4d3a93e7bc8a9ffb1692c50a4f766422f30e665/packages/apollo-server-core/src/runHttpQuery.ts#L343
     */
    dataSources() {
      const dataSources = {}

      // endpoints...
      Object.keys(endpoints).forEach(key => {
        const endpointGroup = endpoints[key]

        // requests...
        Object.keys(endpointGroup).forEach(endpointName => {
          if (dataSources[endpointName]) {
            return
          }

          const endpoint = endpointGroup[endpointName]
          if (endpoint.toApollo) {
            // endpoint.toApollo()
            dataSources[endpointName] = endpoint

            /**
             * @see https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-core/src/runHttpQuery.ts#L343
             * issue here is Object.values
             */
            // Object.defineProperty(dataSources, endpointName, {
            //   // enumerable: true,
            //   // value: endpoint,
            //   get() {
            //     return endpoint
            //   },
            // })
          }
        })
      })

      // require('fliplog').quick(dataSources)

      return dataSources
    },
    tracing: true,
    introspection: true,
    cache: debugCache,
    debug: true,
    cacheControl: {
      defaultMaxAge: 60,
      stripFormattedExtensions: false,
      // calculateCacheControlHeaders: true,
    },
    formatError(error) {
      console.error(error)
      // require('fliplog').quick(error)

      return error
    },
    formatResponse(response) {
      if (process.env.NODE_ENV === 'production') {
        pino.logger.info('formatResponse: ', response)
      } else {
        // console.log('formatResponse: ', response)
      }

      // console.log(
      //   'cacheControl: ',
      //   JSON.stringify(response.extensions.cacheControl, undefined, 2)
      // )
      // debugCache.set(response.url)

      return response
    },
    engine: {
      apiKey:
        process.env.APOLLO_ENGINE_KEY ||
        'service:skava-engine:_oygzZUWfir8gDOh7kpgAQ',
      /**
       * @see https://github.com/apollographql/apollo-engine-js/issues/191
       */
      // origins: [
      //   {
      //     supportsBatch: true,
      //     requestTimeout: '60s',
      //   },
      // ],
      // Resize the default in-memory cache.
      // stores: [
      //   {
      //     name: 'inMemEmbeddedCache',
      //     inMemory: debugCache,
      //     // inMemory: {
      //     //   // 100 MB; defaults to 50MB.
      //     //   cacheSize: 104857600
      //     // },
      //   },
      // ],
      // queryCache: {
      //   publicFullQueryStore: 'inMemEmbeddedCache',
      // },
    },
  })
}

function createApp() {
  // @todo re-enable continue when starting mocks
  // if (process.env.MOCK_GRAPHQL) {
  //   addMockFunctionsToSchema({
  //     schema,
  //   })
  // }
  const server = createServer()
  // Initialize the app and proxy
  const app = express()
  app.use(compression())

  app.use(cookieParser())

  /**
   * @see https://www.npmjs.com/package/cors
   * @see https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i
   * @see https://www.npmjs.com/package/cors#enabling-cors-pre-flight
   */
  // app.options('/graphql', securityOriginMiddleware)
  // const apolloMiddlewareBuilt = createApolloMiddleware()

  app.use(cookieMiddleware)
  app.use(pino)

  const corsOptions = {
    origin: toHostWithProtocol(),
    credentials: true,
  }

  server.applyMiddleware({ app, cors: corsOptions })
  return app
}

export {
  schema,
  createApp,
  pino as log,
  pino,
  // corsOptions,
}
export default createApp