Feat: Generate TypeScript API client from OpenAPI spec#180
Merged
kilodesodiq-arch merged 3 commits intoJun 22, 2026
Merged
Conversation
The secret is only needed when sign()/verify() are actually called, not during module initialization. This allows the spec export script (and any other non-webhook boot path) to start the app without WEBHOOK_SECRET present. If called without a configured secret, it still fails loudly.
Contributor
Author
|
@kilodesodiq-arch Kindly review. |
Contributor
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #118
Feat: Generate Typed TypeScript HTTP Client from OpenAPI Spec #118
Summary
Generates a fully typed TypeScript HTTP client from the NestJS Swagger/OpenAPI spec and wires it into the frontend, replacing raw fetch calls with compile-time–safe URL and request-body checking.
Backend
DocumentBuilderconfig intosrc/swagger.config.tsscripts/export-spec.ts— bootstraps NestJS without an HTTP listener and writesopenapi.jsonto the frontend directory; registered asnpm run spec:export@ApiBodydecorators onverification-inbox.controller.ts(approve,reject,requestResubmission,addInternalNote) — bodies were accepted at runtime but invisible in the specadditionalProperties: trueto themetadatafield inCreateCampaignDto/UpdateCampaignDtoso the generated types produceRecord<string, unknown>instead ofRecord<string, never>Frontend
openapi-fetch(runtime client) andopenapi-typescript(codegen) as dependencies;pnpm generate:apiregeneratessrc/lib/generated/api.tsfromopenapi.jsonopenapi.jsonandsrc/lib/generated/api.ts(do not edit by hand)src/lib/api-client.ts—createClient<paths>routed through the existingfetchClientmock layer soNEXT_PUBLIC_USE_MOCKS=truecontinues to work transparentlyuseCampaigns,useHealthStatus,useOptimisticCampaignMutations,verification-api,verification-inbox-api, andAidDistributionMapto the typed client/campaigns,/health,/verification-inboxetc. without the required/api/v1/prefixuseAidPackagesandcsv-validation(/recipients/import/*) intentionally kept on rawfetchClient— these endpoints are mock-only and absent from the backend Swagger specCI
Adds two steps after Build in
backend-ci.yml: re-runsspec:export, thengit diff --exit-code app/frontend/openapi.jsonto fail the pipeline if the committed spec has drifted from the backend.Maintainer Notice — Pre-existing Frontend Routing Issue (out of scope for this PR)
While smoke-testing the frontend during this PR, a pre-existing issue was found that prevents the frontend from rendering at all on
main.The root layout (
src/app/layout.tsx) callsgetMessages()fromnext-intl/serveroutside the[locale]route segment. Without a locale middleware to inject the locale into the request context,getRequestConfigreceivesrequestLocale = undefined, hits thenotFound()guard insrc/i18n.ts, and every page returns 404. Additionally, Next.js 16 (used by this project) has renamedmiddleware.tstoproxy.ts, so the old convention no longer applies.The fix is: (1) add
proxy.tsatapp/frontend/proxy.tsusingnext-intl/middleware'screateMiddlewarefor locale detection and redirect, and (2) movegetMessages()andNextIntlClientProviderfrom the root layout intosrc/app/[locale]/layout.tsxwhere locale context is available.Testing
Manual verification:
npm run start:dev) and Swagger UI confirmed live athttp://localhost:3000/api/docs— all tag groups visible (Analytics, Campaigns, Verification Inbox, etc.)mock-api/client.test.ts) confirm thefetchClientinterception layer still works throughapiClientwhenNEXT_PUBLIC_USE_MOCKS=trueChecklist