Add MSW plugin for API mocking in testing and development#93
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds Mock Service Worker (MSW) integration to ObjectStack, enabling browser and Node.js API mocking without server infrastructure. The implementation includes a new plugin package and example usage demonstrations.
Changes:
- New
@objectstack/plugin-mswpackage with MSWPlugin and ObjectStackServer classes for automatic MSW handler generation - Example package
@objectstack/example-msw-demodemonstrating both browser standalone and runtime integration patterns - Automatic endpoint generation for discovery, metadata, data CRUD operations, and UI protocol
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/plugin-msw/package.json | Package configuration with MSW 2.0+ dependency and runtime peer dependency |
| packages/plugin-msw/src/msw-plugin.ts | Main plugin implementing RuntimePlugin interface with handler generation logic |
| packages/plugin-msw/src/index.ts | Package exports for MSWPlugin, ObjectStackServer, and MSW types |
| packages/plugin-msw/tsconfig.json | TypeScript configuration for ES2020 modules |
| packages/plugin-msw/README.md | Comprehensive documentation with usage examples and API reference |
| packages/plugin-msw/CHANGELOG.md | Version 0.3.1 initial release notes |
| examples/msw-demo/package.json | Example package dependencies and scripts |
| examples/msw-demo/src/server.ts | Runtime integration pattern example |
| examples/msw-demo/src/browser.ts | Browser standalone usage example |
| examples/msw-demo/tsconfig.json | TypeScript configuration for NodeNext modules |
| examples/msw-demo/README.md | Example usage documentation |
| pnpm-lock.yaml | Lock file updates for new packages and MSW dependencies |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
| async onStop() { | ||
| if (this.worker) { | ||
| this.worker.stop(); | ||
| console.log(`[MSWPlugin] Stopped MSW worker.`); | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
The onStop lifecycle method is not part of the RuntimePlugin interface. The interface only defines optional install and onStart methods (see packages/runtime/src/types.ts). This method will never be called by the kernel and represents dead code. Consider removing it or extending the RuntimePlugin interface to include an onStop hook if this functionality is needed.
| async onStop() { | |
| if (this.worker) { | |
| this.worker.stop(); | |
| console.log(`[MSWPlugin] Stopped MSW worker.`); | |
| } | |
| } |
| const mockProtocol = { | ||
| getData: async (object: string, id: string) => { | ||
| return { id, object, name: `Mock ${object}`, status: 'active' }; | ||
| }, | ||
| createData: async (object: string, data: any) => { | ||
| return { id: 'new-id', ...data }; | ||
| }, | ||
| // Add other methods as needed | ||
| } as any; |
There was a problem hiding this comment.
The mock protocol object uses TypeScript any type casting without proper error handling or type checking. This could lead to runtime errors if the protocol methods are not properly implemented. Consider creating a proper mock that implements the expected protocol interface or using a testing library to create type-safe mocks.
| const mockProtocol = { | |
| getData: async (object: string, id: string) => { | |
| return { id, object, name: `Mock ${object}`, status: 'active' }; | |
| }, | |
| createData: async (object: string, data: any) => { | |
| return { id: 'new-id', ...data }; | |
| }, | |
| // Add other methods as needed | |
| } as any; | |
| interface MockProtocol { | |
| getData(object: string, id: string): Promise<unknown>; | |
| createData(object: string, data: unknown): Promise<unknown>; | |
| } | |
| const mockProtocol: MockProtocol = { | |
| getData: async (object: string, id: string) => { | |
| return { id, object, name: `Mock ${object}`, status: 'active' }; | |
| }, | |
| createData: async (object: string, data: unknown) => { | |
| return { id: 'new-id', ...data as Record<string, unknown> }; | |
| }, | |
| // Add other methods as needed | |
| }; |
| /** | ||
| * Custom handlers to add to MSW | ||
| */ | ||
| customHandlers?: Array<any>; |
There was a problem hiding this comment.
Using Array<any> for handler types weakens type safety. MSW provides specific handler types (e.g., RequestHandler from 'msw') that should be used instead. This would provide better type checking and IDE support for consumers of this API.
| name = 'msw'; | ||
| private options: MSWPluginOptions; | ||
| private worker: any; | ||
| private handlers: Array<any> = []; |
There was a problem hiding this comment.
Using Array<any> for the handlers property weakens type safety. Consider using a more specific type like RequestHandler[] from MSW to provide better type checking.
| export class MSWPlugin implements RuntimePlugin { | ||
| name = 'msw'; | ||
| private options: MSWPluginOptions; | ||
| private worker: any; |
There was a problem hiding this comment.
Using any type for the worker weakens type safety. Consider importing and using the proper type from MSW (e.g., SetupWorker from 'msw/browser') to provide better type checking and IDE support.
| private worker: any; | |
| private worker: ReturnType<typeof setupWorker> | null = null; |
| try { | ||
| const result = await ObjectStackServer.getData( | ||
| params.object as string, | ||
| params.id as string | ||
| ); | ||
| return HttpResponse.json(result.data, { status: result.status }); | ||
| } catch (error) { | ||
| const message = error instanceof Error ? error.message : 'Unknown error'; | ||
| return HttpResponse.json({ error: message }, { status: 404 }); | ||
| } |
There was a problem hiding this comment.
The error handling pattern here catches errors and returns a 404 status, but the getData method in ObjectStackServer.getData already handles errors and returns a response object with status and data. This creates a double error handling that could mask the original error. The outer try-catch may be unnecessary since ObjectStackServer.getData already handles errors internally.
| try { | |
| const result = await ObjectStackServer.getData( | |
| params.object as string, | |
| params.id as string | |
| ); | |
| return HttpResponse.json(result.data, { status: result.status }); | |
| } catch (error) { | |
| const message = error instanceof Error ? error.message : 'Unknown error'; | |
| return HttpResponse.json({ error: message }, { status: 404 }); | |
| } | |
| const result = await ObjectStackServer.getData( | |
| params.object as string, | |
| params.id as string | |
| ); | |
| return HttpResponse.json(result.data, { status: result.status }); |
| * ``` | ||
| */ | ||
| export class MSWPlugin implements RuntimePlugin { | ||
| name = 'msw'; |
There was a problem hiding this comment.
The plugin name 'msw' is inconsistent with the naming pattern used in other ObjectStack plugins. For example, HonoServerPlugin uses 'com.objectstack.server.hono' (reverse domain notation). Consider using a similar pattern like 'com.objectstack.msw' or 'com.objectstack.plugin.msw' for consistency across the codebase.
Implements Mock Service Worker integration for ObjectStack, enabling browser and Node.js API mocking without server infrastructure.
Implementation
New Package:
@objectstack/plugin-mswMSWPlugin- Runtime plugin implementing automatic handler generation for all ObjectStack endpointsObjectStackServer- Simplified mock API for common CRUD operationsExample Package:
@objectstack/example-msw-demoUsage
Browser Mode (standalone):
Runtime Integration:
Endpoints Mocked
/api/v1- Discovery/api/v1/meta[/:type[/:name]]- Metadata access/api/v1/data/:object[/:id]- CRUD operations (GET, POST, PATCH, DELETE)/api/v1/ui/view/:object- UI protocolOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.