-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Breaking: use Request
and Response
objects in endpoints and hooks
#3384
Conversation
🦋 Changeset detectedLatest commit: 7a5a03a The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
✔️ Deploy Preview for kit-demo canceled. 🔨 Explore the source changes: 7a5a03a 🔍 Inspect the deploy log: https://app.netlify.com/sites/kit-demo/deploys/61e86ce8ece61400079c3eed |
A realisation: if the signature of Netlify provides a So of the officially supported adapters, the only one that can actually make use of the The conclusion is that we should remove |
Another realisation: since request bodies can only be consumed once, and since there are valid reasons to need to control how it's consumed (#831, #70 (comment)), we can't realistically parse the body before calling handlers. And the endpoint-level config idea (#70 (comment)) is a non-starter unfortunately, since we would need to parse the body before identifying which endpoint(s) matched the request. So I've changed my mind a bit about the API — I think we need to expose the underlying -export async function post({ url, method, headers, rawBody, body, params, locals }) {
+export async function post({ request, url, params, locals }) {
+ const body = await request.json();
// ...
} (Since And this would in fact enable file uploads, albeit in a suboptimal way: export async function post({ request }) {
const data = await request.formData();
await send_to_s3(data.get('video'));
// ...
} For handling large files this isn't ideal, since it buffers all the data in memory. Essentially what we'd eventually need is a way to handle uploads in streaming fashion — Remix has parseMultiPartFormData which is close to what I'm imagining, except that it appears to be Node-only. Something like this: import { multipart } from '$app/somewhere';
export async function post({ request }) {
for await (const { name, value } of multipart(request)) {
if (name === 'video') {
await send_to_s3(value.name, value.type, value.stream());
}
}
// ...
} Happily, that doesn't need to be part of this PR. |
A PR in SvelteKit introduces a number of breaking changes that lay the foundation for streaming request/response bodies enable multipart form handling (including file uploads) better align SvelteKit with modern platforms that deal with `Request` and `Response` objects natively Hooks (`handle`, `handleError` and `getSession`) and endpoints previously received a proprietary `Request` object: ```ts interface Request<Locals = Record<string, any>, Body = unknown> { url: URL; method: string; headers: RequestHeaders; rawBody: RawBody; params: Record<string, string>; body: ParameterizedBody<Body>; locals: Locals; } ``` Instead, they now receive a `RequestEvent`: ```ts export interface RequestEvent<Locals = Record<string, any>> { request: Request; // https://developer.mozilla.org/en-US/docs/Web/API/Request url: URL; // https://developer.mozilla.org/en-US/docs/Web/API/URL params: Record<string, string>; locals: Locals; } ``` `method` and `headers` are no longer necessary as they exist on the `request` object. (`url` is still provided, since the `URL` object contains conveniences like `url.searchParams.get('foo')`, whereas `request.url` is a string.) To access the request body use the text/json/arrayBuffer/formData methods, e.g. `body = await request.json()`. See sveltejs/kit#3384 for details
So, is it possible to get the rawBody data now? I'm using Stripe's API and need the raw request body from an endpoint's post function. Help! |
I was lead here by a svelte error when trying to update packages of https://github.com/timsonner/sveltekit-system-call |
I'm also struggling to figure out how to get the |
I'm not sure about mux.com but I was able to get the rawBody for Stripe's checkout webhook with this:
|
Thanks @KTruong008, this is how I fixed my code (you may find using export async function post({ request }) {
const rawBody = await request.buffer();
const body = JSON.parse(rawBody.toString());
const signature = request.headers.get('mux-signature') || '';
const eventData = body.data;
let isValidSignature = false;
try {
isValidSignature = Webhooks.verifyHeader(
rawBody,
signature,
MUX_WEBHOOK_SECRET
); |
@benwoodward — You can also get the raw body from |
I need help finding right replacement. Original import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ request, resolve }) => {
if (request.url.searchParams.has('_method')) {
request.method = request.url.searchParams.get('_method').toUpperCase();
}
const response = await resolve(request);
return response;
}; => So I changed import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
if (event.url.searchParams.has('_method')) {
event.request.method = event.url.searchParams.get('_method').toUpperCase();
}
const response = await resolve(event);
return response;
}; But it is not working giving this error
Would you please tell me how to fix the problem? |
@hyunduk0206 I recommend asking this kind of question on StackOverflow or the svelte discord. However, I would just console.log out the values to see what's contained within the parameters. |
@benwoodward Thank you for your reply. I will not ask this kind of question here, except for this question. I have tried to print the values, but I couldn't due to error. But I can write down the part of code that is related to the value. import type { Request } from '@sveltejs/kit';
import PrismaClient from '$lib/prisma';
const prisma = new PrismaClient();
export const api = async (request: Request, data?: Record<string, unknown>) => {
let status = 500;
let body = {};
switch (request.method.toUpperCase()) {
case 'GET':
status = 200;
body = await prisma.todo.findMany();
break;
case 'POST':
status = 201;
body = await prisma.todo.create({
data: {
created_at: data.created_at as Date,
done: data.done as boolean,
text: data.text as string
}
});
break;
case 'DELETE':
status = 200;
body = await prisma.todo.delete({
where: {
uid: request.params.uid
}
});
break;
case 'PATCH':
status = 200;
body = await prisma.todo.update({
where: {
uid: request.params.uid
},
data: {
done: data.done,
text: data.text
}
});
break;
default:
break;
}
if (request.method.toUpperCase() !== 'GET' && request.headers.accept !== 'application/json') {
return {
status: 303,
headers: {
location: '/'
}
};
}
return {
status,
body
};
}; |
I solved my problem by following the offical doc (https://kit.svelte.dev/docs/routing#endpoints-http-method-overrides). |
There were a few breaking changes to work through (unsprisingly, we jumped about 100 versions here!), namely the new objects being passed to the hook functions (sveltejs/kit#3384).
Adding the info of how to read request body data to kit.svelte.com would be quite useful, it took me over a day to find this thread. |
https://kit.svelte.dev/docs/web-standards#fetch-apis-request ? Could be in a clearer place alongside |
Yes, my app only has I found the answer from this thread, Svelte gave the link as a console error, but all the attempts with |
I’m currently getting “Invalid Request Body” when deployed and uploading a file using a Named Action through a form. Any ideas why? |
Hey does this solution still work for you? I'm having issues with the arraybuffer. It seems that you can get the body via |
This PR introduces a number of breaking changes that
Request
andResponse
objects nativelyHow to update your app
Hooks (
handle
,handleError
andgetSession
) and endpoints previously received a proprietaryRequest
object:Instead, they now receive a
RequestEvent
:method
andheaders
are no longer necessary as they exist on therequest
object. (url
is still provided, since theURL
object contains conveniences likeurl.searchParams.get('foo')
, whereasrequest.url
is a string.)Updating hooks
The
resolve
function passed tohandle
now returns aPromise<Response>
;handle
must do likewise.A rewritten
handle
hook might look like this:(This example illustrates the new APIs but also demonstrates a way in which rewriting HTML is now less efficient; we may need to add a
transformPage
option or something to satisfy that use case in a more streamlined way.)Updating endpoints
Similarly, handlers receive a
RequestEvent
. MostGET
handlers will be unchanged, but any handler that needs to read the request body will need to update:Handlers do not need to return a
Response
object, but they can. Specifically, theheaders
property can be any form that can be passed to theHeaders
constructor......which means that since a
Response
object has a compliantstatus
,headers
andbody
, you can do this sort of thing:Updating svelte.config.js
If you're using the
headers
,host
orprotocol
config options, you should remove them. Most adapters will automatically set the correct URL without the help of these options; in other cases likeadapter-node
the options have been moved into the adapter options.How to update your custom adapter
The interface for adapters has changed as well — the
app.render
function now takes aRequest
and returns aPromise<Response>
.On platforms that use these objects natively (like Cloudflare Workers and Deno) this means you can delete some code. On Lambda-like and Node-like platforms you must create the
Request
and handle theResponse
yourself — consult theadapter-node
andadapter-netlify
examples:kit/packages/adapter-node/src/handler.js
Lines 37 to 49 in 84f6136
kit/packages/adapter-netlify/src/handler.js
Lines 17 to 23 in 84f6136
(Note that your adapter may need to expose options to configure the base URL (or protocol/host header) like
adapter-node
does, following the removal of theheaders
/host
/protocol
config options.)What's next
After these API changes are in place, we can implement support for streaming request/response bodies, which will enable handling of large files and so on (at least on platforms that support streaming, i.e. not Lambda).
Original PR comment
Breaking change — changes the
app.render
signature, which adapters will need to accommodateapp.render
should accept aRequest
as inputapp.render
should return aResponse
Headers
object (enables one-linefetch
proxying)Request
andResponse
and node req/resReadableStream
object is supported everywhere —node-fetch
uses node streams under the hood instead of web streams)This doesn't yet tackle file uploads (#70), that can happen in a follow-up I think. It also doesn't mean that Svelte components somehow support streaming, this is purely about simplifying the API and enabling streamed endpoint request/response bodies
Follow-ups:
ReadableStream
to enable streamed responses in a cross-platform wayPlease don't delete this checklist! Before submitting the PR, please make sure you do the following:
Tests
pnpm test
and lint the project withpnpm lint
andpnpm check
Changesets
pnpx changeset
and following the prompts. All changesets should bepatch
until SvelteKit 1.0