1

I have this REST API which performs CRUD operations over Clients.

When I get requests containing invalid fields, for instance, a "name" field with over 100 characters, a http error code is returned along with details: "Name field must be less than 100 characters!"

Problem: I must return multiple errors at a time, for example, if "name" and "birthday" are invalid in the same request, both error details must be shown.

Question 1: Is it a good design for APIs to return more than one error? Or should I rely on View to validate those input errors and keep my API as it is?

In case I end up implementing multiple returns I'll come across another issue: my project implements domain-driven design. It means there is a domain (class) and validation is taken care on constructor. If something goes wrong, exception is thrown!

Question 2: How should I validate all my fields, if my flow is broken on the first exception?

I hope it was clear to understand and thanks in advance!

4 Answers4

2

Is it a good design for APIs to return more than one error?

Nothing wrong with that at all. RFC 7807 uses as one of its examples a response describing multiple invalid parameters.

should I rely on View to validate those input errors and keep my API as it is?

I'm not quite sure how you mean this, but you should certainly be validating the inputs on the receiving end. See Domain Driven Security by Johnsson and Deogun.

How should I validate all my fields, if my flow is broken on the first exception?

An important thing to recognize is that message validation is separable from the domain logic -- messages are valid or not valid regardless of the current state.

If we consider validation as a first class concept, then we can think of the validation as taking a RawMessage to a ValidatedMessage. The former is something domain agnostic -- a JSON document, an application/x-www-form-urlencoded payload, a collection of key value pairs. The latter is a value object, created from values that the domain model will recognize.

Your validation method returns an Or-Type: either you get a validated message, or you get a list of validation errors

Either<ValidatedMessage, Errors> validate(RawMessage m)

Scott Wlaschin's Domain Modeling Made Functional is a really good reference on this idea.

VoiceOfUnreason
  • 40,245
  • 4
  • 34
  • 73
1

Input validation is key point in REST API design. It is important for you, as you can save yourself from undesirable, possibly dangerous, data, and you can help the users of your APIs with clear messages where they are misusing them.

To answer to the first question, I don't think there is something wrong in collecting and returning all the input validation errors, it is an exhaustive approach. Another known approach is to return on the first problem you meet. The second saves you some computation time, when this is important.

To answer to the second question, you can simply enclose in try-catch clause each validation step, and append to the errors if you have met some exception.

NiVeR
  • 8,872
  • 4
  • 26
  • 34
1

Question 1: Is it a good design for APIs to return more than one error? Or should I rely on View to validate those input errors and keep my API as it is?

HTTP status codes are divided in classes. As long as all errors fall in the same class (400 Bad Request for instance), you can include a description of all of them in the response body.

Question 2: How should I validate all my fields, if my flow is broken on the first exception?

The issue has been brought up multiple times on SO. See this Q for instance.

There is no hard and fast rule. I'm of the advice that exceptions are for unexpected cases and that try/catch clauses can clutter your code if there are too many. So I usually don't check stuff bordering on technical requirements, like maximum field length, on the domain side.

guillaume31
  • 12,725
  • 28
  • 43
0

You can create a domain model for OO assertions for fulfill the purpose or 'more easily' you can apply a functional approach using a Monad such as either to compose the business errors. The second if already provided if you use a proper tool such as Scala or any other language supporting these monads.