GraphQL
PURISTA does not enforce a dedicated GraphQL package. The recommended approach is to keep GraphQL as an adapter layer and invoke commands from resolvers.
Why this works well
- Commands already define runtime-validated contracts via schemas.
- Business logic remains independent from GraphQL-specific concerns.
- You can keep REST and GraphQL side-by-side over the same command set.
Typical architecture
- Build and start your services as usual.
- In your GraphQL server, call commands from resolvers (mutation/query handlers).
- Map GraphQL input to command payload/parameter, and map command output to GraphQL types.
Resolver example (conceptual)
typescript
const resolvers = {
Mutation: {
async createUser(_: unknown, args: { input: { email: string } }, ctx: { userId: string }) {
const payload = { email: args.input.email }
const parameter = { requestedBy: ctx.userId }
return commandClient.UserService['1'].createUser(payload, parameter)
},
},
}commandClient can be an in-process embedded client (monolith) or a generated client (distributed setup).
Recommended practices
- Keep GraphQL schema focused on consumer needs; keep command contracts focused on domain needs.
- Validate/normalize GraphQL input before invoking commands.
- Propagate principal/tenant context explicitly into command parameters or message fields.
- Prefer small, composable commands over large GraphQL-specific orchestration logic.
See also:
