Conversation
|
|
|
Error agent completed without reporting progress |
|
@malcolm-kee is attempting to deploy a commit to the Hey API Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: e4a9553 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3570 +/- ##
==========================================
- Coverage 40.04% 39.37% -0.67%
==========================================
Files 520 543 +23
Lines 19243 20379 +1136
Branches 5720 6140 +420
==========================================
+ Hits 7705 8024 +319
- Misses 9342 9957 +615
- Partials 2196 2398 +202
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
7a46406 to
bc978a9
Compare
|
@malcolm-kee Before I go into it, two questions:
|
bc978a9 to
dedf542
Compare
|
@mrlubos I come up with the API design and AI was doing most of the implementations while I watch. Not final. I'm happy to iterate on this, just want some progress on this plugin. |
|
The diff is big is mostly because of the tests and snapshots. |
dedf542 to
c7133e3
Compare
@hey-api/codegen-core
@hey-api/json-schema-ref-parser
@hey-api/nuxt
@hey-api/openapi-ts
@hey-api/shared
@hey-api/spec-types
@hey-api/types
@hey-api/vite-plugin
commit: |
c7133e3 to
b119b40
Compare
packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts
Outdated
Show resolved
Hide resolved
|
I did some refactoring/enhancements:
|
|
@mrlubos I manually validated the code and made some refactoring. It would be great if you can provide some feedbacks, especially on the API. |
ac3c300 to
b34b5bd
Compare
|
More revision:
|
b34b5bd to
9b8e509
Compare
|
Added |
9b8e509 to
1963185
Compare
|
Change plugin options from |
e3e18f0 to
7bb2ae4
Compare
|
Ideas on how to continue enhancing this PR, in case anyone want to take over this, since I might not be free to iterate on this: Implement
|
|
@malcolm-kee good eye – that one is intentional. If we're skipping or throwing an error on missing mocks, there's no need to provide any arguments. More importantly, this is the base experience I want people to have: const server = setupServer(
...createMswHandlers().all(),
);
server.listen();or with single handler: const server = setupServer(
createMswHandlers().one.tuiPublish(),
);
server.listen();As with the rest of the ecosystem, it should just work™. In the end, the behavior I'm steering towards with this v0 is mock what we can (based on the examples field), and skip everything else. The above examples feel good to me, just need to bring back the After playing with it more, I agree that fake data is very high on the priority list. A lot of specs simply don't have example fields, which would make the default experience basically do nothing haha. Did you have an interest in working on that feature? |
|
I agree with the principle of it should just work, but I want to push back a little, as I disagree that making the parameter optional is achieving that. There are two scenarios when someone add a msw handlers:
By making the parameter optional in all cases, we're making the life for scenario 2 easier but at the cost of scenario 1. Now that instead of letting the type guide them on which mock handlers can be used safely, they have to wait until the runtime error in the test to let them know if a manual mock data is required. A middle ground that we can attempt is to apply different logic based on the method - Last thing I want to point out is that this is a decision we had to make even with the faker plugin, because user might disable default value from faker with |
|
Yeah I'm interested in working on the faker plugin, didn't do anything yet cause I assumed you've started something? |
|
@mrlubos is the plan to wait for faker plugin before merging this? |
|
@malcolm-kee Not necessarily, but it requires several more days to prepare the response modeling part, and I need to work on other things too so I will pick this up again later |
|
@malcolm-kee fyi, this is how far I am with it, and 1 of those files are docs |
|
WIP for faker plugin: |
|
TL;DR — Adds a new Key changes
Summary | 71 files | 30 commits | base: MSW handler generation from OpenAPI operations
Each operation produces a function like Each handler also exports a named response type alias — e.g.
|
| Option | Type | Default | Purpose |
|---|---|---|---|
baseUrl |
string | number | boolean |
'*' |
Base URL for handler path matching |
responseFallback |
'error' | 'passthrough' |
'error' |
Behavior when no response is provided |
source |
MaybeArray<PluginSourceNames> |
['@hey-api/examples'] |
Controls example embedding via source plugins |
v2/plugin.ts · shared/sort.ts · types.ts · config.ts
Type-safe baseUrl derived from ClientOptions
Before: Generated
RequestHandlerOptions.baseUrlwas typed asstring?.
After: ThebaseUrlproperty is typed asClientOptions['baseUrl']?when the TypeScript plugin emits aClientOptionstype, falling back tostringotherwise.
The createRequestHandlerOptions function uses plugin.querySymbol to look up the TypeScript plugin's ClientOptions type at generation time. When found, it uses a conditional $if branch to derive the baseUrl type as an indexed access on that symbol, ensuring MSW handler base URLs accept exactly the same server URL union as the generated client. A responseFallback property is also included on RequestHandlerOptions, allowing per-handler override of the global fallback behavior.
shared/types.ts · client-core/client.ts
Extract getBaseUrl() to shared package
Before:
resolveBaseUrlStringwas a private function inside the client-core plugin. OpenAPI 2.0 specs with host-only server URLs (e.g.api.postmarkapp.com/) did not emit abaseUrlin generated client config.
After: Base URL resolution is a publicgetBaseUrl()utility in@hey-api/shared, consumed by both client-core and the new MSW plugin. Host-only URLs are now correctly emitted.
The extracted function simplifies the client-core code — the old 20-line resolveBaseUrlString + inline URL validation is replaced by a single getBaseUrl(plugin.config.baseUrl ?? true, plugin.context.ir) call, with property building via $if chaining on the $.object().
url.ts · client-core/client.ts
New @hey-api/examples plugin and plugin taxonomy changes
Before: Data-source plugins were tagged as
mockerand referenced viaPluginMockNames.
After: A new@hey-api/examplesplugin scaffold is introduced with asourcetag,PluginMockNamesis renamed toPluginSourceNames, and a newhandlertag is added for the MSW plugin.
The @hey-api/examples plugin currently has a stub handler (() => {}) — its full implementation is deferred. The MSW plugin declares it as a dependency via config.source, which resolveConfig normalizes to an array and adds to plugin.dependencies. This replaces the previous valueSources approach with a plugin-based dependency model where source: [] disables example embedding entirely.
examples/config.ts · examples/types.ts · plugins/types.ts · shared/plugins/types.ts
Tests, specs, and documentation
Before: No MSW test infrastructure; docs page was a feature-status placeholder.
After: Full test coverage across 3 snapshot scenarios, runtime integration tests, type-level tests, themockers.yamltest spec, and complete plugin documentation.
Snapshot tests in packages/openapi-ts-tests/msw/v2/ cover default, source-default (with examples), and source-disabled (without examples) scenarios. The mockers.yaml spec exercises GET, POST, and PUT operations with varying response content types (json, text, binary) and example values. The openapi-ts-fetch example adds runtime tests verifying actual MSW behavior (static responses, custom resolvers, path params, status codes, void operations, handler overrides) and type tests validating type safety with expectTypeOf. Documentation replaces the placeholder with full installation, usage, and API reference sections.
3.1.x.test.ts · msw.test.ts · msw-types.test-d.ts · msw.md
|
@malcolm-kee from now on the builds should be passing. I'm going to move examples from OpenAPI into their own plugin so they can be freely combined with other sources such as Faker |

Closes #1486
Summary
Implement
mswplugin that generates amsw.gen.tsfile with type-safe mock handler factories from OpenAPI specs. Each operation is exported as a named handler creator (<operationId>Mock) with a wildcard base URL, plus agetAllMockshelper to generate handlers for all operations at once. AcreateMswHandlerFactoryfunction is also exported for custom base URL binding.Important
Even though many expect fake data generation is part of this plugin, that probably overlaps with faker plugin. The only mock data handled by this plugin at the moment is the
exampledefined in the OpenAPI spec.API Design
Configuration
Usage
Individual handler exports (wildcard base URL)
Handler options
MSW handler options can be passed as a second argument:
Custom base URL (
createMswHandlerFactory)All handlers (
getAllMocks)Design decisions
Why
<operationId>Mocknaming? — AppendingMockavoids naming collisions with other generated artifacts (types, SDK functions) while keeping the handler clearly associated with its operation.Why both individual exports and
createMswHandlerFactory? — Individual exports use a wildcard (*) base URL for zero-config convenience. The factory function allows binding to a specific base URL when needed (e.g. integration tests against a specific server).Why
valueSourcesinstead ofexample: boolean? — Extensible for future sources (e.g.['example', 'faker']when faker plugin is ready).onMissingMock— Operations that require a response argument (no default example) are either skipped ('skip') or return a 501 ('error'). Overrides always take precedence.Handler creator signatures
{ result, status? } | ToResponseUnion<Responses> | HttpResponseResolver<PathParams, Body>{ result, status? } | ToResponseUnion<Responses> | HttpResponseResolver<PathParams, Body>HttpResponseResolver<PathParams, Body>* Optional if the spec defines an
examplefor the dominant response.Response method selection
application/jsonHttpResponse.json()text/*HttpResponse.text()binary/octet-streamnew HttpResponse()new HttpResponse(null)When multiple 2xx responses exist, the dominant one is chosen by priority: json > text > binary > void.
Known limitations
HttpResponseResolverto avoid MSW'sDefaultBodyTypeconstraint issues with union/void response types