[JAVA] Feign, das einen API-Client nur mit einer Schnittstelle implementiert, ist sehr praktisch!

1. Was ist Feign?

Feign ist eine sehr einfache Java HTTP-Clientbibliothek. Bewertung von: star: 2745 auf github (Stand: 2. April 2018), daher scheint es sich um eine ziemlich genutzte Bibliothek zu handeln. Sie können eine HTTP-Anfrage mit sehr kurzem Code ausgeben. Der Fluss bei Verwendung von "Feign" ist wie folgt.

Die Nachteile sind, dass nur textbasierte HTTP-Anforderungen ausgegeben werden können und HTTP-Antworten nur auf BODY zugreifen können.

(Hinzugefügt am 08.04.2018) Es wird von der Standardeinstellung "Feign" nicht unterstützt, aber Sie können binäre HTTP-Anforderungen mit einem anderen Modul oder Ihrer eigenen Implementierung verarbeiten.

2. Vorbereitung der Bibliothek

Fegin ist so konfiguriert, dass die verwendeten Komponenten ausgetauscht werden können. Dieses Mal werden wir "OkHttp", "Jackson" und "Logback" verwenden.

pom.xml


<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-jackson</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-slf4j</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.3</version>
</dependency>

3. Definieren Sie die API-Schnittstelle

Definieren Sie die API, die Sie als Schnittstelle aufrufen möchten.

Dieses Mal möchte ich den Fall des Aufrufs der unten gezeigten API betrachten.

Artikelnummer Pfad HTTP-Methode Erläuterung
1 /todos GET Holen Sie sich alle TODO
2 /todos/{todoId} GET Ruft das von todoId angegebene TODO ab
3 /todos POST Erstellen Sie ein TODO mit den übertragenen Daten
Der Inhaltstyp istapplication/jsonZu
4 /todos/{todoId} PUT Aktualisieren Sie das von todoId angegebene TODO
Der Inhaltstyp istapplication/jsonZu
5 /todos/{todoId} DELETE Löschen Sie das von todoId angegebene TODO

Der API-Endpunkt (URL) lautet "http: // localhost: 8090 / todo-rest / api / v1".

TodoApi.java


package com.example.feign.demo;

import java.util.List;

import feign.Headers;
import feign.Param;
import feign.RequestLine;

public interface TodoApi {

    @RequestLine("GET /todos")
    List<Todo> findAll();
    
    @RequestLine("GET /todos/{todoId}")
    Todo getTodo(@Param("todoId") String todoId);
    
    @RequestLine("POST /todos")
    @Headers("Content-Type: application/json")
    Todo createTodo(Todo todo);

    @RequestLine("PUT /todos/{todoId}")
    @Headers("Content-Type: application/json")
    Todo updateTodo(@Param("todoId") String todoId, Todo todo);
    
    @RequestLine("DELETE /todos/{todoId}")
    void deleteTodo(@Param("todoId") String todoId);
}

4. Erstellen Sie eine API-Instanz in Feign und führen Sie sie aus

Ich habe die API-Schnittstelle definiert, aber nicht ihre Implementierungsklasse. Eine Instanz der API wird mit Feign erstellt. Durch Aufrufen der API werden einfach die Methoden der Schnittstelle ausgeführt.

TodoApiDemo.java


package com.example.feign.demo;

import java.util.List;

import feign.Feign;
import feign.Logger;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.okhttp.OkHttpClient;
import feign.slf4j.Slf4jLogger;

public class TodoApiDemo {

    public static void main(String[] args) {
        // 1. create instance of api interface with feign 
        TodoApi todoApi = Feign.builder()      // builder call at first
                .client(new OkHttpClient())    // use OkHttpClient of feign
                .encoder(new JacksonEncoder()) // use Jackson of feign
                .decoder(new JacksonDecoder()) // use Jackson of feign
                .logger(new Slf4jLogger())     // use Slf4j of feign
                .logLevel(Logger.Level.FULL)   // setting log level to most detail
                .target(TodoApi.class, 
                        "http://localhost:8090/todo-rest/api/v1");
        
        // 2. call api [GET /todos]
        List<Todo> todos = todoApi.findAll();
        System.out.println(todos);
    }
}

Es wird eine dedizierte Konfigurationsmethode bereitgestellt, um eine Instanz mit dem Builder-Muster zu erstellen.

5. API-Testprobe (Bonus)

Der Aufruf ist nicht schwierig, da nur die Methode der API-Instanz aufgerufen wird. Als Referenz werde ich den Beispiel-API-Test beschreiben. Da der Zweck darin besteht, "Feign" zu verwenden, ist der Inhalt des Tests selbst angemessen.

TodoApiTest.java


package com.example.feign.demo;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import java.util.Date;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

import feign.Feign;
import feign.Logger;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.okhttp.OkHttpClient;
import feign.slf4j.Slf4jLogger;

public class TodoApiTest {

    // test api
    TodoApi todoApi;
    
    private <T> T factory(Class<T> apiType, String url) {
        return Feign.builder()                 // builder call at first
                .client(new OkHttpClient())    // use OkHttpClient of feign
                .encoder(new JacksonEncoder()) // use Jackson of feign
                .decoder(new JacksonDecoder()) // use Jackson of feign
                .logger(new Slf4jLogger())     // use Slf4j
                .logLevel(Logger.Level.FULL)   // setting log level to most detail
                .target(apiType, url);
    }

    @Before
    public void setUp() throws Exception {
        todoApi = factory(TodoApi.class,
                "http://localhost:8090/todo-rest/api/v1");
    }

    @Test
    public void testFindAll() {
        List<Todo> todos = todoApi.findAll();
        System.out.println(todos);
        assertThat(todos.size(), is(2));
    }

    @Test
    public void testCreateTodo() {
        Todo todo = new Todo();
        todo.setTodoTitle("hello");
        Todo registeredTodo = todoApi.createTodo(todo);
        System.out.println(registeredTodo);
    }

    @Test
    public void testGetTodo() {
        String todoId = "36e06987-ef33-436a-a2c6-d215096ee902";
        Todo todo = todoApi.getTodo(todoId);
        System.out.println(todo);
        assertThat(todo.getTodoId(), is(todoId));
    }

    @Test
    public void testUpdateTodo() {
        String todoId = "36e06987-ef33-436a-a2c6-d215096ee902";
        String title = "update......";
        Todo todo = new Todo();
        todo.setTodoId(todoId);
        todo.setTodoTitle(title);
        todo.setCreatedAt(new Date());
        Todo updatedTodo = todoApi.updateTodo(todoId, todo);
        System.out.println(updatedTodo);
        assertThat(updatedTodo.getTodoId(), is(todoId));
        assertThat(updatedTodo.getTodoTitle(), is(title));
        assertThat(updatedTodo.isFinished(), is(true));
    }
    
    @Test
    public void testDeleteTodo() {
        String todoId = "36e06987-ef33-436a-a2c6-d215096ee902";
        todoApi.deleteTodo(todoId);
        System.out.println("ok");
    }
}

6. Schließlich

Dieses Mal erklärte ich Feign, eine Bibliothek für den Java-HTTP-Client. Es ist eine sehr einfach zu verwendende Bibliothek, da fast die API-Schnittstelle definiert wird. Obwohl diesmal nicht erklärt, unterstützt "Feign" auch "JAXB" und "JAX-RS". Es gibt eine Einschränkung, dass nur textbasierte HTTP-Anforderungen verarbeitet werden können, aber ich wollte sie aktiv mit APIs verwenden, die davon nicht betroffen sind.

Recommended Posts

Feign, das einen API-Client nur mit einer Schnittstelle implementiert, ist sehr praktisch!
Implementieren Sie den API-Client mit nur Anmerkungen unter Verwendung von Feign (OpenFeign).
Was ist eine Schnittstelle?
[swift5] Versuchen Sie, einen API-Client auf verschiedene Arten zu erstellen
Was genau ist eine API?