Handling YAML format in your REST with Spring Boot
In general a REST service serves JSON document formats. In Spring Boot it is even the standard without having to configure anything. Over HTTP we have the ability to send a Content-Type as header to instruct the server to return a certain document format (Mime type). Besides handling JSON, XML is another common document format. But what if we want to serve or read a YAML document format? This tutorial provides the required steps to be able to handle objects in YAML format. To be able to send a YAML Content-Type with the header, and to be able to serialize and deserialize with the existing ObjectMappers of Jackson. This tutorial will use Spring Boot, Jackson and a YAML dataformat extension library for Jackson.
Add dependency
First we need to add the YAML Jackson extension to our Gradle build file.
dependencies {
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.4'
}
Register ObjectMapper
Now we can create a specific ObjectMapper
with a registered YAMLFactory
.
To create our YAML ObjectMapper the following line will:
@Configuration public class ObjectMapperConfiguration {
//This is our default JSON ObjectMapper. Add @Primary to inject is as default bean. @Bean @Primary public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); //Enable or disable features return objectMapper; }
@Bean public ObjectMapper yamlObjectMapper() { ObjectMapper yamlObjectMapper = new ObjectMapper(new YAMLFactory()); //Enable or disable features return yamlObjectMapper; } }
Now we have registered two ObjectMapper
instances. One for JSON and one for YAML.
Both with the option to enable or disable features in the ObjectMapper.
Register MessageConverter and Content Negotiation
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
private static final MediaType MEDIA_TYPE_YAML = MediaType.valueOf("text/yaml");
private static final MediaType MEDIA_TYPE_YML = MediaType.valueOf("text/yml");
@Autowired
@Qualifier("yamlObjectMapper")
private ObjectMapper yamlObjectMapper;
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.favorPathExtension(true)
.favorParameter(false)
.ignoreAcceptHeader(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType(MediaType.APPLICATION_JSON.getSubtype(),
MediaType.APPLICATION_JSON)
.mediaType(MEDIA_TYPE_YML.getSubtype(), MEDIA_TYPE_YML)
.mediaType(MEDIA_TYPE_YAML.getSubtype(), MEDIA_TYPE_YAML);
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter yamlConverter =
new MappingJackson2HttpMessageConverter(yamlObjectMapper);
yamlConverter.setSupportedMediaTypes(
Arrays.asList(MEDIA_TYPE_YML.getSubtype(), MEDIA_TYPE_YAML.getSubtype())
);
converters.add(yamlConverter);
}
}
Read YAML file
Another option we have is to read YAML files and transform them into Objects.
Lets say we already have a FileService
that has functionality to read a file as an InputStream.
interface FileService {
InputStream read(String name);
}
To transform this InputStream
into an Object, we autowire the YAML ObjectMapper and provide the returned InputStream to the ObjectMapper.
@Service
public class CustomerService {
@Autowired
private FileService fileservice;
@Autowired
@Qualifier("yamlObjectMapper")
private ObjectMapper yamlObjectMapper;
public Customer get() {
try {
@Cleanup
InputStream inputStream = fileservice.read("my-customer.yaml");
return yamlObjectMapper.readValue(inputStream, Customer.class);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
@Data
public static class Customer {
private String name;
private String surname;
private String email;
}
}
NB. For this example Lombok was used http://projectlombok.org.