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-Type: text/html; charset=utf-8
.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.
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', }) })
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', }) })
route(['GET'], 'api-data', async function(req: ProcessedRequest) { const stats = await storage.getValue('stats') return new RouteResult(stats, 200, { ['Content-Type']: 'application/json', }) })
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', }) })
Content-Type
header for your response.FormData
for file uploads and complex forms.© 2025 Routzie Routzie.com