Request & Response
Learn how to handle HTTP requests and responses in MoroJS with type safety, automatic parsing, and flexible response formatting.
Request Handling
Request Context
typescript
1app.get('/example', ({ request, headers, params, query, body, context }) => {
2 // request: Full Request object
3 console.log(request.method); // GET
4 console.log(request.url); // /example?foo=bar
5
6 // headers: Typed headers object
7 console.log(headers['content-type']);
8 console.log(headers.authorization);
9
10 // params: Route parameters (typed)
11 console.log(params.id); // From /users/:id
12
13 // query: Query string parameters
14 console.log(query.search); // From ?search=value
15
16 // body: Parsed request body (validated if schema provided)
17 console.log(body.name);
18
19 // context: Middleware-populated context
20 console.log(context.user); // From auth middleware
21
22 return { success: true };
23});
Request Body Parsing
typescript
1// JSON body parsing (automatic)
2app.post('/users', {
3 body: z.object({
4 name: z.string(),
5 email: z.string().email()
6 }),
7 handler: ({ body }) => {
8 // body is automatically parsed and validated
9 return { user: body };
10 }
11});
12
13// Form data parsing
14app.post('/upload', {
15 body: z.object({
16 file: z.instanceof(File),
17 description: z.string().optional()
18 }),
19 handler: ({ body }) => {
20 // Handle file upload
21 return { filename: body.file.name };
22 }
23});
24
25// Raw body access
26app.post('/webhook', ({ request }) => {
27 const rawBody = await request.text();
28 const signature = request.headers.get('x-signature');
29
30 // Verify webhook signature
31 if (!verifySignature(rawBody, signature)) {
32 throw new Error('Invalid signature');
33 }
34
35 return { received: true };
36});
Response Handling
Response Formats
typescript
1// Simple JSON response
2app.get('/users', () => {
3 return { users: [] }; // Automatically serialized to JSON
4});
5
6// Custom status code
7app.post('/users', ({ body }) => {
8 const user = createUser(body);
9 return {
10 status: 201,
11 body: { user }
12 };
13});
14
15// Custom headers
16app.get('/download/:file', ({ params }) => {
17 const file = getFile(params.file);
18 return {
19 status: 200,
20 headers: {
21 'Content-Type': 'application/octet-stream',
22 'Content-Disposition': `attachment; filename="${file.name}"`
23 },
24 body: file.content
25 };
26});
27
28// Redirect response
29app.get('/old-endpoint', () => {
30 return {
31 status: 301,
32 headers: {
33 'Location': '/new-endpoint'
34 }
35 };
36});
Streaming Responses
typescript
1// Server-sent events
2app.get('/events', () => {
3 return new Response(
4 new ReadableStream({
5 start(controller) {
6 const interval = setInterval(() => {
7 const data = `data: ${JSON.stringify({ timestamp: Date.now() })}\n\n`;
8 controller.enqueue(new TextEncoder().encode(data));
9 }, 1000);
10
11 // Cleanup after 30 seconds
12 setTimeout(() => {
13 clearInterval(interval);
14 controller.close();
15 }, 30000);
16 }
17 }),
18 {
19 headers: {
20 'Content-Type': 'text/event-stream',
21 'Cache-Control': 'no-cache',
22 'Connection': 'keep-alive'
23 }
24 }
25 );
26});
27
28// File streaming
29app.get('/stream/:file', ({ params }) => {
30 const fileStream = createReadStream(params.file);
31 return new Response(fileStream, {
32 headers: {
33 'Content-Type': 'application/octet-stream'
34 }
35 });
36});
Error Response Patterns
Standard Error Responses
typescript
1app.get('/users/:id', {
2 params: z.object({ id: z.string().uuid() }),
3 handler: async ({ params }) => {
4 const user = await getUserById(params.id);
5
6 if (!user) {
7 return {
8 status: 404,
9 body: {
10 error: 'USER_NOT_FOUND',
11 message: 'User not found',
12 code: 'E001'
13 }
14 };
15 }
16
17 return { user };
18 }
19});
20
21// Global error handling
22app.use(async (context, next) => {
23 try {
24 await next();
25 } catch (error) {
26 if (error.name === 'ValidationError') {
27 return {
28 status: 400,
29 body: {
30 error: 'VALIDATION_ERROR',
31 message: error.message,
32 details: error.errors
33 }
34 };
35 }
36
37 if (error.name === 'UnauthorizedError') {
38 return {
39 status: 401,
40 body: {
41 error: 'UNAUTHORIZED',
42 message: 'Authentication required'
43 }
44 };
45 }
46
47 // Unknown error
48 return {
49 status: 500,
50 body: {
51 error: 'INTERNAL_SERVER_ERROR',
52 message: 'Something went wrong'
53 }
54 };
55 }
56});