How to expose a validation API in a RESTful way?

2019-01-21 21:28发布

问题:

I'm generally a fan of RESTful API design, but I'm unsure of how to apply REST principles for a validation API.

Suppose we have an API for querying and updating a user's profile info (name, email, username, password). We've deemed that a useful piece of functionality to expose would be validation, e.g. query whether a given username is valid and available.

What are the resource(s) in this case? What HTTP status codes and/or headers should be used?

As a start, I have GET /profile/validate which takes query string params and returns 204 or 400 if valid or invalid. But validate is clearly a verb and not a noun.

回答1:

The type of thing you've described is certainly more RPC-style in its' semantics, but that doesn't mean you can't reach your goals in a RESTful manner.

There's no VALIDATE HTTP verb, so how much value can you get from structuring an entire API around that? Your story centers around providing users with the ability to determine whether a given user name is available - that sounds to me like a simple resource retrieval check - GET: /profile/username/... - if the result is a 404, the name is available.

What this highlights is that that client-side validation is just that - client side. It's a UI concern to ensure that data is validated on the client before being sent to the server. A RESTful service doesn't give a whit whether or not a client has performed validation; it will simply accept or reject a request based on its' own validation logic.

REST isn't an all-encompassing paradigm, it only describes a way of structuring client-server communications.



回答2:

You are confusing REST with resource orientation, there's nothing in REST that says you cannot use verbs in URLs. When it comes to URL design I usually choose whatever is most self-descriptive, wheather is noun or verb.

About your service, what I would do is use the same resource you use to update, but with a test querystring parameter, so when test=1 the operation is not done, but you can use it to return validation errors.

PATCH /profile?test=1
Content-Type: application/x-www-form-urlencoded

dob=foo

... and the response:

HTTP/1.1 400 Bad Request
Content-Type: text/html

<ul class="errors">
  <li data-name="dob">foo is not a valid date.</li>
</ul>


回答3:

We have also encountered the same problem. Our reasoning for having the client defer to the server for validation was to prevent having mismatched rules. The server is required to validate everything prior to acting on the resources. It didn't make sense to code these rules twice and have this potential for them to get out of sync. Therefore, we have come up with a strategy that seems to keep with the idea of REST and at the same time allows us to ask the server to perform the validation.

Our first step was to implement a metadata object that can be requested from a metadata service (GET /metadata/user). This metadata object is then used to tell the client how to do basic client side validations (requiredness, type, length, etc). We generate most of these from our database.

The second part consist of adding a new resource called an analysis. So for instance, if we have a service:

GET /users/100

We will create a new resource called:

POST /users/100/analysis

The analysis resource contains not only any validation errors that occurred, but also statistical information that might be relevant if needed. One of the issues we have debated was which verb to use for the analysis resource. We have concluded that it should be a POST as the analysis is being created at the time of the request. However, there have been strong arguments for GET as well.

I hope this is helpful to others trying to solve this same issue. Any feedback on this design is appreciated.



回答4:

It is greate to have the validation in the REST API. You need a validation anyway and wy not to use it on the client side. In my case I just have a convention in the API that a special error_id is representing validation errors and in error_details there is an array of error messages for each feild that has errors in this PUT or POST call. For examople:

{
  "error": true,
  "error_id": 20301,
  "error_message": "Validation failed!",
  "error_details": {
    "number": [
      "Number must not be empty"
    ],
    "ean": [
      "Ean must not be empty",
      "Ean is not a valid EAN"
    ]
  }
}

If you use the same REST API for web and mobile application you will like the ability to change validation in both only by updating the API. Especialy mobile updates would take more than 24h to get published on the stores.

And this is how it looks like in the Mobile application:

The response of the PUT or POST is used to display the error messages for each field. This is the same call from a web application using React:

This way all REST API response codes like 200 , 404 have they'r meanig like they should. A PUT call responses with 200 even if the validation fails. If the call passes validation the response would look like this:

{
  "error": false,
  "item": {
"id": 1,
"created_at": "2016-08-03 13:58:11",
"updated_at": "2016-11-30 08:55:58",
"deleted_at": null,
"name": "Artikel 1",
"number": "1273673813",
"ean": "12345678912222"
  }
}

There are posible modifications you could make. Maby use it without a error_id. If tehre are error_details just loop them and if you find a key that has the same name as a field put his value as error text to the same field.



标签: api http rest