Press "Enter" to skip to content

Building consistent web api responses

vpandzic 0

This blog post will be about importance of building consistent web api responses. This first part will be almost language agnostic, but if you want to see real implementation of building consistent response from ASP.NET Web Api you can read second part.

When you read about building successfull RESTfull web service you always read about building intuitive, predictable URLs which contains nouns instead of verbs, for example,{objectId}/images  for getting all images that belong to particular object. Intuitively, information about one particular object would return{objectId}  URL. List of all objects would return  URL. For each of them you would initiate GET  request. If you want to make endpoint that creates new object in RESTfull nature you would need to make endpoint that accepts POST  request to  URL. It makes client who implements your  API happier about it because you are following some standard. I often see good, predictable URL structures, and APIs that follow  REST when we talk about URLs, logical use of HTTP verbs ( GET for getting information, POST for insterting new data and similar. However, what I don’t see so often, and what I think it makes client code much more elegant is building consistent web api response.

Example of inconsistent web api responses

Let’s see some example of inconsistent web api responses :  – returns list of objects, response looks like this:

Returned status code is 200. This API is not perfect, like any, error can happen and in that case response returned to the client looked liked this:

"Error happened" . Returned status code is 500.  -returns data about one object. Response status code is 200, and response looks like this:

When error(s) happen this response is returned with status code 500:

Analysis of responses

Positive thing about examples above is that at least correct HTTP status code is returned so client code can appropriately handle response and diffirentiate between success and failure. However, there are few problems:

  • If you want to return more data in case of failure (instead of generic “Error happened” message ) you can’t do it without breaking client’s code. Client expects string, and you would like to return object that contain more that data, for example:

First takeway from example is above. Don’t return simple data types, wrap response inside some kind of object for making client’s code less brittle.

  • This was fixed in second example (receiving data about one object). Creator of web api created completely new object that contain statusCode property and errors   property. Error property is object which contains userMessage  and errorCode  property. Nice thing about that is that error object is extensible. Creator of web api can add additional property as necessary. However, if we compare error responses from  and{objectId}  we can see they are inconsistent. Not only client must refer to your documentation more often but you are also forcing your client to write more code. More code because developer who makes integration of your API must create model class for each response. Imagine, ListOfObjectsErrorResponseDto  and OneObjectErrorResponseDto . There are three takeaways from this part of article. Make error response consistent. Make each property that you know in advance that will be extended as object instead of simple data type. (see Error property). Don’t force developer who implements your api to read more of your documentation than necessary and to write more code than necessary.

Let’s fix this API responses

Let’s try to put this together in consistent way following best practices from above.

This is response for getting list of all objects (HTTP status code is still 500 -because server error happened)

Response from receiving one object is:

Now, responses are predictable, consistent. Client can learn your logic behind your API more quickly because you only have one type of object. Client can now write only one error response model, and therefore can only have few lines of code that makes deserialization of your error responses. If you want to add more metadata to your responses you can – client’s code won’t break only because you added one additional property to your responses.

More analysis

Let’s go step further and discuss successfull responses. In first case, by visiting we are getting back some array -list of objects. In second case, we are getting only one object. At first glance, you are probably see that “extensibility” problem. What if we want to add additional data to list of objects. Maybe we want to implement paging and would like to return number of objects in total. If we want to do something like this it requires big changes to client’s code. This is ObjectListResponseDto :

If we know we are returning list of objects it would probably be good idea to return object that contains list of object as one property of that object leaving possibility to add additional properties to that object open( like above). If we know we are returning one object it is probably bad idea to return just that object. This way, you can’t easily attach metadata about response. Instead wrap it inside some object ( ObjectResponseDto ).

There is consistency problem left unresolved. At first, you may think that ObjectResponseDto and ObjectListResponse  don’t have anything in common (properties are obviously different) and you are right. However, we can achieve that responses from  and{objectId}  are the same. Benefit of this is that makes client’s code that does deseralization of JSON response much easier and elegant because it can expect some structure always. Let’s see that generic response structure:

In case of success response while receiving list of object we are getting back complex object that contains data  property. data  property is of type ObjectListResponse , so you generic response class would look like this:

In success scenario of getting one object we will receive object that contains data  property (just like in case of receving list of objects).

If your language supports generics like C# than your Generic response class can look like this:

This way client’s code is much more elagant. GenericResponse is the only model it has to deserialiaze. Takeaway from this. Make consistent web api success responses my making them all return some structure. All difference is inside data  property. Data  property is sometimes of type ObjectResponse, sometimes is of type ObjectListResponse.

Making same response for success and failure -building consistent web api responses

Remember error response from few paragraphs above? Here it is again:

If we add those properties to GenericResponse class we could make model that is returned always -in case of different response models, in case of success and failure.

Now in case of failure, it is returned 403 (Bad request), 500 or other >400 status code. Errors property is populated with errors and data  property is null. In case of success errors  property is empty and data  property is populated with appropriate data. Result of making consistent web api response:

  • Integration of web service takes less time because developer writes less code , refers to documentation less often
  • More elagant code. By taking advantage of advanced language features like generics and the fact that responses are consistent developer can make code that is easier to write and easier to maintain.
  • Happier costumers – APIs are built for business and costumers. All things from mentioned above (less time to integration, easirer maintaince, less bugs) result in happier costumers who use you application.

In second part of this series of articles about building consistent web api responses I will explain and show how to build consistent Web Api response using C# and ASP.NET Web Api.

    Leave a Reply

    Your email address will not be published. Required fields are marked *