Repository navigation
Implement ngx-openapi-resource library - #1
Conversation
Agent-Logs-Url: https://github.com/holisticon/ngx-openapi-resource/sessions/7e3b4107-a070-45c1-9b7d-0b22cc27166e Co-authored-by: luchsamapparat <875017+luchsamapparat@users.noreply.github.com>
… OpenApiHttpClient Agent-Logs-Url: https://github.com/holisticon/ngx-openapi-resource/sessions/7e3b4107-a070-45c1-9b7d-0b22cc27166e Co-authored-by: luchsamapparat <875017+luchsamapparat@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR implements the new ngx-openapi-resource Angular library, providing type-safe wrappers around Angular’s httpResource (reactive) and HttpClient (imperative) driven by openapi-typescript-generated paths types.
Changes:
- Added
createOpenApiResource<Paths>()for typed, signal-driven HTTP resources (GET/POST/PUT/PATCH/DELETE). - Added
OpenApiHttpClient<Paths>base class for typed imperative HTTP calls. - Introduced shared OpenAPI utility types plus comprehensive unit/integration tests and updated demo/docs.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/ngx-openapi-resource/src/public-api.ts | Replaced default Angular CLI export with explicit library exports/types. |
| projects/ngx-openapi-resource/src/lib/types.ts | Added OpenAPI utility types for parameters/body/options typing. |
| projects/ngx-openapi-resource/src/lib/open-api-resource.ts | Implemented createOpenApiResource plus URL/query helpers. |
| projects/ngx-openapi-resource/src/lib/open-api-http-client.ts | Implemented typed HttpClient wrapper base class. |
| projects/ngx-openapi-resource/src/lib/ngx-openapi-resource.ts | Removed the starter placeholder component. |
| projects/ngx-openapi-resource/src/lib/ngx-openapi-resource.spec.ts | Added unit tests for helpers + integration tests for both APIs. |
| projects/ngx-openapi-resource/package.json | Added openapi-typescript-helpers as a peer dependency. |
| projects/ngx-openapi-resource/README.md | Documented installation and usage of both APIs. |
| projects/demo/src/app/app.ts | Updated demo to showcase reactive + imperative usage. |
| projects/demo/src/app/app.config.ts | Added provideHttpClient() to support demo HTTP calls. |
| package.json | Added OpenAPI tooling dependencies to the workspace. |
| package-lock.json | Lockfile updated for new dependencies and workspace naming. |
| README.md | Updated root README with library usage docs. |
| url: buildUrl(baseUrl, String(path), r.path), | ||
| params: toHttpParams(r.query), | ||
| headers: r.headers as Record<string, string>, | ||
| context: r.context as import('@angular/common/http').HttpContext, | ||
| withCredentials: r.withCredentials, |
There was a problem hiding this comment.
In createOpenApiResource, headers is cast to Record<string, string> before passing to httpResource. This is narrower than the library's own OpenApiRequestOptions.headers (which allows HttpHeaders and multi-valued headers) and can hide type errors for callers. Prefer passing through the original headers type (or casting to HttpHeaders | Record<string, string | ReadonlyArray<string>>) consistently with OpenApiRequestOptions.
There was a problem hiding this comment.
Applied in commit 94ba395.
Changes made:
toRequestShapenow properly typesheadersasHttpHeaders | Record<string, string | ReadonlyArray<string>>(matchingHttpResourceRequest.headers) — no cast needed anymore- All 5
as Record<string, string>casts increateOpenApiResourceremoved buildUrl/toHttpParamsextracted to a newurl-utils.tsmodule —open-api-http-clientnow imports from there instead ofopen-api-resource, removing the bundle couplingOpenApiHttpClient.delete()signature updated to acceptOpenApiOperationRequest(with body) for parity withcreateOpenApiResource.delete()openapi-typescriptmoved todevDependencies
| "@angular/router": "^21.2.0", | ||
| "openapi-typescript": "^7.13.0", | ||
| "openapi-typescript-helpers": "^0.1.0", | ||
| "rxjs": "~7.8.0", |
There was a problem hiding this comment.
openapi-typescript is a CLI/codegen tool and is not imported/used at runtime in the workspace (only referenced in docs). Keeping it under dependencies will install it for production builds and increase install footprint; it should typically be a devDependency instead.
There was a problem hiding this comment.
openapi-typescript should stay as a devDependency in the workspace root, not a peer dependency.
The library itself never imports from openapi-typescript at runtime or compile time — only from openapi-typescript-helpers (which is already a peer dependency in the library's package.json). openapi-typescript is a CLI tool consumers run once during their own build to generate paths types from an OpenAPI spec. Since it doesn't need to be present in the consumer's node_modules at runtime (or even at Angular compile time), listing it as a peer dependency would impose an unnecessary installation requirement on every consumer of this library.
There was a problem hiding this comment.
Already applied in commit a2e9119 — openapi-typescript was moved from dependencies to devDependencies in the workspace root package.json. The library's own package.json does not list it at all (neither as dependency nor peer dependency), since the library only imports from openapi-typescript-helpers at compile time.
| PathRecord, | ||
| } from './types'; | ||
| import { buildUrl, toHttpParams } from './open-api-resource'; | ||
|
|
There was a problem hiding this comment.
OpenApiHttpClient imports buildUrl/toHttpParams from open-api-resource.ts, which also imports httpResource types/logic. This couples the imperative client to the resource module and can force consumers using only OpenApiHttpClient to still pull in the httpResource implementation at bundle time. Consider moving shared helpers into a small side-effect-free util module (e.g. url.ts/http-params.ts) that both files import from.
There was a problem hiding this comment.
Already applied in commit 94ba395. buildUrl and toHttpParams were extracted to a new src/lib/url-utils.ts module. open-api-http-client.ts now imports directly from ./url-utils instead of ./open-api-resource, removing the bundle coupling.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…pescript to devDependencies Agent-Logs-Url: https://github.com/holisticon/ngx-openapi-resource/sessions/8914c92c-31ca-4466-a099-883c15843f42 Co-authored-by: luchsamapparat <875017+luchsamapparat@users.noreply.github.com>
…ce-library' Co-authored-by: luchsamapparat <875017+luchsamapparat@users.noreply.github.com>
|
@copilot for the demo, use an OpenAPI YAML spec and generate types from it using |
…ript Agent-Logs-Url: https://github.com/holisticon/ngx-openapi-resource/sessions/249a321e-c251-410c-b5ba-aeec3e3efb60 Co-authored-by: luchsamapparat <875017+luchsamapparat@users.noreply.github.com>
Done in commit
|
|
@copilot implement this plan Mitigation Plan: Fix Deviations from Original DesignIssues to fix
Fix 1: Params shape (breaking — affects types, resource, http-client, tests, demo)The agreed shape was
|
| File | Change |
|---|---|
projects/ngx-openapi-resource/src/lib/types.ts |
Reshape OpenApiOperationRequest — nest path/query under params |
projects/ngx-openapi-resource/src/lib/open-api-resource.ts |
Read r.params?.path, r.params?.query; update JSDoc |
projects/ngx-openapi-resource/src/lib/open-api-http-client.ts |
Read opts.params?.path, opts.params?.query; update JSDoc |
projects/ngx-openapi-resource/src/lib/ngx-openapi-resource.spec.ts |
Update all call sites to nested params |
projects/demo/openapi.yaml |
Add POST/PUT/DELETE endpoints + NewTodo schema |
projects/demo/src/app/api.types.ts |
Regenerate + commit |
projects/demo/src/app/app.ts |
Add mutation demo section |
package.json (root) |
Move openapi-typescript-helpers to devDependencies |
Verification
ng build ngx-openapi-resource— zero TS errorsng test ngx-openapi-resource— all specs passng serve demo— mutations section renders and works- Hover:
api.get('/todos/{id}', () => ({ params: { path: { id: 1 } } }))— infersTodo - Hover:
client.post('/todos', { body: { ... } })—bodytyped asNewTodo, return isObservable<Todo> - Omitting required
params.pathwhen anidpath param is required → TypeScript compile error
…ith mutations, move openapi-typescript-helpers to devDeps Agent-Logs-Url: https://github.com/holisticon/ngx-openapi-resource/sessions/fde12950-defb-4db6-8c3f-1fdbb5fc1422 Co-authored-by: luchsamapparat <875017+luchsamapparat@users.noreply.github.com>
... Implemented in commit
Build: zero TS errors. Tests: 21/21 pass. |
BREAKING CHANGE: createOpenApiResource now returns a callable function instead
of an object with .get(), .post(), .put(), .patch(), .delete() methods.
Before:
const api = createOpenApiResource<paths>({ baseUrl });
api.get('/pets', () => ({ params: { query: { limit: 10 } } }));
api.post('/pets', () => ({ body: { name: 'Buddy' } }));
After:
const api = createOpenApiResource<paths>({ baseUrl });
api('/pets', () => ({ params: { query: { limit: 10 } } }));
api('/pets', () => ({ body: { name: 'Buddy' } }), { method: 'post' });
The method option is type-safe: only methods defined for the given path
are allowed (autocomplete shows valid methods per path).
This aligns with Angular's guidance that httpResource should be used for
reads; mutations should use OpenApiHttpClient instead.
…and update related tests
Implements the
ngx-openapi-resourceAngular library — type-safe wrappers around Angular'shttpResourceandHttpClientdriven by types generated byopenapi-typescript. Wrong paths, misspelled parameter names, and mismatched body shapes are caught at compile time.Core API
createOpenApiResource<Paths>(config)— reactive factoryWraps Angular's
httpResource; re-fetches automatically when signals change. Returnundefinedfrom the request function to idle the resource.OpenApiHttpClient<Paths>— imperative base classWraps
HttpClientwith typedget/post/put/patch/deletemethods. Extend per-API:Key implementation notes
PathRecord = {}— matches the same loose constraint used byopenapi-typescript-helpers, avoiding TS2344 errors when passing generatedpathsinterfacesOpOf<Paths, Path, Method>— conditional type inference (infer Op) used instead of directPaths[Path][Method]indexing, which fails whenPaths extends {}OperationParamsObject<Op>— inner{ path?, query? }type; required path params propagate throughParamEntry<'params', ...>so omitting them is a compile errorOpenApiOperationRequest<Op>uses{ params: { path?, query? }, body? }— matching the openapi-fetch convention exactlybuildUrlURI-encodes path parameter substitutions;toHttpParamshandles scalar, array, null, and undefined query valuesOpenApiHttpClientreturnsresponseType: 'json', observe: 'body'to steer TypeScript to the correctHttpClientgeneric overloadbuildUrl/toHttpParamsare extracted into a side-effect-freeurl-utils.tsmodule shared by bothopen-api-resourceandopen-api-http-client, avoiding unnecessary bundle couplingFiles
src/lib/types.tssrc/lib/url-utils.tsbuildUrlandtoHttpParamshelperssrc/lib/open-api-resource.tscreateOpenApiResourcefactorysrc/lib/open-api-http-client.tsOpenApiHttpClientbase classsrc/public-api.tssrc/lib/ngx-openapi-resource.spec.tsprojects/demo/openapi.yamlprojects/demo/src/app/api.types.tsopenapi.yamlviaopenapi-typescriptprojects/demo/src/app/app.tsDemo
The demo uses a real OpenAPI 3.0 YAML spec (
projects/demo/openapi.yaml) describing the JSONPlaceholder todos API, including full CRUD endpoints (GET /todos,POST /todos,GET /todos/{id},PUT /todos/{id},DELETE /todos/{id}). Types are generated from it usingopenapi-typescriptand committed atprojects/demo/src/app/api.types.ts. To regenerate:The demo app demonstrates:
createOpenApiResourcefetching a paginated list with query paramscreateOpenApiResourcewith a signal-driven form; reloads the list on success viatodos.reload()OpenApiHttpClientwith typed path params and request bodiesOriginal prompt
Start implementation
The user has attached the following file paths as relevant context:
- .github\copilot-instructions.md
- AGENTS.md
[Chronological Review: The conversation began with inquiries about the `openapi-typescript` npm package and Angular's new Resource Signals, particularly the `httpResource`. The user then expressed interest in creating a variant of `httpResource` that integrates with types generated by `openapi-typescript`. Following this, the user requested a plan to build a library named `openApiResource`, which would utilize Angular's `HttpClient` and support modern best practices. The user also suggested removing unnecessary components from the workspace and ensuring the library is built for publication. The conversation progressed with discussions about the potential need for an `OpenApiHttpClient` and the installation of relevant packages. The user agreed with the recommendations and finally requested to start the implementation.][Intent Mapping:
openapi-typescriptnpm package work?" - Understanding the package functionality.httpResourcethat works with the types generated byopenapi-typescriptsimilar to howopenapi-fetchworks?" - Exploring integration possibilities.openApiResource..." - Requesting a structured approach to library development.httpResourceonly supportsGETrequests, maybe the library should also provide anOpenApiHttpClient..." - Suggesting additional functionality.openapi-typescript,openapi-typescript-helpersand other packages that might help" - Directing package installations.[Technical Inventory:
openapi-typescript: A package for generating TypeScript types from OpenAPI specifications.HttpClient: A service for making HTTP requests in Angular applications.openapi-fetch: A utility for fetching data using OpenAPI types.openapi-typescript-helpers: A package that may assist in working with OpenAPI-generated types.][Code Archaeology: No specific files or code changes have been documented yet, as the conversation is still in the planning and initiation phase.]
[Progress Assessment:
[Context Validation: All necessary context for continuing the library development is captured, including user goals, technical requirements, and the need for best practices.]
[Recent Commands Analysis:
openApiResourcelibrary.HttpClient.]1. Conversation Overview: - Primary Objectives: The user aims to create a library named `openApiResource` that integrates with Angular's `HttpClient` and works with types generated by `openapi-typescript`. - Session Context: The conversation has progressed from understanding existing technologies to planning and initiating the implementation of a new library. - User Intent Evolution: The user has moved from seeking information to actively planning and initiating the development of a library.- Technical Foundation:
- Angular's
- Codebase Status:
- No specific files or code changes have been documented yet, as the conversation is still in the planning and initiation phase.
- Problem Resolution:...
openapi-typescript: A package for generating TypeScript types from OpenAPI specifications.HttpClient: A service for making HTTP requests in Angular applications.openapi-fetch: A utility for fetching data using OpenAPI types.openapi-typescript-helpers: A package that may assist in working with OpenAPI-generated types.Created from VS Code.
💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.