condran
6/30/2016 - 1:24 PM

Spring Cloud Netflix with PATCH (client side)

Spring Cloud Netflix with PATCH (client side)

Spring Cloud Netflix with PATCH (client side)

I have been researching Spring Boot and Spring Cloud, there are lots of goodies here but as with all technology there are gotchas.

Feign Client does not support PATCH out of the box! ಠ_ಠ ... ಠ~ಠ ... ⊙︿⊙

You might see an error like this if you try to use RequestMethod.PATCH in your @FeignClient interface: java.net.ProtocolException: Invalid HTTP method: PATCH

I am using the current versions:

Spring ProjectVersion
Spring CloudBrixton.RELEASE
Spring Boot1.3.5.RELEASE

You need to include this library in your pom.xml, and then Feign will pick it up, so that's not too bad but the info is hard to find in various StackOverflow posts / docs / Google links

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <!-- Required to use PATCH -->
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

Your spring boot application class will look something like this (if you want to use HAL from Feign)

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class SpringBootApplication {
    // main, etc
}

Finally, make sure your FeignClient interface is properly defined

// Use spring application service id, or URL, whatever you need to find the REST service
@FeignClient("book-data-rest-discovery-service-id")
public interface SpringDataRESTClient {

    @RequestMapping(method = RequestMethod.GET, value = "/books", consumes= MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    PagedResources<Book> getBookData(@RequestParam("page") int page);

    @RequestMapping(method = RequestMethod.GET, value = "/books/{id}", consumes= MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    Resource<Book> getBook(@PathVariable("id") String id);

    @RequestMapping(method = RequestMethod.POST, value = "/books", consumes= MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    void save(Book newBook);

    // You can also use RequestMethod.PUT, which is better supported than PATCH by default (no need to include extra 'feign-httpclient' in Maven pom)
    @RequestMapping(method = RequestMethod.PATCH, value = "/books/{bookId}", consumes= MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    Book update(@PathVariable("bookId") UUID bookId, Book book);

}