enterprise-graphql
v1.0.0
Published
--- name: enterprise-graphql team: https://navinc.atlassian.net/wiki/people/team/ea9346dd-5ceb-4d64-a6ae-8daaece6ec0d docs: https://git.nav.com/frontend/enterprise-graphql/blob/main/README.md repo: https://git.nav.com/frontend/enterprise-graphql bugsnag:
Downloads
5
Readme
name: enterprise-graphql team: https://navinc.atlassian.net/wiki/people/team/ea9346dd-5ceb-4d64-a6ae-8daaece6ec0d docs: https://git.nav.com/frontend/enterprise-graphql/blob/main/README.md repo: https://git.nav.com/frontend/enterprise-graphql bugsnag: https://app.bugsnag.com/nav-inc/enterprise-graphql datatype: green database: database_setup_enabled: True extensions: '["uuid-ossp"]' pre_deploy:
- name: db-migrate args: ['pnpm', 'run', '--filter=enterprise-graphql', 'db:migrate'] resources: maxcpu: 1000m maxmemory: 512Mi procs: http: port: 4000 replicas: 3 type: http healthcheck_url: /health args: ['pnpm', 'run', '--filter=enterprise-graphql', 'start:enterprise-web'] resources: maxcpu: 500m maxmemory: 512Mi mincpu: 50m minmemory: 64Mi enterprise-admin: port: 4001 replicas: 3 type: http healthcheck_url: /health args: ['pnpm', 'run', '--filter=enterprise-graphql', 'start:enterprise-admin'] resources: maxcpu: 300m maxmemory: 256Mi mincpu: 50m minmemory: 64Mi enterprise-partners: port: 4002 replicas: 6 type: http healthcheck_url: /health args: ['pnpm', 'run', '--filter=enterprise-graphql', 'start:enterprise-partners'] resources: maxcpu: 400m maxmemory: 512Mi mincpu: 50m minmemory: 64Mi enterprise-customers: port: 4003 replicas: 6 type: http healthcheck_url: /health args: ['pnpm', 'run', '--filter=enterprise-graphql', 'start:enterprise-customers'] resources: maxcpu: 1500m maxmemory: 512Mi mincpu: 50m minmemory: 64Mi cronjobs: delete-sessions: schedule: '0 0 1 * *' args: ['pnpm', 'run', '--filter=enterprise-graphql', 'delete:sessions'] resources: maxcpu: 1000m maxmemory: 512Mi
Enterprise GraphQL
Nav's common, modular GraphQL repository for all GraphQL services.
team: All Front End DevelopersOverview
This project contains a single GraphQL gateway designed to serve all GraphQL code at Nav. It has a blend of modules that contain resolvers/schema or schema stitching. These modules can be served in different blends via an "instance" of Enterprise GraphQL.
The project is written using Typescript, Apollo Server, Express, and the Sequelize ORM. It depends on a PostgreSQL database.
Sub Documents
Instances in Production
http (enterprise-web module)
This serves Nav's internal web applications. ie: enterprise-web
publicly accessible
- https://app.sandbox.nav.com/enterprise-graphql/graphql
- https://app.nav.com/enterprise-graphql/graphql
only accessible internally or via VPN
- https://app.int1.nav.engineering/enterprise-graphql/graphql
- https://app.staging.nav.engineering/enterprise-graphql/graphql
enterprise-admin
This serves admins such as reachard admin and modularized onboarding flow admin.
only accessible internally or via VPN
- https://enterprise-graphql-admin.int1.nav.engineering/graphql
- https://enterprise-graphql-admin.staging.nav.engineering/graphql
- https://enterprise-graphql-admin.sandbox.nav.engineering/graphql
- https://enterprise-graphql-admin.prod.nav.engineering/graphql
enterprise-partners
This serves all API partners that create accounts and pull CTAs to display in their dashboards. ie: Clover, Credit Suite and Creditsafe
accessible by our partners
- https://api.nav.com/partners/graphql
- https://api.sandbox.nav.com/partners/graphql
only accessible internally or via VPN
- https://api.int1.nav.engineering/partners/graphql
- https://enterprise-graphql-enterprise-partners.int1.nav.engineering/graphql
- https://enterprise-graphql-enterprise-partners.staging.nav.engineering/graphql
- https://enterprise-graphql-enterprise-partners.sandbox.nav.engineering/graphql
- https://enterprise-graphql-enterprise-partners.prod.nav.engineering/graphql
enterprise-customers
This serves API partners for reports, score, and createDBFile / fileCreationStatus
accessible by our partners
- https://api.nav.com/enterprise/customers/graphql
- https://api.sandbox.nav.com/enterprise/customers/graphql
only accessible internally or via VPN
- https://api.int1.nav.engineering/enterprise/customers/graphql
- https://enterprise-graphql-enterprise-customers.int1.nav.engineering/graphql
- https://enterprise-graphql-enterprise-customers.staging.nav.engineering/graphql
- https://enterprise-graphql-enterprise-customers.sandbox.nav.engineering/graphql
- https://enterprise-graphql-enterprise-customers.prod.nav.engineering/graphql
Getting Started
Setting up a local database
You can run a local copy of PostgreSQL if you want to work with the DB tables locally. Install PostgreSQL using your preferred method. An easy way to get started is to use Postgres.app because it will spin up a local database for you with a few clicks. Once you get your DB up and running, you should point your .env file to your local DB. If you used Postgres.app, your DB and user will both be your computer's username, and your password will be empty. Ensure that there are no other PostgreSQL processes running on the same port at the time. If you change the DB_PORT variable, be sure that your locally running Postgres has received the change in its configuration as well.
If you're not comfortable with SQL on the command line, Postico is a great GUI for viewing a PostgreSQL database.
Setting up a local Redis cache
You will need to run a local version of Redis to support APQ caching. This is very easy to do using Homebrew. You can do the following:
brew update
brew install redis
# Registers the service to run each time you boot your machine
brew services start redisNav private pkgs
For local development, makes sure to have the NAV_GITLAB_API_TOKEN configured as described in the nav-private-pkgs project.
Repo set up
Below are the steps to get the repo set up. Be sure to configure the NAV_GITLAB_API_TOKEN and install your local DB and Redis cache first.
cp .env.example .env
pnpm i
pnpm run dev:enterprise-webOnce the app is running, you can view the GraphQL Playground at http://localhost:4000/graphql.
Contributing to this Repository
GraphQL Modules, Resolvers, and Schema
To keep an organized project, our GraphQL resources are broken out into modules. All modules should be put in a consistent folder/file structure. If you need to add a new set of resolvers+schema, create a folder under ./src/graphql/modules with the name of the feature/service. Inside that folder, create index.ts where you define your module, and resolvers/resolvers.ts and /type-defs/type-defs.ts. Look at other examples in the code to see how these are written.
If you need to write an Apollo DataSource, name the file in this pattern: ServiceNameDataSource.ts. You can extend SequelizeDataSource, RESTDataSource, or create your own extension of DataSource. Data sources can be placed in the module, or in ./src/graphql/data-sources if it's a common module.
GraphQL Stitching
If you're stitching in a new service, create a folder under ./src/graphql/modules with the name of the feature/service. Inside that folder, create index.ts. See ./src/graphql/modules/reachard-customers/index.ts for an example of remote schema stitching.
Multiple Instances of Enterprise GraphQL
Enterprise GraphQL was designed to be modular. This means that a single codebase can create different instances of a GraphQL gateway with a unique mix of queries/mutations/schema. This allows us to spin up instances to support admin, web, partners, etc. but share common code and reduce the repo count. In order to do this, all modules must be in the same folder as mentioned above.
The modules for a given instance will be defined in an environment variable called GRAPHQL_MODULES. This var will be defined in the start script for the respective service instance, not the configurations repo. You should use the package.json config object to add shared env vars for new instances, and reference that in the start and dev scripts for that instance (i.e. start:enterprise-web and dev:enterprise-web).
The instances are defined in the README frontmatter as procs. You can see examples of that at the top of this file. Each proc will need a unique port and start script. By default, navctl will create internal routing to the service. If you want to make a publicly available URL, you must configure that in a different repository that handles K8s routing.
To start a specific instance, you will find dev/start scripts for each one in the package.json.
Working with the ORM
This project uses the Sequelize ORM to simplify managing our DB models and records. You can find the CLI documentation here if you need to reference it. You can run all Sequelize commands by adding them after npm run sequelize --. See the examples below.
You'll need to populate your DB using the migrations to run the project. You can do that using the following commands:
# Run DB migrations. Builds out the required tables from the migration scripts.
npm run sequelize -- db:migrateYou may need to create new migration data at some point, especially if you are adding a new Modularized Onboarding flow. The CLI can generate a new migration for you via:
# Generate a new DB migration
npm run sequelize -- migration:generate --name your-new-migration-nameThe new migration will be placed in ./db/migrations. You can look at other migrations for an example of how to code one.
If you need to wipe your entire DB and start over, you can run the following (CAUTION, you will lose ALL data and tables):
# Clear your DB tables
npm run sequelize -- db:migrate:undo:all
npm run sequelize -- db:migrate
npm run sequelize -- db:seed:allIf the above doesn't work for you, you can try the nuclear option. This will drop and recreate your entire database. This is dangerous. You've been warned.
# Drop and re-create DB
npm run sequelize -- db:drop
npm run sequelize -- db:createWorking with Rover CLI
Rover CLI will run as an automatic stage in the pipeline after changes to Enterprise Graphql are deployed to an environment. This job will check your changes against the production variation of the schema by generating a schema.graphql file and outputting the results of any breaking changes that may have been introduced.
To troubleshoot any issues, you can output and inspect a schema from your locally running instance of Enterprise Graphql with the following command.
npx -p @apollo/rover rover graph introspect http://localhost:4000/graphql | catTesting
# Run all tests
pnpm run test
# Run changed tests in watch mode
pnpm run test:watchUsing supertest alongside Mock Service Worker
In line with our ADR, we use Mock Service Worker (MSW) to mock HTTP requests in our tests. However, there are some requests we have using the supertest library where we actually want the request to happen. In order to prevent MSW from warning us that these requests haven't been mocked correctly we can add the x-supertest-request custom header to the request. This makes our console out from test runs a lot less noisy. Example:
import request from 'supertest';
...
await request(createServer())
.post('/test')
.set('x-supertest-request', 'true') // make sure msw doesn't warn about this
.set('Content-Type', 'application/json')
.send('{ "query": "{ here }" }')
.expect(200)
.then((response) => {
expect(response.body).toEqual({ result: 'non-mocked response' });
});
...Operating and Maintaining
Monitoring & Alerts
Links for the different monitoring and alerts dashboards can be found in Confluence.
Updating Dependencies
All dependencies are managed in the package.json file.
TODO: Common errors, and playbooks on how to resolve them. TODO: Are there uptime commitments or other SLAs for this code? What are they? TODO: Are there specific monitoring alerts set up for this code? What should be done if they go off?
Risk
Interfaces
| URL | Internal/External | Description | | ---------------------------------------------- | ----------------- | --------------------------------------------------------------------------------- | | https://app.nav.com/enterprise-graphql/graphql | External | The GraphQL gateway for accessing all GQL services that enterprise-graphql offers | | https://app.nav.com/enterprise-graphql/health | External | Health check endpoint |
Data Sensitivities
| Data Type | Integrity | Availability | Confidentiality | | --------------- | --------- | ------------ | --------------- | | Personal Credit | Moderate | High | High | | PII | Moderate | High | High | | Business Credit | Moderate | Moderate | Moderate | | Onboarding Data | Low | Moderate | Low |
Known Risks
| Summary | Interest | Controls | Likelihood | Severity | Rating | Recommendations | | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -------- | -------- | ----------------------------------------------------------------------------------- | | If the Apollo Server portion of the service was down, Enterprise Web would not be able to access Reachard. This would render Enterprise Web unusable. | This would pose a risk to the availability of our enterprise apps to our enterprise partners. | Multiple Kubernetes pods. There are E2E tests in place to verify that the applications this service supports are still functioning. | Low | High | Low Risk | No | | If the PostgreSQL DB was down, then all Modularized Onboarding flows would be rendered useless. | This would pose a risk to the availability of our enterprise apps to our enterprise partners. | DevOps has tools in place to check the health of the RDS instance. There are E2E tests in place to verify that the applications this service supports are still functioning. | Low | Moderate | Low Risk | No | | Downstream applications fail to authorize access to resources based on the JWT. | Confidentiality. | Downstream JWT access verification. | Low | High | Low Risk | Documentation should exist that instructs downstream apps to manage access control. |
Data Flow Diagram

// TODO: Add Typescript support for *.graphql files and convert all modules to that standard // TODO: Test out the following scalars to see if they still work: USDollars, Year, MonthDate. Do we need to implement those in ent-graphql side?
Apollo Studio
Each instance of our enterprise-graphql servers have a graph created for them on Apollo Studio which provides tools for registering schemas, checking schema updates for breaking changes, metric reporting, and notifications. More about the features can be learned on their documentation site.
Schema Registration and Metrics
With Apollo-Server, we use the automatic schema registration and metric reporting features. If the following environment variables are set Apollo-Server will connect to the given Apollo Studio graph and register the GraphQL schema for the provided variant automatically once the server starts. It will then also send metrics to Apollo Studio with data about requests types and error rates.
APOLLO_KEY=YOUR_KEY_TIED_TO_THE_GRAPH_YOU_ARE_CONNECTING_TO
APOLLO_GRAPH_VARIANT=staging
APOLLO_SCHEMA_REPORTING=trueThe APOLLO_KEY variable is defined in the package.json file and exported at run time when the server starts with the npm run start:enterprise-* script so it can be unique for each instance. The APOLLO_GRAPH_VARIANT and APOLLO_SCHEMA_REPORTING variables are defined in the configuration repo for each environment and are pulled in at deploy time.
We currenlty register schema and report metrics for our integration, staging, sandbox, and production environments.
Schema Checks
We also use the Schema checking feature which allows us to identify any breaking changes to the schema before deploying to production. This is done in our CI/CD pipeline where we check the new schema for each enterprise-graphql instance against what is currently running in production.
Notifications
Each enterprise-graphql instance also has notifications configured. Messages will be sent to our #graphql-changes slack channel for schema changes and performance alerts.
