This repository is a fork of DEFRA/forms-manager. It is maintained as a separate copy due to the service requirements of the Core Delivery Platform (CDP).
Please install the Node.js version in .nvmrc using Node Version Manager nvm via:
cd grants-ui-config-api
nvm use-
Install Docker
-
Start compose stack
docker compose upor
npm run docker:up- Optionally create a
.envfile with the following environment variables populated at root level:
PORT=3011
MONGO_URI=mongodb://mongodb:27017/
JWT_SECRET= <JWT secret for JWT signing>
GRANTS_CONFIG_BROKER_URL=http://localhost:3012
FORMS_API_SLUGS=my-grant,another-grant
If not provided, default values will be used so the application can be started.
The API will be available at http://localhost:3011 once started.
AWS Services: The Docker Compose setup includes LocalStack for local AWS service emulation (S3 and SNS). AWS credentials and config in the /localstack/aws.env is used for local development.
Audit Events: Event-based audit publishing to SNS is disabled by default. To enable, set:
FEATURE_FLAG_PUBLISH_AUDIT_EVENTS=trueSNS_TOPIC_ARN=<your-topic-arn>SNS_ENDPOINT=http://localstack:4566(for local development)
Config Broker: On startup the API seeds form definitions from the config broker service. See Config Broker Integration below.
Proxy Configuration: For proxy support, see https://www.npmjs.com/package/proxy-from-env which is used by https://github.com/TooTallNate/proxy-agents/tree/main/packages/proxy-agent.
All available Npm scripts can be seen in package.json To view them in your command line run:
npm runThe API runs on port 3011 by default. This can be configured via the PORT environment variable.
Form definitions support an optional metadata field for storing structured form metadata. Metadata validation is performed automatically when publishing forms to ensure data integrity.
For detailed information on metadata structure, validation rules, and examples, see docs/metadata-guide.md.
On startup the API seeds grant form definitions from an external config broker service (GRANTS_CONFIG_BROKER_URL). The seeder:
- Calls
GET /api/allGrantson the config broker to retrieve all available grants and their versions. - Filters grants to those listed in the
FORMS_API_SLUGSenvironment variable (comma-separated slugs). - For each grant version, calls
GET /api/version?grant=<slug>&version=<semver>to retrieve version detail including the S3 manifest. - Fetches the YAML form definition from S3 using the
pathfield (bucket name) andmanifestkeys from the broker response. - Creates or updates the form version in the database:
- New version: creates form metadata (or reuses existing) and inserts the version document.
- Existing version, status changed: updates the version status in the database.
- Existing version, same status: skips (no-op).
Grant form versions use semantic versioning (e.g. 1.0.0). Multiple versions of the same grant can be active simultaneously.
| Variable | Description | Default |
|---|---|---|
GRANTS_CONFIG_BROKER_URL |
Base URL of the config broker service | "" |
FORMS_API_SLUGS |
Comma-separated list of grant slugs to seed | "" |
The codebase uses JSDoc type annotations for TypeScript-style type safety without requiring TypeScript compilation. Custom type definitions are maintained in:
src/api/types.js- API-specific types including request types and document schemas- Form model types are imported from
@defra/forms-model
Key custom types include:
FormDefinitionWithMetadata- Form definition with required metadata fieldFormMetadataWithVersions- Form metadata including version history- Various request types for API endpoints
The application is containerised using Docker. To build the Docker image locally, e.g. for testing with grants-ui compose stack:
npm run docker:buildThis build is for local use only and is tagged with local.
The API follows the OpenAPI 3.1 specification. View the complete API documentation:
- openapi.yaml - Complete OpenAPI specification
The API provides endpoints for:
- Health - Service health checks
- Forms - Form metadata and lifecycle management (create, read, update, delete)
- Definitions - Draft and live form definition management
- Versions - Form version history and retrieval
- Pages - Page management within form definitions
- Components - Component management within pages
Most endpoints require JWT Bearer token authentication. See Calling API endpoints below for authentication setup.
Config-broker-seeded forms support an optional ?version=<semver> query parameter on the slug endpoints:
| Endpoint | Without version |
With version=1.0.0 |
|---|---|---|
GET /forms/slug/{slug} |
Returns form metadata | Returns form metadata (version param ignored) |
GET /forms/slug/{slug}/definition |
Returns latest active semver version; falls back to live definition for editor-workflow forms | Returns definition for the specified semver version |
Multiple semver versions can be active simultaneously. "Latest" is determined by semver comparison (not creation order).
If you're adding endpoints for new features, update the openapi.yaml file to include the new endpoints.
The project includes an HTTP client configuration file (config.http) that works with IntelliJ IDEA and VS Code REST Client extensions.
-
Generate JWT_SECRET using the npm script:
# Print JWT secret to console npm run generate:jwt_secretand paste into
.envfile. -
Generate an authentication token using the npm script:
# Print token to console npm run generate:token # Save token to http-client.private.env.json npm run generate:token:save
The
generate:token:savecommand creates/updateshttp-client.private.env.jsonwith your token, which is automatically used by the HTTP client. -
Set up per environment variables:
- The base configuration is in http-client.env.json
- Private/sensitive values (like tokens) are stored in
http-client.private.env.json(git-ignored)authToken- JWT token generated as abovex-api-key– obtain this per‑environment value from the CDP portal user profile page:https://portal.cdp-int.defra.cloud/user-profile
-
Start the API:
npm run docker:up
-
Execute requests:
- Open config.http in your IDE
- Select the environment (e.g., "local") from the dropdown
- Click "Run" on any request to execute it
The HTTP client files include examples for all API endpoints:
- config.http - Form management, pages, components, versioning, and slug endpoints with semver support
- broker.http - Config broker service endpoints (
/api/allGrants,/api/version)
The project includes unit and integration tests, which are run automatically on CI.
You can also run tests locally (unit and integration):
npm run testnpm run test:unitnpm run test:unit:watchnpm run test:integrationnpm run test:integration:watchtest/integration/api.integration.test.js- Main integration test suite
The integration test suite covers 37 test cases equivalent to the original Postman collection:
- Health Check - API health endpoint
- Forms CRUD - Create, read, update, delete forms
- Form Definitions - Draft and live form definitions
- Form Migration - V1 to V2 engine migration
- Pages - Create, update, delete, reorder pages
- Components - Create, update, delete form components
- Lists - Create, update, delete lists (including large lists with 100 elements)
- Sections - Add and remove sections
- Form Options - Configure form options like showReferenceNumber
- Go-Live Flow - Complete workflow to publish a form
Tests run sequentially and maintain state between tests using a testState object. This mirrors the Postman collection approach where collection variables stored IDs between requests.
Example flow:
- Create a form → Store
formId - Add pages to form → Store
pageId,pageId2,pageId3 - Reorder pages using stored IDs
- Clean up by deleting form using stored
formId
Integration tests are included in jest.config.cjs:
testMatch: Includestest/**/*.test.{cjs,js,mjs}testPathIgnorePatterns: Excludes the Postman collection directory
npm run test:integration -- -t "should create a new form"npm run test:integration -- --verbosenpm run test -- --testPathPattern=integration --coverage- Sequential Execution: Tests in the main suite run sequentially as they depend on state from previous tests
- Cleanup: Always clean up created resources (forms, pages, etc.)
- Assertions: Use specific assertions that match the Postman test equivalents
- Token Management: Tokens are generated once per test suite in
beforeAll - State Management: Use
testStateobject to pass data between sequential tests
- Increase timeout:
jest.setTimeout(60000)in test file - Check server initialization in
beforeAll
- Ensure tests run sequentially (not in parallel)
- Verify cleanup in
afterAlland cleanup tests
THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
The following attribution statement MUST be cited in your products and applications when using this information.
Contains public sector information licensed under the Open Government license v3
The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.