-
-
Notifications
You must be signed in to change notification settings - Fork 35
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(servervalidationerror): adds a ServerValidationError #52
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Hi @theboxer, thanks for your contribution. I think this is very useful and the optimal way to deal with custom validation errors set in server code execution. Though, I already implemented this pattern in all of my projects via the "native" way, which is using the validation library to do the job. I closed an issue yesterday about the same problem, check out the comment I left there. I think this approach is pretty good already, but please let me know what you think about it. Thanks! |
@TheEdoRan thanks for that example, I actually think that it make perfect sense to deal with the validation errors as natively as possible. I actually didn't think about the option to add new set of validation to the same schema server side and perform the db validation on this level. I will update my code to use this approach :) However, not every project I run uses local data access and will be able to leverage the native schema. When I interact with the data through a remote crud API, it's impossible to do the check beforehand in the schema. I think this instance would be ideal for the proposed solution in this PR. What do you think? |
You can interact with external APIs in I think your solution is great if the native way cannot be used. However, I also think that:
export const registerUser = action(schema, async (input, ctx, { serverValidationError }) => {
...
});
export const registerUser = action(schema, async (input, { serverValidationError, ctx }) => {
...
}); I still have to decide what the best approach is. First one could be included in version 6, since it only adds a feature and breaks nothing, second one with the breaking change would be included in version 7. Also, I think it's probably better to be a little more explicit and name this function something like Please let me know what you think about this, and thank you for the patience. |
Even if this would be possible, I don't think it would be a good approach to do so, schema should be purely responsible for data validation and not calling API (by this I mean regular CUD endpoints, not specific endpoints for validation) and returning API's data as a side effect
I don't think this is a good idea. It would force you to send unvalidated data to the server action and then to the API endpoint. I see the
I completely agree with this one, I added it as an extra argument, because I didn't want to break the BC. I do agree that it should be an object, as there may be another utils functions later on, like you mentioned. I'd also vote for v7 to merge it with context and have it as a second argument. For the name, maybe it could be even more explicit as |
f606001
to
2c99e07
Compare
I mean, I don't see a huge problem with this approach, because it's just all server code in the end, but I understand your point of view, it could create some confusion. And as I said, data cannot be passed to the action's server code function, so it's pretty useless in most cases anyway.
Don't know why I didn't think about this. Yes, this is pretty terrible. If the server receives invalid data and we don't stop execution before reaching action's server code function, we would get invalid parsed input as the first argument of the action's server code function, so I absolutely agree with you.
Yes, I also think this is better.
Hmm, yes, internally we throw a Lastly, I'm currently actively working on and thinking about the optimal way to solve #51. Once I find the right solution, I'll push the changes to the Please let me know what you think about all of this, and thank you again for your contribution! |
I think I expressed this one in a wrong way. I wanted to say I'd love to see it in v6 as a third argument as it's fully BC and then for v7 I'd love to see it merged with the context. But if you want to go with just v7 I'm fine with that and can prepare the changes. Let me know. I agree with the rest and went ahead and renamed the function to Let me know if there's something else I should update or add (like different example vs adjusting the login one) |
Yeah, I think this is the better solution, to hopefully avoid additional user confusion.
Great!
I'd say keep them as they are right now, since the new |
5e19b46
to
5b750a8
Compare
Rebased the PR with |
…can throw from server action When user throws the server validation error, it produces validationErrors in same way as when schema validation fails.
Rather than having the throwSerrverValidationError as a solo function that's passed to the server
I'm working on your code and really want to implement this feature ASAP. Problem is, I don't know why but my editor (VS Code) doesn't gray out the code below type Utils<S extends Schema, Context> = {
ctx: Context;
returnValidationErrors: (validationErrors: ValidationErrors<S>) => never;
}; It still doesn't work, same behavior as your implementation that uses |
UPDATE: yes, this is a TypeScript bug (?). I set up a new project with just a .ts file and without using next-safe-action, same behavior. I also found out that if you don't destructure the object, it works as expected: This isn't good. Maybe we should keep the util functions as the third argument of the action's server code function and tell users to avoid destructuring the object. I'm not a fan of this, but I suppose it's the only approach we can adopt that's "good enough". |
Ugh, I found few TS issues on GH that this is kind of expected behaviour - nothing for the destructing not working..... We can also ditch this completely and go back to exposing the actual error class, so instead of calling utils function, you'd do: throw new ServerValidationError<typeof schema>({
username: {
_errors: ['invalid']
}
}); It's not that pretty, but works.... |
…s` function A TypeScript limitation makes impossible to get correct visualization of stopped code execution when using a function that returns `never` (throws an error) from a destructured object. Instead, using a standalone exported function to return validation errors to the client actually works as expected.
5b750a8
to
26eddf3
Compare
I exported a standalone function named |
I'm not sure if passing an unused var is better than passing the schema type, but not a huge deal. I like it and thank you! Also, can this go to v6 as it doesn't break BC? |
I agree that it's not a wonderful solution, but I think it's the least painful way to implement it, because you get:
So while I understand that passing an argument that isn't actually used is not that great, I also think that in the end it provides the best DX for this use case.
It could go in v6, but I prefer to keep this in the Once this PR is merged, though, you can install the lib with |
Fair point, I agree with that.
Make sense, thanks :) |
🎉 This PR is included in version 7.0.0-next.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
🎉 This PR is included in version 7.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
🎉 |
I've encountered in almost every project that interacts with an external API a need to return a validation error from the server action. Common example could be when creating a new record that has a unique key (for example email). The server action calls the API and get an error that the email already exists. I usually hacked this and returned a response from server action in similar format to:
Then on client side, there's a need for an additional check on the returned data.
This PR aims to add a way for the user to trigger
validationErrors
output from the server action, instead of the described approach above, there's new function passed to the server action, that lets you trigger thevaldiationErrors
.On the client side, this will return:
Which removes the need to do an additional check on the data, but you can rely on that if
validationErrors
andserverErrors
are null, your server action succeeded.Side note: I initially exported the ServerValidationError and wanted the user to throw it manually, but that would require passing
typeof schema
orschema
to the error, to be able to hint possible validation error keys. The current approach with helper method doesn't require that, but I'm not 100% sold on it....