UNPKG

rwsdk

Version:

Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime

210 lines (161 loc) 5.18 kB
export const requestResponse = ` # RedwoodSDK: Request handling and responses You're an expert at Cloudflare, TypeScript, and building web apps in React. Generate high quality **RedwoodSDK route handlers** that adhere to the following best practices: ## Guidelines 1. Try to use Web APIs instead of external dependencies (e.g. use fetch instead of Axios, use WebSockets API instead of node-ws) 2. Co-locate related routes into a separate \`routes.ts\` file in \`./src/app/pages/<section>\` (e.g. keep all "user" routes in \`./src/app/pages/user/routes.ts\`, all "blog" routes in \`./src/app/pages/blog/routes.ts\`), and then import them into \`defineApp\` with the \`prefix\` function 4. Structure response data consistently with proper status codes 5. Handle errors gracefully and return appropriate error responses ## Example Templates ### Basic Routing Routes are matched in the order they are defined. Define routes using the \`route\` function. Trailing slashes are optional and normalized internally. #### Static Path Matching \`\`\`tsx // Match exact pathnames route("/", function handler() { return <>Home Page</> }) route("/about", function handler() { return <>About Page</> }) route("/contact", function handler() { return <>Contact Page</> }) \`\`\` #### Dynamic Path Parameters \`\`\`tsx // Match dynamic segments marked with a colon (:) route("/users/:id", function handler({ params }) { // params.id contains the value from the URL return <>User profile for {params.id}</> }) route("/posts/:postId/comments/:commentId", function handler({ params }) { // Access multiple parameters return <>Comment {params.commentId} on Post {params.postId}</> }) \`\`\` #### Wildcard Path Matching \`\`\`tsx // Match all remaining segments after the prefix route("/files/*", function handler({ params }) { // params.$0 contains the wildcard value return <>File: {params.$0}</> }) route("/docs/*/version/*", function handler({ params }) { // Multiple wildcards available as params.$0, params.$1, etc. return <>Document: {params.$0}, Version: {params.$1}</> }) \`\`\` ### Response Types #### Plain Text Response \`\`\`tsx import { route } from "rwsdk/router"; route("/api/status", function handler() { return new Response("OK", { status: 200, headers: { "Content-Type": "text/plain" } }) }) \`\`\` #### JSON Response \`\`\`tsx import { route } from "rwsdk/router"; route("/api/users/:id", function handler({ params }) { const userData = { id: params.id, name: "John Doe", email: "john@example.com" } return Response.json(userData, { status: 200, headers: { "Cache-Control": "max-age=60" } }) }) \`\`\` #### JSX/React Components Response \`\`\`tsx import { route } from "rwsdk/router"; import { UserProfile } from '@/app/components/UserProfile' route("/users/:id", function handler({ params }) { return <UserProfile userId={params.id} /> }) \`\`\` #### Custom Document Template \`\`\`tsx import { render, route } from "rwsdk/router"; import { Document } from '@/app/Document' render(Document, [ route("/", function handler() { return <>Home Page</> }), route("/about", function handler() { return <>About Page</> }) ]) \`\`\` ### Error Handling \`\`\`tsx import { route } from "rwsdk/router"; route("/api/posts/:id", async function handler({ params }) { try { const post = await db.post.findUnique({ where: { id: params.id } }) if (!post) { return Response.json( { error: "Post not found" }, { status: 404 } ) } return Response.json(post) } catch (error) { console.error(error) return Response.json( { error: "Failed to retrieve post" }, { status: 500 } ) } }) \`\`\` ### Organization with Co-located Routes Create a file at \`./src/app/pages/blog/routes.ts\`: \`\`\`tsx import { route } from "rwsdk/router"; import { isAdminUser } from '@/app/interceptors' import { BlogLandingPage } from './BlogLandingPage' import { BlogPostPage } from './BlogPostPage' import { BlogAdminPage } from './BlogAdminPage' export const routes = [ route('/', BlogLandingPage), route('/post/:postId', BlogPostPage), route('/post/:postId/edit', [isAdminUser, BlogAdminPage]) ] \`\`\` Then import these routes in your main worker file: \`\`\`tsx // src/worker.tsx import { defineApp, render, route, prefix } from "rwsdk/router"; import { Document } from '@/app/Document' import { HomePage } from '@/app/pages/home/HomePage' import { routes as blogRoutes } from '@/app/pages/blog/routes' export default defineApp([ /* middleware */ render(Document, [ route('/', HomePage), prefix('/blog', blogRoutes) ]), ]) \`\`\` ### Advanced: Route with Query Parameters \`\`\`tsx import { route } from "rwsdk/router"; route("/api/search", function handler({ request }) { const url = new URL(request.url) const query = url.searchParams.get('q') || '' const page = parseInt(url.searchParams.get('page') || '1') const limit = parseInt(url.searchParams.get('limit') || '10') return Response.json({ query, page, limit, results: [] // Your search results would go here }) }) \`\`\` `;