OpenAPI / Swagger from contracts
The same contracts generate a full OpenAPI 3.0 document — method, path, params, request body, and responses all derived from the Zod schemas, so your API docs can never drift from what the client calls.
import { NestFactory } from '@nestjs/core'
import { setupContractSwagger } from '@tahanabavi/typewire-nestjs'
import { contracts } from './contracts'
const app = await NestFactory.create(AppModule)
setupContractSwagger(app, contracts, {
path: 'docs',
info: { title: 'My API', version: '1.0.0' },
})
await app.listen(3000)
// Swagger UI → http://localhost:3000/docs
// Raw JSON → http://localhost:3000/docs-json@nestjs/swagger is an optional peer dependency — install it only if you use setupContractSwagger(). Prefer to serve the document yourself? Build the plain object directly:
import { buildOpenApiDocument } from '@tahanabavi/typewire-nestjs'
const document = buildOpenApiDocument(contracts, {
info: { title: 'My API', version: '1.0.0' },
})
// hand to SwaggerModule.setup(), write to disk, feed a client generator, ...What the generator maps from each contract endpoint:
| Contract | OpenAPI |
|---|---|
path: "/users/:id" | /users/{id} with a required id path parameter |
request.path / request.query / request.headers | typed parameters (array query params → explode: true, matching repeated-key serialization) |
request.body (or a flat request) | requestBody — application/json, or multipart/form-data when bodyType: "form-data" |
response | the success response (201 for POST, 200 otherwise) |
z.date() / z.bigint() / file fields | string+date-time / string+int64 / string+binary (never throws) |
auth: true | bearerAuth security requirement + documented 401 |
| — | a shared ContractValidationError schema on every 400 |
Options: bearerAuth (default on), includeValidationError (default on), servers, and successStatus(endpoint) to override the documented success code.
Exports
@tahanabavi/typewire-nestjs
| Export | Kind | Purpose |
|---|---|---|
TypeFetchEndpoint | decorator | Bind route + validation from an http contract endpoint |
UseContract | decorator | Validation only, on manually declared routes — any transport |
ContractInput / ContractPath / ContractQuery / ContractBody / ContractHeaders | param decorators | Validated request data |
TypeFetchModule | module | forRoot() global options |
ContractValidationInterceptor | interceptor | Applied automatically; exported for advanced wiring |
ResponseEnvelopeInterceptor / ContractEnvelopeExceptionFilter | interceptor / filter | Response-envelope success + error wrapping |
decryptRequestBody / encryptResponseData / encryptValue / decryptValue | functions | Field-level encryption building blocks |
getContractEndpoint | helper | Read the bound endpoint in guards/interceptors |
createPermissionGuard | function | Build a guard enforcing the contract's permission key → typed 403 |
RequirePermission | decorator | Declare/override a permission requirement on a route |
PermissionGuardConfig / PermissionDecisionLike | types | Config and decision shapes for the permission guard |
setupContractSwagger | helper | Build + mount Swagger UI from contracts |
buildOpenApiDocument | function | Contracts → plain OpenAPI 3.0 document |
InferRequest / InferResponse / ContractHandler | types | End-to-end handler typing |
ContractValidationException / ContractResponseViolationException | exceptions | Thrown on 400 / 500 |
formatZodIssues, coerceInput, validateRequest | utilities | Building blocks for custom pipelines |
contractFile / isContractFile / CONTRACT_EXPOSED_HEADERS | function / helpers | Non-JSON responseType responses and the headers they need |
SkipEnvelope | decorator | Exempt a route from the global response envelope |
transportOf / isHttpEndpoint / assertTransport / describeContractRoute | helpers | Read an endpoint's wire without touching a field it may not have |
TYPEFETCH_ENDPOINT_METADATA, TYPEFETCH_OPTIONS_METADATA, TYPEFETCH_MODULE_OPTIONS, TYPEFETCH_PERMISSION_METADATA, TYPEFETCH_SKIP_ENVELOPE_METADATA, PARSED_REQUEST_KEY | constants | Metadata & DI tokens |
@tahanabavi/typewire-nestjs/grpc
| Export | Kind | Purpose |
|---|---|---|
GrpcEndpoint | decorator | Bind a Connect JSON route from a transport: "grpc" contract |
GrpcException | exception | Throw a specific gRPC status from a handler |
GrpcDeadline | param decorator | The caller's deadline, with an AbortSignal |
ConnectExceptionFilter / ConnectDeadlineInterceptor | filter / interceptor | Applied automatically; exported for manual wiring |
toConnectError / codeFromThrownStatus / parseDeadline | functions | The mapping rules, testable on their own |
GrpcCode / codeName / statusFromGrpcCode | re-exports | From @tahanabavi/typefetch-grpc, so a handler needs one import |
@tahanabavi/typewire-nestjs/graphql
| Export | Kind | Purpose |
|---|---|---|
ContractGraphQLModule | module | forRoot({ contracts, path?, allowGet?, requireAllResolvers? }) |
GraphQLEndpoint | decorator | Mark a provider method as the resolver for a GraphQL contract |
GraphqlException | exception | Throw a specific extensions.code |
ContractGraphQLRegistry / ContractGraphQLDispatcher | services | The operation index and the request pipeline |
toGraphqlError / graphqlCodeFromStatus / statusFromGraphqlCode | functions | The mapping rules |
@tahanabavi/typewire-nestjs/socket
| Export | Kind | Purpose |
|---|---|---|
bindSocketContracts | function | Give every contract event its wire name and id |
SocketEvent | decorator | Bind a gateway handler to a client->server event |
SocketPayload / SocketEventInfo | param decorators | The validated frame; the bound event |
emitSocketEvent / createSocketEmitter | functions | Push a server->client event, validated |
createSocketPermissionGuard | function | Enforce an event's contract permission server-side |
SocketContractException / SocketAckInterceptor | exception / interceptor | Contract failures on a frame; ack validation |
InferSocketRequest / InferSocketAck / InferSocketPayload | types | End-to-end gateway typing |
License
MIT © Taha Nabavi