Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Denna starter förenklar användningen av Feign som REST-klient, via Spring Cloud OpenFeign. För att använda den, lägg till följande i tjänstens pom.xml:

...

Lägg även till annoteringen @EnableFeignClients på main-klassen.

Alternativ 1 - FeignMultiCustomizer

FeignMultiCustomizer är en ersättare för den utfasade klassen FeignBuilder, beskriven under alternativ 2. Den är en hjälpklass för att bygga REST-klienter med hjälp av interface som annoteras med Spring:s annoteringar för request-mappning, t.ex.:

Code Block
languagejava
@FeignClient(name = "GithubClient", 
             url = "${integration.github.url}", 
             configuration = GithubConfiguration.class)
public interface GithubClient {

    @GetMapping("/{user}?tab=repositories", produces = APPLICATION_JSON_VALUE)
    List<Repo> getRepositoriesForUser(@PathVariable("user") String user);
}

Med hjälp av klassen FeignMultiCustomizer genereras den faktiska klient som används av interfacet:

Code Block
languagejava
@Import(FeignConfiguration.class)										[1]
public class GithubConfiguration {

	@Bean
	FeignBuilderCustomizer feignBuilderCustomizer() {
		return FeignMultiCustomizer.create()
			.withCustomizer(...)										[2]
			.withErrorDecoder(...)										[3]
			.withRequestInterceptor(...)								[4]
			.withRequestOptions(...)									[5]
			.withRequestTimeoutsInSeconds(...)							[6]
			.withRetryableOAuth2InterceptorForClientRegistration(...)	[7]
			.composeCustomizersToOne();									[8]
	}
}

Interfacet kan sedan användas för att anropa integrationer i andra klasser:

Code Block
@Service
public class RepositoryService {
	@Autowired
	private GithubClient githubClient;
	
	public List<Repo> getCustomer(String user) {
		return githubClient.getRepositoriesForUser(user);
	}
}

[1] Ifall FeignConfiguration från Dept-44 importeras så läggs funktionalitet för loggning av request och response, requestId-hantering samt hantering av truststore för domän sundsvall.se (för hantering av anrop mot andra mikrotjänster i WSO2) till.
[2] Möjliggör ytterligare anpassning av Feign-klienten i de fall stöd saknas i ramverket.
[3] Anger den error decoder som ska användas för att översätta de fel som kastas av integrationen.
[4] Anger de interceptorer som ska användas för att förändra det utgående anropet före det skickas.
[5] Anger de anrops-alternativ som ska gälla för klienten avseende timeouts och follow-redirects
[6] En alternativ metod till [5] där follow-redirects default sätts till true
[7] Anger att ett nytt anrop med förnyat access token ska ske ifall autentiseringsuppgifterna har gått ut.
[8] Skapar den FeignBuilderCustomizer som sedan används av OpenFeign-ramverket när klienten skapas.

Note

Alternativ 2 - FeignBuilderObs, denna hjälpklass är på väg att fasas ut och ersätts med FeignMultiCustomizer som beskrivits ovan

FeignBuilder används, precis som det låter, för att bygga en REST-klient vars metoder definieras i ett interface som annoteras med Spring:s annoteringar för request-mappning, t.ex.:

...

[4] Om angiven (användarnamn och lösenord) sätts Basic-autentisering upp.
[5] Anger connect timeout. Default-värde är 10 sekunder.
[6] Anger read timeout. Default-värde är 60 sekunder.
[7] Anger om REST-klienten ska följa omdirigeringar. Default-värde är true.
[8]-[12] Kan, om så önskas, användas för att exempelvis använda en alternativ HTTP-klient eller för att konfigurera retry-policy och liknande.
[13] Skapar själva REST-klienten, av given typ.

Notera att det inte går att använda FeignBuilder där OAuth2- och Basic-autentisering konfigureras samtidigt.

Alternativ

...

3 - annoteringar

Först och främst behövs ett klient-interface:

...

Code Block
languagejava
@Import(FeignConfiguration.class)
class GithubClientConfiguration {

    @Bean
    RequestInterceptor basicAuthInterceptor(String username, String password) { [1]
        return FeignHelper.basicAuthInterceptor(username, password);
    }

    @Bean
    FeignBuilderCustomizer feignBuilderCustomizer() {                           [2]
        return FeignHelper.customizeRequestOptions()
            .withConnectTimeout(Duration.ofSeconds(60))
            .withReadTimeout(Duration.ofSeconds(5))
            .build();
    }
    	
    @Bean
    ErrorDecoder errorDecoder() {                                               [3]
		return new GenericJsonErrorDecoderProblemErrorDecoder("GithubClient");
	}
}

Ifall konfigurationen definierar någon böna av typen RequestInterceptor, likt [1], kommer den automatiskt att knytas in i Feign-klienten. I exemplet används en utility-klass från ramverket - FeignHelper - för att skapa en interceptor för Basic-autentisering. FeignHelper har även stöd för att jacka in exempelvis en interceptor för OAuth2 och för att anpassa timeouts likt [2].

...

Ramverket erbjuder en generisk ErrorDecoder. D.v.s. en mappning mellan “error-response” från tjänsten som anropas och exceptions i den egna tjänsten.

Genom att använda den GenericJsonErrorDecoder ProblemErrorDecoder eller JsonPathErrorDecoder behöver man inte implementera en egen. Har anropad tjänst även implementerat felhantering enligt https://datatracker.ietf.org/doc/html/rfc7807 behöver man inte göra någonting mer än att skapa ProblemErrorDecoder bönan i sin konfigurationsklass (se första exemplet nedan).

Om anropad tjänst däremot har uppfunnit en egen modell för fel, kan man behöva peka ut den data man vill mappa med hjälp av klassen JsonPathErrorDecoder och JSON-path.

Konfiguration som krävs när anropad tjänst implementerat RFC-7807:

Code Block
languagejava
@Import(FeignConfiguration.class)
class GithubClientConfiguration {

    @Bean
	ErrorDecoder errorDecoder() {                                               
		return new GenericJsonErrorDecoderProblemErrorDecoder("GithubClient");
	}
}


Konfiguration för fel som avviker från ovan beskriven standard. Genom att använda JsonPathErrorDecoder och ange sökvägen via JSON-path till den data vi vill mappa kan vi hantera vilka strukturer på felmeddelandet som helst. Se exempel nedan:

...

Code Block
languagejava
@Import(FeignConfiguration.class)
class GithubClientConfiguration {

    @Bean
	ErrorDecoder errorDecoder() {                                               
		new GenericJsonErrorDecoderJsonPathErrorDecoder("GithubClient", new JsonPathSetup(
			"$['errorMessage']", "$['extraInfo']['details']", "$['extraInfo']['status']"))
	}
}

...