123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- // modified from vue-cli-plugin-apollo/graphql-server
- // added a return value for the server() call
- const http = require('http')
- const { chalk } = require('@vue/cli-shared-utils')
- const express = require('express')
- const { ApolloServer, gql } = require('apollo-server-express')
- const { PubSub } = require('graphql-subscriptions')
- const merge = require('deepmerge')
- function defaultValue (provided, value) {
- return provided == null ? value : provided
- }
- function autoCall (fn, ...context) {
- if (typeof fn === 'function') {
- return fn(...context)
- }
- return fn
- }
- module.exports = (options, cb = null) => {
- // Default options
- options = merge({
- integratedEngine: false
- }, options)
- // Express app
- const app = express()
- // Customize those files
- let typeDefs = load(options.paths.typeDefs)
- const resolvers = load(options.paths.resolvers)
- const context = load(options.paths.context)
- const schemaDirectives = load(options.paths.directives)
- let pubsub
- try {
- pubsub = load(options.paths.pubsub)
- } catch (e) {
- if (process.env.NODE_ENV !== 'production' && !options.quiet) {
- console.log(chalk.yellow('Using default PubSub implementation for subscriptions.'))
- console.log(chalk.grey('You should provide a different implementation in production (for example with Redis) by exporting it in \'apollo-server/pubsub.js\'.'))
- }
- }
- let dataSources
- try {
- dataSources = load(options.paths.dataSources)
- } catch (e) {}
- // GraphQL API Server
- // Realtime subscriptions
- if (!pubsub) pubsub = new PubSub()
- // Customize server
- try {
- const serverModule = load(options.paths.server)
- serverModule(app)
- } catch (e) {
- // No file found
- }
- // Apollo server options
- typeDefs = processSchema(typeDefs)
- let apolloServerOptions = {
- typeDefs,
- resolvers,
- schemaDirectives,
- dataSources,
- tracing: true,
- cacheControl: true,
- engine: !options.integratedEngine,
- // Resolvers context from POST
- context: async ({ req, connection }) => {
- let contextData
- try {
- if (connection) {
- contextData = await autoCall(context, { connection })
- } else {
- contextData = await autoCall(context, { req })
- }
- } catch (e) {
- console.error(e)
- throw e
- }
- contextData = Object.assign({}, contextData, { pubsub })
- return contextData
- },
- // Resolvers context from WebSocket
- subscriptions: {
- path: options.subscriptionsPath,
- onConnect: async (connection, websocket) => {
- let contextData = {}
- try {
- contextData = await autoCall(context, {
- connection,
- websocket
- })
- contextData = Object.assign({}, contextData, { pubsub })
- } catch (e) {
- console.error(e)
- throw e
- }
- return contextData
- }
- }
- }
- // Automatic mocking
- if (options.enableMocks) {
- // Customize this file
- apolloServerOptions.mocks = load(options.paths.mocks)
- apolloServerOptions.mockEntireSchema = false
- if (!options.quiet) {
- if (process.env.NODE_ENV === 'production') {
- console.warn('Automatic mocking is enabled, consider disabling it with the \'enableMocks\' option.')
- } else {
- console.log('✔️ Automatic mocking is enabled')
- }
- }
- }
- // Apollo Engine
- if (options.enableEngine && options.integratedEngine) {
- if (options.engineKey) {
- apolloServerOptions.engine = {
- apiKey: options.engineKey,
- schemaTag: options.schemaTag,
- ...options.engineOptions || {}
- }
- console.log('✔️ Apollo Engine is enabled')
- } else if (!options.quiet) {
- console.log(chalk.yellow('Apollo Engine key not found.') + `To enable Engine, set the ${chalk.cyan('VUE_APP_APOLLO_ENGINE_KEY')} env variable.`)
- console.log('Create a key at https://engine.apollographql.com/')
- console.log('You may see `Error: Must provide document` errors (query persisting tries).')
- }
- } else {
- apolloServerOptions.engine = false
- }
- // Final options
- apolloServerOptions = merge(apolloServerOptions, defaultValue(options.serverOptions, {}))
- // Apollo Server
- const server = new ApolloServer(apolloServerOptions)
- // Express middleware
- server.applyMiddleware({
- app,
- path: options.graphqlPath,
- cors: options.cors
- // gui: {
- // endpoint: graphqlPath,
- // subscriptionEndpoint: graphqlSubscriptionsPath,
- // },
- })
- // Start server
- const httpServer = http.createServer(app)
- httpServer.setTimeout(options.timeout)
- server.installSubscriptionHandlers(httpServer)
- httpServer.listen({
- host: options.host || 'localhost',
- port: options.port
- }, () => {
- if (!options.quiet) {
- console.log(`✔️ GraphQL Server is running on ${chalk.cyan(`http://localhost:${options.port}${options.graphqlPath}`)}`)
- if (process.env.NODE_ENV !== 'production' && !process.env.VUE_CLI_API_MODE) {
- console.log(`✔️ Type ${chalk.cyan('rs')} to restart the server`)
- }
- }
- cb && cb()
- })
- // added in order to let vue cli to deal with the http upgrade request
- return {
- apolloServer: server,
- httpServer
- }
- }
- function load (file) {
- const module = require(file)
- if (module.default) {
- return module.default
- }
- return module
- }
- function processSchema (typeDefs) {
- if (Array.isArray(typeDefs)) {
- return typeDefs.map(processSchema)
- }
- if (typeof typeDefs === 'string') {
- // Convert schema to AST
- typeDefs = gql(typeDefs)
- }
- // Remove upload scalar (it's already included in Apollo Server)
- removeFromSchema(typeDefs, 'ScalarTypeDefinition', 'Upload')
- return typeDefs
- }
- function removeFromSchema (document, kind, name) {
- const definitions = document.definitions
- const index = definitions.findIndex(
- def => def.kind === kind && def.name.kind === 'Name' && def.name.value === name
- )
- if (index !== -1) {
- definitions.splice(index, 1)
- }
- }
|