@ebca/gql-gateway
v0.0.11
Published
GraphQL gateway for EBCA queries, inbound components, snapshots, and subscriptions.
Maintainers
Readme
@ebca/gql-gateway
GraphQL gateway for EBCA read repositories, inbound components, snapshots, and live projections.
@ebca/gql-gateway exposes the same EBCA application surface as the WebSocket gateway without putting GraphQL runtime concerns into @ebca/core. The default package is transport-neutral: it validates @EbcaQuery(...) declarations open to gql, writes exposed inbound components, resolves projected component snapshots, filters lifecycle projections, and returns JSON-ready payloads.
An optional NestJS GraphQL bridge is available at @ebca/gql-gateway/nestjs.
Install
npm install @ebca/gql-gateway typeormFor the optional NestJS GraphQL bridge:
npm install @ebca/gql-gateway typeorm @nestjs/graphql @nestjs/microservices graphqlQuery Gateway
import { EbcaGqlGatewayModule } from '@ebca/gql-gateway';
EbcaGqlGatewayModule.forRoot({
defaultRoles: ['user'],
});The consuming application decides how to authenticate GraphQL requests. The gateway receives an already authenticated EBCA identity and request id from the resolver layer.
Optional NestJS GraphQL Bridge
import { EbcaGqlNestjsModule } from '@ebca/gql-gateway/nestjs';
EbcaGqlNestjsModule.forRoot({
identityResolver: AppGraphqlIdentityResolver,
ebca: {
defaultRoles: ['user'],
},
});The bridge provides:
EbcaJsonscalar;- generic
ebcaQuery(input)field; - generic
ebcaComponentMutation(input)field; - generic
ebcaComponentRequest(input)field; - generic
ebcaComponent(input)subscription; - identity resolver injection;
- call-through to the neutral gateway services.
Query Declaration
import {
BaseEntity,
EbcaQuery,
EbcaQueryParam,
EbcaReadRepository,
Entity,
} from '@ebca/core';
@Entity({ name: 'OrderEntity' })
class OrderEntity extends BaseEntity {}
class OrdersParams {
@EbcaQueryParam({ required: true })
readonly accountId!: string;
}
export interface OrderSummary {
readonly id: string;
readonly status: string;
}
@EbcaReadRepository()
export class OrdersReadRepository {
@EbcaQuery({
name: 'orders',
entityClass: OrderEntity,
})
async orders(params: OrdersParams): Promise<readonly OrderSummary[]> {
return [];
}
}Generated GraphQL contracts infer GraphqlQueryResultByName from the query method return annotation and exported declarations reachable from the repository import graph. resultType is only needed as an explicit override for unusual signatures.
Omit query gates when a query should be visible through every query transport, pass a non-empty list such as gates: ['gql'] to restrict it, or use gates: [] for repository-internal methods.
Realtime Components
GraphQL component subscriptions use the same component projection metadata as the WebSocket gateway:
@Component({
projection: {
expose: true,
gates: ['gql'],
audience: 'owner',
ownerField: 'playerId',
},
})
export class InventoryComponent extends BaseComponent {}The NestJS bridge listens to EBCA lifecycle topics, applies the same audience and policy rules, and emits ebcaComponent(input) events to matching GraphQL subscribers. Component snapshots use ebcaComponentRequest(input) and the same projection visibility.
ComponentOptions.websocket remains supported as a deprecated alias for older components. New declarations should use projection; omit gates when the component should be visible through every realtime projection gateway.
Inbound GraphQL mutations use @Component({ inbound: { expose: true, fields: [...] } }), exactly like REST and WebSocket inbound writes. For owner-scoped writes, GraphQL validates ownership through ownerComponent; owner fields copied from the client payload are not trusted.
Command components use the same ComponentManager path as other inbound writes. They stay transient unless core metadata sets transient: false. GraphQL creates a random commandId when one is missing, so idempotent retries need a stable caller-provided commandId exposed in inbound.fields.
Why This Is Useful
GraphQL often creates a parallel DTO/service layer. EBCA keeps the read-side contract close to the read repository:
- params are declared once;
- validation lives in EBCA metadata;
- multiple transports can reuse the same query;
- domain reads can be shared across apps;
- live component visibility is declared once;
- generated contracts and runtime reports see the same surface.
The package keeps GraphQL as an adapter, not the owner of business logic.
Build
bun run buildThis builds the transport-neutral query gateway. The neutral gateway imports TypeORM for collection snapshot reads.
bun run build:nestjsThis builds the optional @ebca/gql-gateway/nestjs subpath and requires @nestjs/graphql plus graphql.
The NestJS bridge also uses @nestjs/microservices to receive EBCA lifecycle events for subscriptions.
License
Apache-2.0.
