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: bd22266 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 39.39% 38.77% -0.62%
==========================================
Files 520 542 +22
Lines 19279 20406 +1127
Branches 5714 6125 +411
==========================================
+ Hits 7595 7913 +318
- Misses 9445 10055 +610
- Partials 2239 2438 +199
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 New changes:
The last part is improving the actual handlers and fixing some bugs I found. |
I'm concerned that it introduces invalid mock. In my experience, invalid mocks are a nightmare to debug because the resulting errors usually pop up in the UI logic, far away from the network layer. We should probably force
I think it could be confusing, given that MSW handler has
Could we add explicit return type for Other than that, LGTM! |
|
@malcolm-kee added explicit types back. RE
RE |
|
I want to make sure I understand your concern correctly — could you clarify a bit?
Were you using I agree it feels odd that If it's too confusing, we can ship this plugin without |
|
One more thing, not sure if it's intentional. I realize that in the latest implementation, all the first parameter becomes optional. It was made required previously as a signal to user that they must provide the mock response. |
|
@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 | 63 files | 20 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 |
valueSources |
string[] |
['example'] |
Controls OpenAPI example embedding |
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
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, mockers, and mockers-disabled 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


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