-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(server-functions): add rawHandler for streaming file uploads #5708
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Adds .rawHandler() method to createServerFn() that provides direct access to the raw Request object without automatic body parsing. This enables:
- Streaming large file uploads directly to cloud storage without buffering in memory
- Enforcing file size limits during upload rather than after
- Implementing custom body parsing with libraries like busboy
- Minimizing memory footprint for file operations
The raw handler receives { request, signal, context } where:
- request: Raw Request object with unread body stream
- signal: AbortSignal for cancellation support
- context: Full middleware context (auth, user info, etc.)
Closes TanStack#5704
WalkthroughThis PR adds Changes
Sequence DiagramsequenceDiagram
participant Client
participant ClientMiddleware as Client<br/>Middleware
participant Server
participant ServerMiddleware as Server<br/>Middleware
participant RawHandler as Raw<br/>Handler Fn
alt Normal Handler Path
Client->>ClientMiddleware: Execute client middleware
ClientMiddleware->>Server: Send parsed payload
Server->>Server: Parse FormData
Server->>ServerMiddleware: Execute server middleware
ServerMiddleware->>ClientMiddleware: Execute server middleware
ClientMiddleware->>Server: Call handler(ctx)
else Raw Handler Path (New)
Client->>ClientMiddleware: Execute client middleware
ClientMiddleware->>Server: Send raw request + signal
Server->>ServerMiddleware: Execute server middleware
ServerMiddleware->>RawHandler: Call rawHandler({request, signal, context})
RawHandler->>RawHandler: Stream/process raw body
RawHandler->>Server: Return Response
end
Server-->>Client: Return result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/start/framework/react/guide/server-functions.md (1)
330-330: Minor grammatical issue in sentence.The sentence "Return
Responseobjects binary data, or custom content types." is missing a word.Apply this diff to fix the grammar:
-Return `Response` objects binary data, or custom content types. +Return `Response` objects for binary data, or custom content types.
🧹 Nitpick comments (1)
packages/start-client-core/src/createServerFn.ts (1)
806-814: Fail fast when the Request is missingIf
getStartContextServerOnly()ever fails to hydrate aRequest(for example, somebody reuses the raw handler from a background job without a live HTTP request), we will handundefinedto userland and the very firstrequest.*access will explode with a cryptic “cannot read properties of undefined”. A defensive guard here gives a clear error and prevents downstream middleware from running in an invalid state.const ctxWithRequest = ctx as typeof ctx & { request: Request } + if (!ctxWithRequest.request) { + throw new Error( + 'createServerFn.rawHandler() requires a Request on the server context.', + ) + } result = await (options.serverFn as any)?.({ request: ctxWithRequest.request, signal: ctx.signal, context: ctx.context, })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
docs/start/framework/react/guide/server-functions.md(1 hunks)packages/start-client-core/src/createServerFn.ts(6 hunks)packages/start-plugin-core/src/create-server-fn-plugin/compiler.ts(1 hunks)packages/start-plugin-core/src/create-server-fn-plugin/handleCreateServerFn.ts(4 hunks)packages/start-plugin-core/src/create-server-fn-plugin/plugin.ts(1 hunks)packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts(1 hunks)packages/start-server-core/src/server-functions-handler.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (AGENTS.md)
Use internal docs links relative to the docs/ folder (e.g., ./guide/data-loading)
Files:
docs/start/framework/react/guide/server-functions.md
docs/{router,start}/**
📄 CodeRabbit inference engine (AGENTS.md)
Place router docs under docs/router/ and start framework docs under docs/start/
Files:
docs/start/framework/react/guide/server-functions.md
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript in strict mode with extensive type safety across the codebase
Files:
packages/start-plugin-core/tests/createServerFn/createServerFn.test.tspackages/start-plugin-core/src/create-server-fn-plugin/plugin.tspackages/start-plugin-core/src/create-server-fn-plugin/handleCreateServerFn.tspackages/start-server-core/src/server-functions-handler.tspackages/start-plugin-core/src/create-server-fn-plugin/compiler.tspackages/start-client-core/src/createServerFn.ts
packages/{*-start,start-*}/**
📄 CodeRabbit inference engine (AGENTS.md)
Name and place Start framework packages under packages/-start/ or packages/start-/
Files:
packages/start-plugin-core/tests/createServerFn/createServerFn.test.tspackages/start-plugin-core/src/create-server-fn-plugin/plugin.tspackages/start-plugin-core/src/create-server-fn-plugin/handleCreateServerFn.tspackages/start-server-core/src/server-functions-handler.tspackages/start-plugin-core/src/create-server-fn-plugin/compiler.tspackages/start-client-core/src/createServerFn.ts
🧬 Code graph analysis (2)
packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts (1)
packages/start-plugin-core/src/create-server-fn-plugin/compiler.ts (1)
compile(203-268)
packages/start-client-core/src/createServerFn.ts (3)
packages/start-client-core/src/index.tsx (5)
CompiledFetcherFn(60-60)Register(100-100)CompiledFetcherFnOptions(59-59)executeMiddleware(80-80)Fetcher(61-61)packages/start-client-core/src/getStartContextServerOnly.ts (1)
getStartContextServerOnly(4-4)packages/start-client-core/src/createMiddleware.ts (1)
AssignAllServerFnContext(325-343)
🔇 Additional comments (7)
packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts (2)
98-145: LGTM! Well-structured test for rawHandler with identifier function.The test correctly verifies that:
- Client compilation creates a wrapper delegating to
__executeServer- Server compilation preserves the original
myRawFuncand passes it as the second argument- POST method is used appropriately for the rawHandler use case
The test follows the established pattern and provides good coverage for the rawHandler feature.
147-196: LGTM! Comprehensive test for inline rawHandler.The test properly validates the inline function pattern for rawHandler, ensuring that:
- The inline async function is correctly compiled on both client and server
- The function signature
{ request, signal }is preserved- Server compilation passes the inline function as the second argument to rawHandler
This complements the identifier-based test and provides complete coverage for both usage patterns.
docs/start/framework/react/guide/server-functions.md (5)
130-142: LGTM! Clear introduction to rawHandler feature.The section introduction and use cases effectively communicate:
- When to use
.rawHandler()over.handler()- Key benefits: streaming, size enforcement, backpressure, memory efficiency
- Alignment with PR objectives for streaming file uploads
144-163: LGTM! Clear basic example.The basic raw handler example effectively demonstrates:
- Access to the raw
requestobject andsignal- Reading request headers and body
- Returning a
ResponseobjectThe example provides a good foundation before introducing more complex streaming scenarios.
165-198: LGTM! Comprehensive streaming example.The streaming file upload example effectively demonstrates:
- Middleware integration and context access (authentication, user info)
- Direct access to
request.bodystream- Size limit enforcement during upload
- Cancellation support via
signalThe
streamToStoragefunction serves as a clear placeholder demonstrating the streaming concept without cluttering the example with implementation details.
200-239: LGTM! Clear client usage and comparison.The client-side example and comparison table effectively:
- Demonstrate practical FormData usage with rawHandler
- Highlight key differences in body parsing, memory usage, and size limit enforcement
- Correctly document parameter signatures for both handler types
- Provide clear guidance on when to use each approach
240-246: LGTM! Important notes clearly document rawHandler behavior.The notes effectively communicate critical differences:
- No automatic parsing (manual handling required)
- Parameter structure:
{ request, context, signal }vs{ data, context, signal }- Middleware context availability (authentication, user info)
- Response return requirement
These notes help prevent common mistakes and clarify expectations.
|
would rather prefer the flag in createServerFn, however we first need to find out how to handle those raw request handlers when it comes to (global) server function middlewares |
Adds .rawHandler() method to createServerFn() that provides direct access to the raw Request object without automatic body parsing. This enables:
The raw handler receives { request, signal, context } where:
Closes #5704
Summary by CodeRabbit
New Features
rawHandler()method for server functions, enabling streaming file uploads and direct access to the raw Request object.Documentation
rawHandler()usage, streaming patterns, and comparison with standardhandler()approach.