Routzie - documentation

How to Build a Frontend in Routzie

Introduction

Machine endpoints in Routzie can return any content type, making it easy to serve HTML, JSON, images, or other formats. You can define endpoints that accept both GET and POST requests, allowing you to build interactive forms and dynamic UIs with a single route function.

Content Types

  • To serve HTML, set the response header to Content-Type: text/html; charset=utf-8.
  • You can also return JSON, images, or other types by setting the appropriate content type.

Handling Forms

You can handle both displaying forms (GET) and processing submissions (POST) in the same route. Use FormData for file uploads and form fields. Store and retrieve values using your storage service.

Examples

1. Simple Value Rendering

route(['GET'], 'home', async function serveUi(source, req: ProcessedRequest) { const value = await storage.getValue('name') const html = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My form</title> </head> <body> <h1>Hello ${value}</h1> <form action="" method="post" enctype="multipart/form-data"> <label for="name">Name:</label> <input type="text" id="name" name="name" required /> <br /><br /> <input type="submit" value="Send"> </form> </body> </html> ` return new RouteResult(html, 200, { ['Content-Type']: 'text/html; charset=utf-8', }) })

2. Form with Image Upload

route(['GET', 'POST'], 'ui', async function(req: ProcessedRequest) { if (req.body instanceof FormData) { await storage.setValue('name', req.body.getValue('name')) const blob: BlobReference = req.body.getValue('image') as BlobReference if (!(blob instanceof BlobReference)) { return new RouteResult('Bad request', 400) } const previousBlob = await storage.getValue('image') if (previousBlob) { try { await removeBlob(machineContext, previousBlob) } catch(e) { console.log('Removing old blob failed', e) } } const newBlob = await copyBlobToContext(req.context, machineContext, blob as any) await storage.setValue('image', newBlob) } const value = await storage.getValue('name') const html = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My form</title> </head> <body> <h1>Hello ${value}</h1> <img src="${externalCallUrl}/image" /> <form action="" method="post" enctype="multipart/form-data"> <label for="name">Name:</label> <input type="text" id="name" name="name" required /> <br /><br /> <label for="image">Image:</label> <input type="file" id="image" name="image" required /> <br /><br /> <input type="submit" value="Send"> </form> </body> </html> ` return new RouteResult(html, 200, { ['Content-Type']: 'text/html; charset=utf-8', }) })

3. Returning JSON Data

route(['GET'], 'api-data', async function(req: ProcessedRequest) { const stats = await storage.getValue('stats') return new RouteResult(stats, 200, { ['Content-Type']: 'application/json', }) })

4. Serving an Image Directly

route(['GET'], 'image', async function(req: ProcessedRequest) { const imageBlob = await storage.getValue('image') if (!imageBlob) { return new RouteResult('Image not found', 404) } return new RouteResult(imageBlob, 200, { ['Content-Type']: 'image/png', }) })

Tips

  • Always set the correct Content-Type header for your response.
  • You can combine GET and POST in one route for forms.
  • Use FormData for file uploads and complex forms.
  • Store and retrieve user data using your storage service.
  • You can serve any frontend assets (HTML, CSS, JS, images) directly from your endpoints.

© 2025 Routzie Routzie.com