Continue the series about Java REST client, I’d like to share how to implement Java REST client using Netflix Feign. As mentioned in the Feign site, Feign is a java to http client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. In similar to other REST client frameworks, libraries, Feign aims to simplify the interaction between client code and http api.
1. Preparation
Assume that we have a RESTful web service with several API as below:
1.1 Get all books
1 |
GET http://localhost:8080/v1/books |
1.2 Create a new book
1 |
POST http://localhost:8080/v1/books |
Example:
1 2 3 4 |
{ "name": "Java How To Program", "author": "Paul Deitel" } |
Responses: application/json
Example:
1 2 3 4 5 |
{ "id": 5 "name": "Java How To Program", "author": "Paul Deitel" } |
STATUS 201 if the book is created successfully.
1.3 Update a book
1 |
PUT http://localhost:8080/v1/books/{id} |
Example:
1 2 3 4 5 |
{ "id": 1, "name": "Java How To Program 2nd", "author": "Paul Deitel" } |
Responses: application/json
STATUS 200 if the book is updated successfully.
STATUS 400 if there is no book with given id
1.4 Delete a book
1 |
DELETE http://localhost:8080/v1/books/{id} |
STATUS 204 if the book is deleted successfully.
STATUS 400 if there is no book with given id or cannot delete the book.
1.5 Source code
The demo source code can be found on the Github.
We use Netflix Feign to communicate with the REST service above, and we will use Jackson JSON providers to deal with JSON content.
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-core</artifactId> <version>8.18.0</version> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-jackson</artifactId> <version>8.18.0</version> </dependency> |
2. Create REST Client Using Netflix Feign
2.1. Define a Proxy Interface at the client side.
We firstly base on the above RESTful API to create a Java interface, annotated with annotations provided by Feign. Feign will process those annotations to make requests and communicate with the remote http api. Let’s see a BookResourceFeign class I have just defined as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import feign.Headers; import feign.Param; import feign.RequestLine; @Headers("Accept: application/json") public interface BookResourceFeign { @RequestLine("GET /v1/books") List<Book> getAllBooks(); @Headers("Content-Type: application/json") @RequestLine("POST /v1/books") Book createBook(Book book); @Headers("Content-Type: application/json") @RequestLine("PUT /v1/books/{id}") Book updateBook(@Param("id") Long id, Book book); @RequestLine("DELETE /v1/books/{id}") void deleteBook(@Param("id") Long id); } |
We can see that the annotations are a little bit different with ones provided by JAX-RS, but it’s pretty easy to understand those. Because this client will accept response as JSON, we annotated the interface: @Headers(“Accept: application/json”). For the Post and Put resources, we specify the request body as JSON, so we annotated @Headers(“Content-Type: application/json”) on those methods. The values of the @RequestLine are kinds of text, very simple to understand.
As for the Book model, we have defined temporarily as follows:
1 2 3 4 5 6 7 8 |
@JacksonXmlRootElement(localName = "book") public class Book { private Long id; private String name; private String author; //All getters and setters should be here } |
2.2. Invoke methods on the Proxy
After having the proxy interface, we just need to invoke its methods to communicate with the RESTful API.
2.2.1. Make a GET request to the RESTful web service (Get all books)
1 2 3 4 5 6 7 8 9 10 |
public class BookRepositoryImplFeign { private static final String URI_BOOK = "http://localhost:8080"; public List<Book> getAllBooks() throws Exception { BookResourceFeign bookResource = Feign.builder().encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()).target(BookResourceFeign.class, URI_BOOK); return bookResource.getAllBooks(); } } |
We will create a main method to test as follows:
1 2 3 4 5 |
public static void main(String[] args) throws Exception { BookRepositoryImplFeign bookRepository = new BookRepositoryImplFeign(); List<Book> books = bookRepository.getAllBooks(); System.out.println(books); } |
Here is the output of my console:
1 |
[Book [id=1, name=Java How To Program, author=Paul Deitel], Book [id=2, name=Thinking in Java, author=Bruce Eckel]] |
2.2.2. Make a POST request to the RESTful web service (create a book)
1 2 3 4 5 6 7 8 9 10 11 |
public class BookRepositoryImplFeign { private static final String URI_BOOK = "http://localhost:8080"; public Book createBook(Book book) throws Exception { BookResourceFeign bookResource = Feign.builder().encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()).target(BookResourceFeign.class, URI_BOOK); Book createdBook = bookResource.createBook(book); return createdBook; } } |
We simply invoked the createBook(book) method on the proxy to create new book by posting the JSON content to the REST API
We will update the main method to test:
1 2 3 4 5 6 |
public static void main(String[] args) throws Exception { BookRepositoryImplFeign bookRepository = new BookRepositoryImplFeign(); Book book = new Book(null, "Effective Java", "Joshua Bloch"); Book createdBook = bookRepository.createBook(book); System.out.println(createdBook); } |
The output of my console:
1 |
Book [id=4, name=Effective Java, author=Joshua Bloch] |
2.2.3. Make a PUT request to the RESTful web service (Update a book)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import feign.Feign; import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; public class BookRepositoryImplFeign { private static final String URI_BOOK = "http://localhost:8080"; public Book updateBook(Book book) throws Exception { BookResourceFeign bookResource = Feign.builder().encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()).target(BookResourceFeign.class, URI_BOOK); Book updatedBook = bookResource.updateBook(book.getId(), book); return updatedBook; } } |
We update the main method to test:
1 2 3 4 5 6 7 8 9 10 11 |
public static void main(String[] args) throws Exception { BookRepositoryImplFeign bookRepository = new BookRepositoryImplFeign(); // Getting the first book from the RESTful service Book book = bookRepository.getAllBooks().get(0); System.out.println(book); // Change the name book.setName(book.getName() + " 3rd"); // Then update the book book = bookRepository.updateBook(book); System.out.println(book); } |
Here is the output of my console:
1 2 |
Book [id=1, name=Java How To Program, author=Paul Deitel] Book [id=1, name=Java How To Program 3rd, author=Paul Deitel] |
Note that the book was updated with the new name: Java How To Program 3rd
2.2.4. Make a DELETE request to the RESTful web service (delete a book)
1 2 3 4 5 |
public void deleteBook(Long id) { BookResourceFeign bookResource = Feign.builder().encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()).target(BookResourceFeign.class, URI_BOOK); bookResource.deleteBook(id); } |
1 2 3 4 5 |
public static void main(String[] args) throws Exception { BookRepositoryImplFeign bookRepository = new BookRepositoryImplFeign(); Book book = bookRepository.getAllBooks().get(0); bookRepository.deleteBook(book.getId()); } |
3. Conclusion
We have learned how to implement Java REST Client using Netflix Feign. Note that we have used Feign Jackson Json message converter to deal with JSON content from REST API. There are a lot of choices. We can use Gson, Sax, JAXB, JAX-RS if we prefer. In future, I will share how to implement Java REST client with another framework like Retrofit and summarize all the common frameworks, tools that can be used to implement Java REST client.
Below are other articles which related to the Java REST client for your references:
Using Netflix Feign with Spring Cloud
Basic Authentication with Open Feign
File Uploading with Open Feign
Java REST Client Using Retrofit 2
Simple Java REST Client Using java.net.URL package
Java REST Client Using Spring RestTemplate
Java REST Client Using Apache HttpClient
Java REST Client Using Jersey Client
Java REST Client Using Resteasy Client
Java REST Client Using Resteasy Client Proxy Framework
Java REST Client Using Apache CXF Proxy-based API