Skip to content

Commit 32409e0

Browse files
committed
Update README.md to enhance clarity on ObjectStack integration and development workflow
1 parent 22e01d0 commit 32409e0

1 file changed

Lines changed: 124 additions & 192 deletions

File tree

examples/msw-react-crud/README.md

Lines changed: 124 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -1,239 +1,171 @@
1-
# MSW + React CRUD Example
1+
# MSW + React CRUD Example with ObjectStack
22

3-
This example demonstrates complete CRUD operations in a React application using **Mock Service Worker (MSW)** for API mocking and the **@objectstack/client** package for all data operations.
3+
This example demonstrates a **Frontend-First** development workflow using **ObjectStack**.
44

5-
## 🎯 Features
5+
It runs the entire **ObjectStack Runtime (Kernel)** directly in the browser using a Service Worker. This allows you to develop fully functional React applications with CRUD capabilities, validation, and API interactions **without running a backend server**.
66

7-
-**Complete CRUD Operations**: Create, Read, Update, Delete tasks
8-
-**ObjectStack Client Integration**: Uses official `@objectstack/client` for all API calls
9-
-**MSW API Mocking**: All API requests are intercepted and mocked in the browser
10-
-**React + TypeScript**: Modern React with full TypeScript support
11-
-**Vite**: Fast development server and build tool
12-
-**Best Practices**: Follows ObjectStack conventions and patterns
7+
## 🏗️ Architecture
138

14-
## 📁 Project Structure
9+
Instead of mocking individual HTTP endpoints manually, this project spins up a real ObjectStack instance inside the browser memory.
1510

11+
```mermaid
12+
graph TD
13+
Client[React App <br/> @objectstack/client] -->|REST API Calls| Network[Browser Network Layer]
14+
Network -->|Intercepted by| SW[Service Worker <br/> MockServiceWorker]
15+
SW -->|Delegates to| Kernel[ObjectStack Kernel <br/> (Running in Browser)]
16+
Kernel -->|Uses| MemoryDriver[In-Memory Driver]
17+
18+
Kernel -.->|Reads| Config[objectstack.config.ts <br/> Schema Definitions]
1619
```
17-
src/
18-
├── components/
19-
│ ├── TaskForm.tsx # Create/Update form component
20-
│ ├── TaskItem.tsx # Single task display component
21-
│ └── TaskList.tsx # Task list with read operations
22-
├── mocks/
23-
│ └── browser.ts # MSW handlers and mock database
24-
├── App.tsx # Main application component
25-
├── App.css # Application styles
26-
├── main.tsx # Entry point with MSW initialization
27-
└── types.ts # TypeScript type definitions
28-
```
29-
30-
## 🚀 Getting Started
31-
32-
### Prerequisites
33-
34-
- Node.js 18+
35-
- pnpm (package manager)
3620

37-
### Installation
38-
39-
```bash
40-
# Install dependencies
41-
pnpm install
21+
## 🎯 Key Features
4222

43-
# Initialize MSW service worker (required for browser mode)
44-
pnpm dlx msw init public/ --save
45-
```
23+
- **Zero-Backend Development**: Develop the entire frontend flow before the backend exists.
24+
- **Real Logic**: It's not just static JSON. The Kernel enforces schema validation, defaults, and even automation logic.
25+
- **Shared Schema**: The same `objectstack.config.ts` used here can be deployed to the real Node.js server later.
26+
- **Instant Feedback**: Changes to the schema are reflected immediately in the browser.
4627

47-
### Running the Application
28+
## 🛠️ Implementation Guide
4829

49-
```bash
50-
# Start development server
51-
pnpm dev
52-
```
30+
Here is how to implement this architecture in your own project.
5331

54-
The application will be available at `http://localhost:3000`
32+
### 1. Define Your Stack
5533

56-
### Building for Production
34+
Create an `objectstack.config.ts` to define your data models and application structure.
5735

58-
```bash
59-
# Build the application
60-
pnpm build
61-
62-
# Preview the production build
63-
pnpm preview
36+
```typescript
37+
// objectstack.config.ts
38+
import { defineStack } from '@objectstack/spec';
39+
40+
export const TaskObject = {
41+
name: 'task',
42+
label: 'Task',
43+
fields: {
44+
subject: { type: 'text', required: true },
45+
priority: { type: 'number', defaultValue: 1 },
46+
isCompleted: { type: 'boolean', defaultValue: false }
47+
}
48+
};
49+
50+
export default defineStack({
51+
objects: [TaskObject]
52+
});
6453
```
6554

66-
## 📖 How It Works
67-
68-
### 1. MSW Setup (`src/mocks/browser.ts`)
55+
### 2. Setup In-Browser Runtime
6956

70-
MSW intercepts HTTP requests in the browser and returns mock data:
57+
Create a mock setup file (e.g., `src/mocks/browser.ts`) that initializes the Kernel with the MSW plugin.
7158

7259
```typescript
73-
import { setupWorker } from 'msw/browser';
74-
import { http, HttpResponse } from 'msw';
75-
76-
// Define handlers matching ObjectStack API
77-
const handlers = [
78-
http.get('/api/v1/data/task', () => {
79-
return HttpResponse.json({ value: tasks, count: tasks.length });
80-
}),
60+
// src/mocks/browser.ts
61+
import { ObjectKernel, DriverPlugin, AppPlugin } from '@objectstack/runtime';
62+
import { ObjectQLPlugin } from '@objectstack/objectql';
63+
import { InMemoryDriver } from '@objectstack/driver-memory';
64+
import { MSWPlugin } from '@objectstack/plugin-msw';
65+
import myConfig from '../../objectstack.config'; // Your config
66+
67+
export async function startMockServer() {
68+
// 1. Initialize In-Memory Database
69+
const driver = new InMemoryDriver();
70+
71+
// 2. Create the Kernel
72+
const kernel = new ObjectKernel();
8173

82-
http.post('/api/v1/data/task', async ({ request }) => {
83-
const body = await request.json();
84-
const newTask = { id: generateId(), ...body };
85-
return HttpResponse.json(newTask, { status: 201 });
86-
}),
74+
kernel
75+
.use(new ObjectQLPlugin()) // Data Engine
76+
.use(new DriverPlugin(driver, 'memory')) // Database Driver
77+
.use(new AppPlugin(myConfig)) // Load your Schema
78+
.use(new MSWPlugin({ // Expose API via Service Worker
79+
enableBrowser: true,
80+
baseUrl: '/api/v1'
81+
}));
8782

88-
// ... more handlers
89-
];
90-
91-
export const worker = setupWorker(...handlers);
83+
// 3. Boot
84+
await kernel.bootstrap();
85+
86+
// 4. (Optional) Load Initial Data
87+
if (myConfig.manifest?.data) {
88+
// ... logic to seed data into driver ...
89+
}
90+
}
9291
```
9392

94-
### 2. ObjectStack Client Usage
93+
### 3. Initialize Worker on Startup
9594

96-
All components use the official `@objectstack/client` package:
95+
Update your entry file (`src/main.tsx`) to start the mock server before rendering the React app.
9796

98-
```typescript
99-
import { ObjectStackClient } from '@objectstack/client';
97+
```tsx
98+
// src/main.tsx
99+
import ReactDOM from 'react-dom/client';
100+
import { App } from './App';
101+
import { startMockServer } from './mocks/browser';
100102

101-
// Initialize client
102-
const client = new ObjectStackClient({ baseUrl: '/api/v1' });
103-
await client.connect();
104-
105-
// READ - Find all tasks
106-
const result = await client.data.find('task', {
107-
top: 100,
108-
sort: ['priority']
109-
});
103+
async function bootstrap() {
104+
// Wait for Service Worker to be ready
105+
await startMockServer();
110106

111-
// CREATE - Create new task
112-
const newTask = await client.data.create('task', {
113-
subject: 'New task',
114-
priority: 1
115-
});
116-
117-
// UPDATE - Update existing task
118-
await client.data.update('task', taskId, {
119-
isCompleted: true
120-
});
107+
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
108+
}
121109

122-
// DELETE - Delete task
123-
await client.data.delete('task', taskId);
110+
bootstrap();
124111
```
125112

126-
### 3. React Components
113+
### 4. Connect Client
127114

128-
**TaskList Component** (`src/components/TaskList.tsx`)
129-
- Fetches and displays all tasks
130-
- Demonstrates READ operations
131-
- Handles task deletion and status toggling
115+
In your React components, connect to the mock API (which mimics the real backend URL structure).
132116

133-
**TaskForm Component** (`src/components/TaskForm.tsx`)
134-
- Form for creating new tasks
135-
- Form for editing existing tasks
136-
- Demonstrates CREATE and UPDATE operations
137-
138-
**TaskItem Component** (`src/components/TaskItem.tsx`)
139-
- Displays individual task
140-
- Provides edit and delete actions
141-
- Shows task metadata (priority, completion status)
142-
143-
## 🔌 API Endpoints Mocked
144-
145-
The example mocks the following ObjectStack API endpoints:
146-
147-
| Method | Endpoint | Description |
148-
|--------|----------|-------------|
149-
| `GET` | `/api/v1` | Discovery endpoint |
150-
| `GET` | `/api/v1/meta/object/task` | Get task object metadata |
151-
| `GET` | `/api/v1/data/task` | Find/list all tasks |
152-
| `GET` | `/api/v1/data/task/:id` | Get single task by ID |
153-
| `POST` | `/api/v1/data/task` | Create new task |
154-
| `PATCH` | `/api/v1/data/task/:id` | Update existing task |
155-
| `DELETE` | `/api/v1/data/task/:id` | Delete task |
156-
157-
## 🎨 UI Features
158-
159-
- **Priority Indicators**: Color-coded priority levels (1-5)
160-
- **Completion Status**: Checkbox to mark tasks as complete
161-
- **Real-time Updates**: Automatic list refresh after CRUD operations
162-
- **Responsive Design**: Works on desktop and mobile devices
163-
- **Loading States**: Shows loading indicators during async operations
164-
- **Error Handling**: Displays error messages for failed operations
165-
166-
## 📚 Key Concepts
167-
168-
### MSW (Mock Service Worker)
169-
170-
MSW intercepts requests at the network level, making it ideal for:
171-
- Development without a backend
172-
- Testing components in isolation
173-
- Demos and prototypes
174-
- Offline development
175-
176-
### ObjectStack Client
177-
178-
The `@objectstack/client` provides a type-safe, consistent API for:
179-
- Auto-discovery of server capabilities
180-
- Metadata operations
181-
- Data CRUD operations
182-
- Query operations with filters, sorting, and pagination
183-
184-
### Best Practices Demonstrated
185-
186-
1. **Single Source of Truth**: All API calls go through ObjectStack Client
187-
2. **Type Safety**: Full TypeScript support with proper interfaces
188-
3. **Component Separation**: Clear separation between data fetching and presentation
189-
4. **Error Handling**: Proper error handling and user feedback
190-
5. **Loading States**: Visual feedback during async operations
191-
192-
## 🔧 Customization
117+
```tsx
118+
// src/App.tsx
119+
import { ObjectStackClient } from '@objectstack/client';
193120

194-
### Adding New Fields
121+
// The client thinks it's talking to a real server
122+
const client = new ObjectStackClient({
123+
baseUrl: '' // Relative path, intercepted by MSW at /api/v1/...
124+
});
195125

196-
1. Update the `Task` interface in `src/types.ts`
197-
2. Update mock handlers in `src/mocks/browser.ts`
198-
3. Update components to display/edit new fields
126+
await client.connect();
127+
const tasks = await client.data.find('task');
128+
```
199129

200-
### Changing Mock Data
130+
### 5. Vite Configuration
201131

202-
Edit the initial data in `src/mocks/browser.ts`:
132+
If you are using Vite, you may need to optimize dependencies to handle CommonJS packages correctly in the browser.
203133

204134
```typescript
205-
const mockTasks = new Map([
206-
['1', { id: '1', subject: 'Your task', priority: 1, ... }],
207-
// Add more tasks...
208-
]);
135+
// vite.config.ts
136+
export default defineConfig({
137+
optimizeDeps: {
138+
include: [
139+
'@objectstack/spec',
140+
'@objectstack/spec/data',
141+
'@objectstack/spec/system'
142+
]
143+
}
144+
});
209145
```
210146

211-
### Styling
212-
213-
All styles are in `src/App.css`. The design uses CSS custom properties (variables) for easy theming.
147+
## 🚀 Running the Example
214148

215-
## 📦 Dependencies
149+
```bash
150+
# Install dependencies
151+
pnpm install
216152

217-
- **@objectstack/client** - Official ObjectStack client SDK
218-
- **@objectstack/plugin-msw** - MSW integration for ObjectStack
219-
- **react** - UI library
220-
- **msw** - Mock Service Worker for API mocking
221-
- **vite** - Build tool and dev server
222-
- **typescript** - Type safety
153+
# Initialize MSW public script (only needed once)
154+
pnpm dlx msw init public/ --save
223155

224-
## 🤝 Related Examples
156+
# Start the dev server
157+
pnpm dev
158+
```
225159

226-
- [`/examples/msw-demo`](../../../msw-demo) - MSW plugin integration examples
227-
- [`/examples/todo`](../../../todo) - Todo app with ObjectStack Client
228-
- [`/examples/ui/react-renderer`](../react-renderer) - React metadata renderer
160+
Open `http://localhost:3000`. You can now create, edit, and delete tasks. The data persists in the browser memory as long as you don't refresh (simulate persistence by seeding data in step 2).
229161

230-
## 📖 Further Reading
162+
## 📦 Migration to Production
231163

232-
- [MSW Documentation](https://mswjs.io/)
233-
- [ObjectStack Client API](../../packages/client)
234-
- [ObjectStack Protocol Specification](../../packages/spec)
235-
- [React Documentation](https://react.dev/)
164+
When you are ready to go to production:
236165

237-
## 📝 License
166+
1. Keep `objectstack.config.ts`.
167+
2. Deploy the official ObjectStack Server (Node.js).
168+
3. Point your `ObjectStackClient` `baseUrl` to the real server.
169+
4. Remove the `startMockServer()` call in `main.tsx`.
238170

239-
Apache-2.0
171+
No frontend code needs to change!

0 commit comments

Comments
 (0)