feat(server-functions): add rawHandler for streaming file uploads#5708
feat(server-functions): add rawHandler for streaming file uploads#5708gzaripov wants to merge 1 commit intoTanStack:mainfrom
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.
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.