UNPKG

rwsdk

Version:

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

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