Skip to content

Commit a1f7dcc

Browse files
Copilothotlong
andcommitted
WIP: Simplify MSW integration with config-based approach
- Create objectstack.config.ts for declarative data model - Add helper function to auto-generate MSW handlers from runtime - Remove plugin-msw dependency (browser incompatibility) - Update package.json and vite.config - Note: Vite workspace resolution issue with dynamic imports needs fix Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 745ac10 commit a1f7dcc

File tree

4 files changed

+155
-32
lines changed

4 files changed

+155
-32
lines changed

examples/ui/msw-react-crud/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@objectstack/client": "workspace:*",
14-
"@objectstack/plugin-msw": "workspace:*",
14+
"@objectstack/driver-memory": "workspace:*",
1515
"@objectstack/runtime": "workspace:*",
1616
"@objectstack/spec": "workspace:*",
1717
"react": "^18.3.1",

examples/ui/msw-react-crud/src/mocks/browser.ts

Lines changed: 149 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,170 @@
11
/**
22
* MSW Browser Worker Setup
33
*
4-
* Simplified setup using ObjectStack plugin-msw.
5-
* All API endpoints are automatically mocked based on objectstack.config.ts
4+
* Simplified setup using auto-generated handlers from objectstack.config.ts
5+
* All API endpoints are automatically mocked based on your data model
66
*/
77

8+
import { setupWorker } from 'msw/browser';
9+
import { http, HttpResponse } from 'msw';
810
import { ObjectStackKernel } from '@objectstack/runtime';
9-
import { MSWPlugin } from '@objectstack/plugin-msw';
11+
import { ObjectStackRuntimeProtocol } from '@objectstack/runtime';
1012
import appConfig from '../../objectstack.config';
1113

1214
let runtime: ObjectStackKernel | null = null;
13-
let mswPlugin: MSWPlugin | null = null;
15+
let protocol: ObjectStackRuntimeProtocol | null = null;
1416

1517
/**
16-
* Initialize and start the ObjectStack runtime with MSW plugin
18+
* Initialize the ObjectStack runtime with your app configuration
19+
*/
20+
async function initializeRuntime() {
21+
runtime = new ObjectStackKernel([appConfig]);
22+
await runtime.start();
23+
protocol = new ObjectStackRuntimeProtocol(runtime);
24+
console.log('[MSW] ObjectStack runtime initialized');
25+
}
26+
27+
/**
28+
* Generate MSW handlers automatically from the runtime protocol
29+
*/
30+
function createHandlers(baseUrl: string = '/api/v1') {
31+
if (!protocol) {
32+
throw new Error('Runtime not initialized. Call initializeRuntime() first.');
33+
}
34+
35+
return [
36+
// Discovery endpoint
37+
http.get(`${baseUrl}`, () => {
38+
return HttpResponse.json(protocol!.getDiscovery());
39+
}),
40+
41+
// Meta endpoints
42+
http.get(`${baseUrl}/meta`, () => {
43+
return HttpResponse.json(protocol!.getMetaTypes());
44+
}),
45+
46+
http.get(`${baseUrl}/meta/:type`, ({ params }) => {
47+
return HttpResponse.json(protocol!.getMetaItems(params.type as string));
48+
}),
49+
50+
http.get(`${baseUrl}/meta/:type/:name`, ({ params }) => {
51+
try {
52+
return HttpResponse.json(
53+
protocol!.getMetaItem(params.type as string, params.name as string)
54+
);
55+
} catch (error) {
56+
const message = error instanceof Error ? error.message : 'Unknown error';
57+
return HttpResponse.json({ error: message }, { status: 404 });
58+
}
59+
}),
60+
61+
// Data endpoints
62+
http.get(`${baseUrl}/data/:object`, async ({ params, request }) => {
63+
try {
64+
const url = new URL(request.url);
65+
const queryParams: Record<string, any> = {};
66+
url.searchParams.forEach((value, key) => {
67+
queryParams[key] = value;
68+
});
69+
70+
const result = await protocol!.findData(params.object as string, queryParams);
71+
return HttpResponse.json(result);
72+
} catch (error) {
73+
const message = error instanceof Error ? error.message : 'Unknown error';
74+
return HttpResponse.json({ error: message }, { status: 404 });
75+
}
76+
}),
77+
78+
http.get(`${baseUrl}/data/:object/:id`, async ({ params }) => {
79+
try {
80+
const result = await protocol!.getData(
81+
params.object as string,
82+
params.id as string
83+
);
84+
return HttpResponse.json(result);
85+
} catch (error) {
86+
const message = error instanceof Error ? error.message : 'Unknown error';
87+
return HttpResponse.json({ error: message }, { status: 404 });
88+
}
89+
}),
90+
91+
http.post(`${baseUrl}/data/:object`, async ({ params, request }) => {
92+
try {
93+
const body = await request.json();
94+
const result = await protocol!.createData(params.object as string, body);
95+
return HttpResponse.json(result, { status: 201 });
96+
} catch (error) {
97+
const message = error instanceof Error ? error.message : 'Unknown error';
98+
return HttpResponse.json({ error: message }, { status: 400 });
99+
}
100+
}),
101+
102+
http.patch(`${baseUrl}/data/:object/:id`, async ({ params, request }) => {
103+
try {
104+
const body = await request.json();
105+
const result = await protocol!.updateData(
106+
params.object as string,
107+
params.id as string,
108+
body
109+
);
110+
return HttpResponse.json(result);
111+
} catch (error) {
112+
const message = error instanceof Error ? error.message : 'Unknown error';
113+
return HttpResponse.json({ error: message }, { status: 400 });
114+
}
115+
}),
116+
117+
http.delete(`${baseUrl}/data/:object/:id`, async ({ params }) => {
118+
try {
119+
const result = await protocol!.deleteData(
120+
params.object as string,
121+
params.id as string
122+
);
123+
return HttpResponse.json(result);
124+
} catch (error) {
125+
const message = error instanceof Error ? error.message : 'Unknown error';
126+
return HttpResponse.json({ error: message }, { status: 400 });
127+
}
128+
}),
129+
130+
// UI Protocol endpoint
131+
http.get(`${baseUrl}/ui/view/:object`, ({ params, request }) => {
132+
try {
133+
const url = new URL(request.url);
134+
const viewType = url.searchParams.get('type') || 'list';
135+
const view = protocol!.getUiView(params.object as string, viewType as 'list' | 'form');
136+
return HttpResponse.json(view);
137+
} catch (error) {
138+
const message = error instanceof Error ? error.message : 'Unknown error';
139+
return HttpResponse.json({ error: message }, { status: 404 });
140+
}
141+
}),
142+
];
143+
}
144+
145+
/**
146+
* Start the MSW worker with auto-generated handlers
17147
*
18148
* This function:
19-
* 1. Creates an ObjectStack runtime with your app configuration
20-
* 2. Installs the MSW plugin to automatically mock all API endpoints
21-
* 3. Starts the runtime (which initializes data and starts MSW)
149+
* 1. Initializes the ObjectStack runtime with your app config
150+
* 2. Generates MSW handlers automatically
151+
* 3. Starts the MSW worker
22152
*/
23153
export async function startMockServer() {
24-
// Create MSW Plugin
25-
mswPlugin = new MSWPlugin({
26-
enableBrowser: true,
27-
baseUrl: '/api/v1',
28-
logRequests: true
29-
});
154+
// Initialize runtime
155+
await initializeRuntime();
30156

31-
// Create runtime with app config and MSW plugin
32-
runtime = new ObjectStackKernel([
33-
appConfig, // Your app configuration with objects and seed data
34-
mswPlugin // MSW plugin to auto-mock all endpoints
35-
]);
157+
// Create handlers from runtime protocol
158+
const handlers = createHandlers('/api/v1');
36159

37-
// Start the runtime (this will initialize everything)
38-
await runtime.start();
160+
// Start MSW worker
161+
const worker = setupWorker(...handlers);
162+
await worker.start({
163+
onUnhandledRequest: 'bypass',
164+
});
39165

40-
console.log('[MSW] ObjectStack runtime started with auto-mocked API endpoints');
166+
console.log('[MSW] Auto-mocked API ready! All endpoints generated from objectstack.config.ts');
167+
return worker;
41168
}
42169

43170
/**
@@ -46,10 +173,3 @@ export async function startMockServer() {
46173
export function getRuntime() {
47174
return runtime;
48175
}
49-
50-
/**
51-
* Get the MSW worker (useful for advanced use cases)
52-
*/
53-
export function getWorker() {
54-
return mswPlugin?.getWorker();
55-
}

examples/ui/msw-react-crud/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ export default defineConfig({
77
server: {
88
port: 3000,
99
},
10+
optimizeDeps: {
11+
include: ['msw', 'msw/browser']
12+
}
1013
});

pnpm-lock.yaml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)