Add custom-validation, etag-caching, restclient-basic-auth: Boot 4.1 API pass
Three companion modules verifying and rewriting the Boot 4.1.1 / Framework 7.0.9 story for three older articles: the javax->jakarta.validation namespace fix plus Jakarta Validation 3.1 record-validation clarification, ETag/ conditional-request APIs re-verified unchanged plus the starter rename, and RestTemplate Basic Auth rebuilt on RestClient with the exchange() trap called out. 19 real passing tests generate every transcript quoted from the three companion articles. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01EQNA6DJ9VgCtW6zhCE8Xud
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
# 2. RestClient with Basic Auth, two ways
|
||||
|
||||
[Prev: {noop} passwords](01-password-encoding.md) | [README](../README.md) | Next: [The starter split, and the exchange() trap](03-starter-split-and-exchange-trap.md)
|
||||
|
||||
Source: [`RestClientConfig.java`](../src/main/java/com/ankurm/restclientbasicauth/client/RestClientConfig.java),
|
||||
[`ApiClient.java`](../src/main/java/com/ankurm/restclientbasicauth/client/ApiClient.java).
|
||||
Test: [`RestClientBasicAuthTest.java`](../src/test/java/com/ankurm/restclientbasicauth/RestClientBasicAuthTest.java).
|
||||
Transcripts: [`docs/output/01-restclient-basic-auth-default-headers.txt`](output/01-restclient-basic-auth-default-headers.txt),
|
||||
[`docs/output/02-restclient-basic-auth-interceptor.txt`](output/02-restclient-basic-auth-interceptor.txt).
|
||||
|
||||
The original article's two `RestTemplate` patterns -- `RestTemplateBuilder.basicAuthentication(...)`
|
||||
and a hand-added `BasicAuthenticationInterceptor` -- both have a direct `RestClient` equivalent.
|
||||
Both are built on the **auto-configured `RestClient.Builder`** injected as a constructor parameter,
|
||||
never `RestClient.create()`, which carries none of Boot's message converters, observability, or
|
||||
customizer beans -- the same rule the
|
||||
[RestTemplate to RestClient migration guide](https://ankurm.com/resttemplate-to-restclient-migration-guide/)
|
||||
covers in more general depth.
|
||||
|
||||
## Idiomatic on RestClient: `defaultHeaders` + `setBasicAuth`
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public RestClient restClientWithDefaultHeaders(RestClient.Builder builder) {
|
||||
return builder
|
||||
.defaultHeaders(headers -> headers.setBasicAuth("admin", "password123"))
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
Response: Hello, you have accessed a secured endpoint!
|
||||
```
|
||||
|
||||
([`docs/output/01-restclient-basic-auth-default-headers.txt`](output/01-restclient-basic-auth-default-headers.txt))
|
||||
-- a real HTTP call against a real embedded Tomcat with a real Spring Security filter chain, not a
|
||||
mock.
|
||||
|
||||
## Ported unchanged: `BasicAuthenticationInterceptor`
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public RestClient restClientWithInterceptor(RestClient.Builder builder) {
|
||||
return builder
|
||||
.requestInterceptor(new BasicAuthenticationInterceptor("admin", "password123"))
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
`BasicAuthenticationInterceptor` implements `ClientHttpRequestInterceptor` -- the exact same
|
||||
interface both `RestTemplate.getInterceptors()` and `RestClient.Builder.requestInterceptor(...)`
|
||||
accept, so this class needs no changes at all to move from one client to the other. Same result:
|
||||
[`docs/output/02-restclient-basic-auth-interceptor.txt`](output/02-restclient-basic-auth-interceptor.txt).
|
||||
|
||||
Prefer `defaultHeaders` when the credentials are fixed at bean-creation time; keep the interceptor
|
||||
form when credentials must be resolved per request (a token fetched from a vault, say) --
|
||||
an interceptor runs on every call, a `defaultHeaders` value is captured once.
|
||||
|
||||
## The negative cases, checked too
|
||||
|
||||
`docs/output/03-restclient-no-credentials-401.txt` and `04-restclient-wrong-password-401.txt`
|
||||
confirm what actually happens on the failure path: `retrieve()` throws
|
||||
`HttpClientErrorException.Unauthorized` on a 401, exactly like `RestTemplate` did -- this is the
|
||||
default `retrieve()` behaviour, not the `exchange()` behaviour covered in the next chapter.
|
||||
|
||||
## Going deeper
|
||||
|
||||
- [`RestClient` Javadoc](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html) (rel="nofollow")
|
||||
- Prev: [{noop} passwords](01-password-encoding.md)
|
||||
- Next: [The starter split, and the exchange() trap](03-starter-split-and-exchange-trap.md)
|
||||
Reference in New Issue
Block a user