API
Ensure docker is running, then run the following when running for the first time:
yarn dev-init api
To start the app:
yarn dev api
These commands are just shorthands for the setup described below.
This project forms the basis of a unified API for products belonging to island.is.
It's built as a thin GraphQL layer on top of data and services provided by government organisations and island.is microservices, where each unit is wrapped in a domain.
- Dev: N/A
- Production: N/A
The code in this app package should be kept as small as possible. Most business logic should be in domain libraries. Shared utilities and middlewares should be in libraries as well.
Domain libraries represent and wrap an underlying data model or service. As a rule of thumb, each microservice and government organisation should have their own domain library.
They can contain the following exports:
- typeDefs: GraphQL schema describing the types, inputs, queries and mutations of the domain.
- resolvers: Object containing GraphQL resolvers for any fields, queries and mutations as needed by the domain.
- services: The domain can export arbitrary services for other domains. These should be strongly typed and not expose any internals of the domain.
The
typeDefs
and resolvers
for all domains are merged into a single GraphQL server.Generally, the resolvers should be really small. They should only manage the resolver arguments, including input and payload wrappers.
The actual resolver logic should be in service functions. These may call another domain's service, call external services and publish messages on exchanges.
Services are classes that contain most of the logic for a domain. They should be easy to test and use dependency injection (DI) to get access to other services and connectors.
Currently, there is no DI container. Everything is hooked up manually in tests and
/apps/api/src/graphql/context
.We use graphql-codegen to generate TypeScript types for all GraphQL schemas. We also generate type definitions for all resolvers, which provides strong typing for parent, input and context arguments as well as the return payload.
To gain these benefits, resolvers should be defined like this:
import { Resolvers } from '@island.is/api/schema'
export const resolvers: Resolvers = {
Person: {
application(person, input, context) {},
},
Query: {
allApplications(_, input, context) {},
},
}
For more information, read the following article. It also explains how to specify a typed context as well as custom model types:
In addition, client apps can use
graphql-codegen
to join together the API schema with client operations. This validates that operations match the schema, and generates type definitions for operation inputs and payloads.For code that can be reused, consider adding it to a shared library. If it's specific to the API, it should be under
/libs/api
, otherwise consider making it available wider. Either way, we can start flat and refactor into subfoldres as the number of libraries grows.Examples:
# Flat
/libs/api/middlewares
# Grouped
/libs/api/clients/cms
/libs/api/clients/x-road
/libs/api/utilities/graphql
Run
AWS_PROFILE=<profile> yarn nx get-secrets <project>
Example:
AWS_PROFILE=islandis yarn nx get-secrets api
This API has minimal logic and mostly wraps external services. Until we figure out an integration/contract testing strategy, the main focus is on unit tests using mocks for external dependencies.
There should be good test coverage on shared code and services. The resolvers are tricky to test so they should be kept simple, with the main logic in unit tested services.
To start the API, run:
yarn start api
If you change a GraphQL schema, you need to update the generated TypeScript types which are used by resolvers and client applications:
yarn nx run api:schemas/codegen
To run tests, you can either run all tests affected by your changes, or run tests in a specific project:
yarn affected:test
yarn test api
Many jest arguments can be passed to test commands. For more details, add
--help
.yarn test api --help
yarn test api --watch
yarn test api --updateSnapshots
yarn test api --runInBand
You can create a new domain or shared library using an NX schematic:
yarn generate @nrwl/node:library api/domains/your-domain
yarn generate @nrwl/node:library api/your-library
If your domain needs to expose fields in the GraphQL schema, make sure to export
typeDefs
and resolvers
in your domain's index.ts
, then add your domain to the list in /apps/spi/src/graphql/domains.ts
.Last modified 1mo ago