Apollo
To run the Apollo GraphQL server using Unit:
-
Install Unit with the unit-dev/unit-devel package. Next, install Unit’s unit-http package. Run the following command as root:
# npm install -g --unsafe-perm unit-http
-
Create your app directory, install Apollo, and link unit-http. Run the commands starting with a hash (#) as root:
$ mkdir -p /path/to/app/ # Path to the application directory; use a real path in your configuration
$ cd /path/to/app/ # Path to the application directory; use a real path in your configuration
$ npm install @apollo/server graphql
# npm link unit-http
-
Create the middleware module; let’s store it as /path/to/app/apollo.js. First, initialize the directory:
$ cd /path/to/app/ # Path to the application directory; use a real path in your configuration
$ npm init
Next, add the following code:
import { ApolloServer } from '@apollo/server'; import { expressMiddleware } from '@apollo/server/express4'; import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'; import express from 'express'; import http from 'http'; import cors from 'cors'; import bodyParser from 'body-parser'; //import { typeDefs, resolvers } from './schema'; const typeDefs = `#graphql type Query { hello: String } `; // A map of functions which return data for the schema. const resolvers = { Query: { hello: () => 'world', }, }; // Required logic for integrating with Express const app = express(); // Our httpServer handles incoming requests to our Express app. // Below, we tell Apollo Server to "drain" this httpServer, // enabling our servers to shut down gracefully. const httpServer = http.createServer(app); // Same ApolloServer initialization as before, plus the drain plugin // for our httpServer. const server = new ApolloServer({ typeDefs, resolvers, plugins: [ApolloServerPluginDrainHttpServer({ httpServer })], }); // Ensure we wait for our server to start await server.start(); // Set up our Express middleware to handle CORS, body parsing, // and our expressMiddleware function. app.use( '/', cors(), bodyParser.json(), // expressMiddleware accepts the same arguments: // an Apollo Server instance and optional configuration options expressMiddleware(server, { context: async ({ req }) => ({ token: req.headers.token }), }), ); // Modified server startup; port number is overridden by Unit config await new Promise((resolve) => httpServer.listen({ port: 80 }, resolve));
Make sure your package.json resembles this (mind “type”: “module”):
{ "name": "unit-apollo", "version": "1.0.0", "description": "Running Apollo over Express on Unit", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Unit Team", "license": "ISC", "dependencies": { "@apollo/server": "^4.7.5", "apollo-server": "^3.12.0", "body-parser": "^1.20.2", "cors": "^2.8.5", "express": "^4.18.2", "graphql": "^16.7.1", "unit-http": "^1.30.0" } }
-
Change ownership:
Run the following command (as root) so Unit can access the application directory (If the application uses several directories, run the command for each one):
# chown -R unit:unit /path/to/app/ # User and group that Unit's router runs as by default
The unit:unit user-group pair is available only with official packages , Docker images, and some third-party repos. Otherwise, account names may differ; run theps aux | grep unitd
command to be sure.For further details, including permissions, see the security checklist.
-
Next, prepare the Apollo configuration for Unit:
{ "listeners": { "*:80": { "pass": "applications/apollo" } }, "applications": { "apollo": { "type": "external", "working_directory": "/path/to/app/", "_comment_working_directory": "Needed to use the installed NPM modules; use a real path in your configuration", "executable": "/usr/bin/env", "_comment_executable": "The external app type allows to run arbitrary executables, provided they establish communication with Unit", "arguments": [ "node", "--loader", "unit-http/loader.mjs", "--require", "unit-http/loader", "apollo.js" ], "_comment_arguments": "The env executable runs Node.js, supplying Unit's loader module and your app code as arguments" } } }
-
Upload the updated configuration.
Assuming the JSON above was added to
config.json
. Run the following command as root:# curl -X PUT --data-binary @config.json --unix-socket \ /path/to/control.unit.sock \ # Path to Unit's control socket in your installation http://localhost/config/ # Path to the config section in Unit's control API
After a successful update, your app should be available on the listener’s IP address and port: