Breaking: use Request and Response objects in endpoints and hooks#3384
Breaking: use Request and Response objects in endpoints and hooks#3384Rich-Harris merged 41 commits intomasterfrom
Request and Response objects in endpoints and hooks#3384Conversation
🦋 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. |
|
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). |
|
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
RequestandResponseobjects nativelyHow to update your app
Hooks (
handle,handleErrorandgetSession) and endpoints previously received a proprietaryRequestobject:Instead, they now receive a
RequestEvent:methodandheadersare no longer necessary as they exist on therequestobject. (urlis still provided, since theURLobject contains conveniences likeurl.searchParams.get('foo'), whereasrequest.urlis a string.)Updating hooks
The
resolvefunction passed tohandlenow returns aPromise<Response>;handlemust do likewise.A rewritten
handlehook 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
transformPageoption or something to satisfy that use case in a more streamlined way.)Updating endpoints
Similarly, handlers receive a
RequestEvent. MostGEThandlers will be unchanged, but any handler that needs to read the request body will need to update:Handlers do not need to return a
Responseobject, but they can. Specifically, theheadersproperty can be any form that can be passed to theHeadersconstructor......which means that since a
Responseobject has a compliantstatus,headersandbody, you can do this sort of thing:Updating svelte.config.js
If you're using the
headers,hostorprotocolconfig options, you should remove them. Most adapters will automatically set the correct URL without the help of these options; in other cases likeadapter-nodethe options have been moved into the adapter options.How to update your custom adapter
The interface for adapters has changed as well — the
app.renderfunction now takes aRequestand 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
Requestand handle theResponseyourself — consult theadapter-nodeandadapter-netlifyexamples: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-nodedoes, following the removal of theheaders/host/protocolconfig 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.rendersignature, which adapters will need to accommodateapp.rendershould accept aRequestas inputapp.rendershould return aResponseHeadersobject (enables one-linefetchproxying)RequestandResponseand node req/resReadableStreamobject is supported everywhere —node-fetchuses 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:
ReadableStreamto 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 testand lint the project withpnpm lintandpnpm checkChangesets
pnpx changesetand following the prompts. All changesets should bepatchuntil SvelteKit 1.0