Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

REST-API Different Content-Type on Error Response

Since some weeks I'm working on an rest api using spring-mvc. The REST-API is working properly and I`m almost done until one last problem when it comes to error handling with specific error-objects.

The REST-API is using JSON as format to serialize Java-Objects. When an error occurs during service-execution an specific error-object gets created and sent back to the client.

Everything is working fine when my rest-services are marked as "produces=application/json". But there are also some services which only need to return simple text using "produces=text/plain". When an error occurs in one of these services Spring-MVC will throw an HttpMediaTypeNotAcceptableException. Seems to be correct cause client asks for content-type "text/plain" but server response with "application/json".

Can you tell me what's the correct solution for this problem?

  1. Only using JSON as response content-type and wrapping simple text always in an special class object. => Seems to me not really REST like, cause REST should support multiple content-types.

  2. Every service serving "text" will be marked as "produces=application/json;text/plain" and Client also need to send both in "accept-header". => When doing it this way the API seems to support two content-types for same resource. But that`s not right. Only in case of an error the API will return JSON, otherwise it will be always "text".

Sounds for me like a really special REST question and couldn`t find related questions on this topic.

like image 301
Vhaos Avatar asked Jun 17 '15 11:06

Vhaos


People also ask

How does REST API handle error response?

The simplest way we handle errors is to respond with an appropriate status code. Here are some common response codes: 400 Bad Request – client sent an invalid request, such as lacking required request body or parameter. 401 Unauthorized – client failed to authenticate with the server.

How do I change the Content-Type in REST API?

To set the Content Type Order, you have to use the uniqueContentTypeOrder method on the Folder object API (note, this is an operation on the folder, not on the List. While you can call uniqueContentTypeOrder on the List object, it is read-only on that object and will not accept any updates.

What are the different content types in REST API?

Some common examples of content types are “text/plain”, “application/xml”, “text/html”, “application/json”, “image/gif”, and “image/jpeg”. Similarly, to determine what type of representation is desired on the client-side, an HTTP header ACCEPT is used.

Can we customize Content-Type in rest?

You can use the dotCMS REST API to manage Content Types. Content Types can be created, updated, copied, and deleted via REST API.


1 Answers

User should always specify what content it's expecting with Accept header. It's you job to return the error that was thrown/caught on the server side in the format that was specified in Accept header. In spring as far as I know it could be achieved with a special mapper. Below you can find such mapper written in groovy to handle text/html.

import groovy.xml.MarkupBuilder
import org.springframework.http.HttpInputMessage
import org.springframework.http.HttpOutputMessage
import org.springframework.http.converter.AbstractHttpMessageConverter

import static org.springframework.http.MediaType.TEXT_HTML

class ExceptionResponseHTMLConverter extends AbstractHttpMessageConverter<ExceptionResponse> {
  ExceptionResponseHTMLConverter() {
    super(TEXT_HTML)
  }

  @Override
  boolean supports(Class clazz) {
    clazz.equals(ExceptionResponse)
  }

  @Override
  ExceptionResponse readInternal(Class clazz, HttpInputMessage msg) {
    throw new UnsupportedOperationException()
  }

  @Override
  void writeInternal(ExceptionResponse e, HttpOutputMessage msg) {
    def sw = new StringWriter()
    new MarkupBuilder(sw).error {
      error(e.error)
      exception(e.exception)
      message(e.message)
      path(e.path)
      status(e.status)
      timestamp(e.timestamp)
    }
    msg.body << sw.toString().bytes
  }
}

And ExceptionResponse class:

class ExceptionResponse {
  String error
  String exception
  String message
  String path
  Integer status
  Long timestamp
}
like image 104
Opal Avatar answered Sep 20 '22 22:09

Opal