I am currently configuring Swagger UI/OpenAPI 3 for my project, which uses Spring Boot and Kotlin. The update endpoints in my controllers include the ETag argument, which I send it to backend as If-Matcher.
I have added the ETag argument as an If-Match header to my request using the io.swagger.v3.oas.annotations.Parameter
annotation, as shown below:
@Parameter(`in` = ParameterIn.HEADER, name = "If-Match") eTag: ETag
And my endpoint looks like this:
@PutMapping("/books/{bookId}")
open fun updateBook(
projectId: BookId,
@RequestBody body: @Valid UpdateBookResource,
@Parameter(`in` = ParameterIn.HEADER, name = "If-Match") eTag: ETag
): ResponseEntity<BookResource> {
//
}
And this solution here works fine.
However, my issue is that I do not want to manually add the @Parameter() annotation to each update endpoint.
So I have an ETagArgumentResolver class to configure this Etag globally. My idea was to add the @Parameter() annotation to this class for global application. However, I have been unable to do so, and I would appreciate any assistance in this matter.
The following code snippet is my ETagArgumentResolver class:
import java.io.InputStream
import java.nio.charset.StandardCharsets.UTF_8
import org.springframework.core.MethodParameter
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpHeaders.IF_MATCH
import org.springframework.http.HttpInputMessage
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.lang.Nullable
import org.springframework.web.bind.support.WebDataBinderFactory
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.method.support.HandlerMethodArgumentResolver
import org.springframework.web.method.support.ModelAndViewContainer
class ETagArgumentResolver : HandlerMethodArgumentResolver {
override fun supportsParameter(parameter: MethodParameter) =
parameter.parameterType == ETag::class.java
override fun resolveArgument(
parameter: MethodParameter,
mavContainer: ModelAndViewContainer,
webRequest: NativeWebRequest,
binderFactory: WebDataBinderFactory
): ETag? {
val ifMatchHeader = webRequest.getHeader(IF_MATCH)
return if (ifMatchHeader.isNullOrBlank()) {
return if (parameter.hasParameterAnnotation(Nullable::class.java)) {
null
} else {
throw HttpMessageNotReadableException(
"Value for request header field '$IF_MATCH' is missing.", MyHttpInputMessage())
}
} else {
ETag.from(ifMatchHeader)
}
}
private class MyHttpInputMessage : HttpInputMessage {
override fun getBody(): InputStream = "".byteInputStream(UTF_8)
override fun getHeaders() = HttpHeaders()
}
}