-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
feat: typed +server.ts
responses with fetch
#11108
base: main
Are you sure you want to change the base?
Conversation
|
For typing request interface TypedRequest<T = any> {
json(): Promise<T>
}
interface TypedEvent<T = any> {
request: TypedRequest<T>
}
export async function GET({ request }: TypedEvent<{ foo: string }>) {
let { foo } = await request.json()
} Not sure if there's an easier way to do this, but it feels a lot more explicit than doing let { foo } = await request.json() as { foo: string } |
Hi, after considering both my proposal in #9938 and yours here my opinion is a little divided. I believe that SvelteKit's mission to make everything accessible to new users, simple to use and implicitly typed is very important. I liked the way my proposal handles things, because it was a change that everyone could benefit from without changing a single line of code. Though it turned out to be a pain to manage, with extremely complicated Types and trouble overall to represent all the possible fetch cases with one or two overloads. I also like your proposal which feels a lot natural and leads to code similar to tRPC without requiring a lot of code changes. My only worry is introducing a function like api_fetch which is basically identical to fetch in its behaviour, but exists with the sole purpose of enforcing types on request (body and path) and on the response. I really liked the simplicity of using the same fetch function for everything. In an ideal world I would choose the typed fetch function (my proposal), but from a user perspective of understanding errors and the types behind the function it is very complicated, and even more complicated is to maintain it in the future. Overall yours seems the most feasible one. How about redirect and goto functions? Should they be rewritten too in the same way? Maybe for fetch, redirect and goto we could provide the base function for non relative paths (ex. Https://...) While for root relative paths (/...) we could provide your api_fetch with the path parameters in the request by overloading the base fetch function. And the same goes for redirect and goto. |
Is this going to be accepted eventually? Can we not just roll the behaviour of the would be 'api-fetch' into the standard sveltekit fetch? It already has special behaviours (as when allowing local routes to autocomplete to the full route). |
Yes I believe it would be possible to roll the behavior into the standard sveltekit
Yes, I believe it would be possible to support this as well, to ensure that goto's and redirects are valid. Additionally this change should be backwards compatible, and it will still be possible to manually call the API routes with no typing/params provided in the API call With fetch, the pseudo algorithm could work similarly to this
It should be also possible to import the svelte custom fetch into the context of components too |
@Rich-Harris thoughts on this proposal? |
feels like this is would be the last major addition to make a sveltekit project fully typesafe all around, especially with the new typesafety in component markup with svelte 5.0 big fan of this 👍 |
I would like to add my support here, I am fan of this proposal over #9938, I think the extra complexity is worthwhile to get a more tRPC like experience. |
The typing in that becomes hell as the author mentioned because typescript doesn't have Regex types.
It just makes sense to use URLs that match the path templates of pages and then using a export async function load({ fetch }) {
const data = await fetch("/api/[post]", {
method: "GET",
params: { post: "123" }
});
return {
text: data.post_id // typed as a string
}
} would be functionally equivalent to this (minus the types) export async function load({ fetch }) {
const data = await fetch("/api/123", {
method: "GET"
});
return {
text: data.post_id // untyped
}
} |
Something like this should be possible to achieve via this approach, here I am using Zod library as an example for input validation
import { z } from "zod"
const api_inputs = z.object({
foo: z.string()
})
export async function POST(
{ request }: TypedEvent<z.infer<typeof api_inputs>>
) { // function return type inferred
const data = api_inputs.parse(await request.json()) // typed & validated input
return json({
baz: "bar"
}) // return type validated as TypedResponse<{ baz: "bar" }>
}
let res = await fetch("/api/xyz", {
method: "POST",
body: {
foo: "hello world"
} // this body would be type-checked
}) // TypedResponse<{ baz: "bar"}>
const data = await res.json() // typed as { baz: "bar" } |
In favor of making this the default behavior of |
+server.ts
responses with fetch
+server.ts
responses with fetch
@PuruVJ I'm not so sure that this is actually a breaking change. We would want to create a The |
Understand the team is likely very busy with Svelte 5 RC stuff, but would love to get this merged! Are there any further blockers? |
@hmnd yeah, very little is developed in terms of the actual PR, but I think there's a solid theoretical direction for where to go. Might need some help figuring out how we want to structure this in the code, and the right modules i'll need to modify to get this system implemented
|
Some additional benefits/advantages to this is that:
|
does this work in client side too like in event bindings? |
Could you elaborate? Edit If you mean like a |
yes. that's what i meant. nice. |
any updates on this ticket guys? |
Attempting to solve
+server.ts
types for API calling #11101+server.ts
types for API calling #11101Approach
/api/[post]/+server.ts
utils
+page.ts
+page.svelte
Theory
Using function overloading in typescript we can overload the
fetch
or custom fetch method with type info that gives us information about available APIs, return types and parameters.This system could also be extended to provide typed inputs for the
body
parameter infetch
as well as supporting typedgoto
sredirect
s and moreThe custom
fetch
provided in theload
functions and other places would more or less reflect the structure of the nativefetch
except with a few changes:params
RequestInit
properties are overrided to force things such asmethod: "GET"
as well as providing an additional parameter calledparams
example
Proof of concept example
I am posting this as a draft PR to gain feedback from the community and contributors.
Some unresolved matters:
App.Error
somewhere?)Related PRs