-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Don't automatically throw from redirect
and error
#11404
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
Comments
If possible, I would completely remove the chance or need to throw something for control flow. There is a lot of literature that explains why exceptions are not ideal for control flow Throwing something makes it very difficult to use other libraries in our backend logic. You have to add boilerplate to throw at the edge of the logic, resulting in more code, a non-linear flow, and patterns that are not widely used (like throwing for control flow itself). My proposed solution is to have internal classes (like This would remove a lot of confusion about this pattern, use a well known approach by other frameworks, create reusable EDIT: seems that months ago this was the implementation and got changed. |
@FedericoBiccheddu As I understand it the anti-pattern is to abuse In this case (both in the current API and in my proposed fix) |
I have to agree with this being confusing. If anything "fail" sounds like a command but "error" is a value. But I would really not loose the types (I don't know how it would affect awesome superforms which we are using) I would prefer if we just used return for everything, and let |
You can achieve the same result with an early return. Using Exceptions are something you don't expect in your program/logic. Saying "I'm done, now framework will do the rest" is not an exception, is exactly what do you expect from it. |
@FedericoBiccheddu Let's agree to disagree. I think it's fine, as a practical matter, to throw the ball over the API boundary between my code (I'm not catching it) and SvelteKit (who is.) You don't. But for the sake of mutual understanding, let me ask a question. If we agree...
Then how would you structure the API for (I realize after writing the above that it looks like a trick question. It's not. If you have an answer, I'd be genuinely interested. If not, that's fine too.) |
I don't have time to address everything here, but I did want to chime in on the "throw vs. redirect" thing -- I used to be in the "Wow, I really wish we could just return these" camp. Unfortunately, the ergonomics of that solution in reality are just untenable. It seems "obvious" that this should work: export function load() {
return redirect('/foo');
} But what happens if you have this?: export const load = withAuthentication(() => {
// get stuff from the database, realize something failed
return error(400);
}) Now what? |
To answer the authentication scenario, another alternative is to bump authentication to I think the "'Wow, I really wish we could just return these' camp" is valid. Developers should be allowed to accomplish whatever goals they need. I believe Remix (which seems to have inspired SvelteKit, SolidStart, etc.) actually does this. You can return or throw regular It's really hard to predict every use case the developer needs to satisfy. Personally, I love Svelte. I think it's much better than React. But I like Remix more than SvelteKit because I find myself butting heads with SvelteKit too often to accomplish what I want when it comes to headers, response objects, and cookies. In Remix, I just say, "Use this That said, regardless of whether we're allowed to return |
This issue has turned somewhat philosophical. Totally my fault. I should have stuck to the facts in the original post, rather than succumbing to the temptation to air radical Jacobin opinions (or maybe retrograde ancien régime opinions, I dunno) about how the SvelteKit API should be. Reset: A function that always throws is bad DX, anyway you cut it. Roll this change back. |
I've run into an issue today with redirect form actions and setting headers. I thought form actions would work like post server endpoint and returning a response with redirect settings would redirect but no get an error because form actions only expects data to return and using set headers redirect doesn't keep headers. |
@JonathonRP It seems that the problem you're describing is related to a different issue. Is that correct? If so, do you still want to leave your comment here? Or migrate it? |
I wanted to share my example of the API of redirect being inconsistent and confusing, and how that can lead to problems. In endpoints return redirect can be achieved multiple ways but I was not expecting form actions on post to work different then post even when using use: enhance |
After migrating to SvelteKit 2, I get |
I can't replicate @DePasqualeOrg's eslint errors, but the example provided is instructive. Too often SvelteKit assumes that it is the be all and end all of the application, rather than a useful piece of an application with other important parts (for example, some database with a Prisma interface.) It bakes in decisions that would be better left to the developer. In this particular instance, SvelteKit has hidden the |
@cdcarson, to replicate the issue, just add |
@DePasqualeOrg Got it. I was using the SvelteKit default eslint, which I assumed had that rule, but maybe that's because I nearly always explicitly type function returns. This has more or less the same effect as the rule, complaining if there's a logical branch inside the function that doesn't return the sanctified type. More to the point, SvelteKit shouldn't add conventions that break cases like yours, especially on such apparently dubious grounds as those which led to this change. |
You can make it possible to return and throw. |
Describe the problem
I appreciate the thought & work that went into #11144 and #11165 but I think it's the wrong approach.
The confusion around
return
andthrow
arises from SvelteKit's original decision to stray from the common sense meanings of those words. I get there was a reason for this -- deriving action function return types, which can't be done if validation errors are thrown. But it led to a less than intuitive API...return fail(400, {bah: 'humbug'})
...ackthrow redirect(302, '/success')
...ack (it's a success, you should be able to return it)throw redirect(302, '/login')
...fair enoughthrow error(500)
...fair enoughHiding the
throw
in the redirect and error cases doesn't really fix the problem. It just kicks the can down the road.never
works in an IDE. But you won't see the "unreachable code" lint if you're looking at something in a GitHub issue.There's also a decent case to be made for...
Describe the proposed solution
Consider rolling it back.
Alternatives considered
Ideally, the error handling API should be re-written to be simpler and more intuitive. Stick to to the easy-to-understand paradigm of throwing
Error
and returning success, like so...Granted, this leaves out how to type
Action
return values, given that validation errors are thrown. I get that this typing is a feature, but I'm not convinced that it's super valuable in practice. The shape ofform
(and theenhance
result) on the client usually needs to narrowed anyway, between success and failure states, and between actions if a route has more than one. The generated types become cumbersome. It's just simpler to cheat...I suppose it's a matter of opinion whether generating action types is worth increasing the eccentricity and surface of the framework API. I'm fine either way. It's easy enough to wrap away the eccentricities.
Importance
nice to have
Additional Information
No response
The text was updated successfully, but these errors were encountered: