npm.io
0.0.13 • Published 2d ago

@ebca/gql-gateway

Licence
Apache-2.0
Version
0.0.13
Deps
0
Size
166 kB
Vulns
0
Weekly
0
Stars
1

@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 typeorm

For the optional NestJS GraphQL bridge:

npm install @ebca/gql-gateway typeorm @nestjs/graphql @nestjs/microservices graphql

Query 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:

  • EbcaJson scalar;
  • 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 build

This builds the transport-neutral query gateway. The neutral gateway imports TypeORM for collection snapshot reads.

bun run build:nestjs

This 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.

Keywords