WebClient upload file - spring-boot

I tried to upload a file using webclient like below
val builder = MultipartBodyBuilder()
builder.part("file", ByteArrayResource(multipartFile.bytes)).filename(multipartFile.name)
webClient.post().uri(applicationProperties.uploadFile)
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve()
.bodyToMono(UploadImageResponse::class.java)
but i have this error
{"timestamp":"2023-01-18T10:21:30.684+0000","status":415,"error":"Unsupported
Media Type","message":"Content type
'multipart/form-data;charset=UTF-8;boundary=jyVJSdCWsbbhz_2obRp_ZBwOtuzLG9yaLl'
not supported","path":"/api/ged/upload-file"}

Related

Spring-boot Api endpoint for uploading file not working after adding 'spring-boot-starter-hateoas' dependency

I have a simple API function to upload a file similar to:
#PostMapping(value = "/documents",
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public Mono<ResponseEntity<String>> uploadDocument(#RequestPart Mono<FilePart> file){
return storeDocumentService
.upload(file)
.map(fileLocation->ResponseEntity.ok(fileLocation))
}
The code works ok and uploads the file. The problem comes when I want to make the response a bit better by returning the link to the uploaded file. For this I want to use HATEOAS 'org.springframework.boot:spring-boot-starter-hateoas'. As soon as I add the dependency 'org.springframework.boot:spring-boot-starter-hateoas' to my 'build.gradle' the endpoint stops working and I get a response:
{
"timestamp": "2023-02-20T04:28:10.620+00:00",
"status": 415,
"error": "Unsupported Media Type",
"path": "/documents"
}
and also I get in the logs:
2023-02-20T05:28:10.618+01:00 WARN 2993 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/pdf' is not supported]
It is important to point out that I upload a ".pdf" file with a header "Content-Type:multipart/form-data". And most important the only change in the working code and not working code is that i just add the dependency for HATEOAS 'org.springframework.boot:spring-boot-starter-hateoas'
For Uploading File We can easily use the type MultiPartFile , This will handles all the types of files and we can easily retrive the fileInputStream(data) from it.
The following code may helps you!..
#PostMapping("uploadExcelData")
public ResponseEntity<?> uploadExcelData(#RequestParam MultipartFile file) throws IOException {
List<...> dataList = fileHandling.convertFileAsJson(file);
if (!dataList.isEmpty()) {
return ....
} else {
return ResponseEntity.ok("No Records found !!");
}
}
I hope the above code will helps you to handle the File in the Endpoint.

how to retrieve the same error response received by webclient in spring reactive

I reveive a request from client, and to process that I have to make request to azure resource management app.
Now, if the client passes me incorrect info, and if I make direct call from postman to azure API, it returns me very useful info. refer below (below call contains incorrect query params) :
i get response like below in case of incorrect param passed :
{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.MachineLearningServices/workspaces/workspace_XYZ/onlineEndpoints/Endpoint_XYZ' under resource group 'resourceGroupXYZ' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix"
}
}
Now, I make this query using springboot reactive webclient API.
But I am not sure how to pass the same error back as it contains very useful info. The exception handling methods calls like onErrorReturn etc did not help me here to get the original error msg. :
response = getWebClient()
.post()
.uri(apiUrl)
.headers(h -> authToken)
.retrieve()
.bodyToMono(String.class)
// .onErrorReturn(response)
.block();

How to perform a file upload to REST service?

I have the following method in the Spring REST controller
#PostMapping("/uploadFile", consumes=["multipart/form-data"])
fun uploadFile(#RequestParam("fileType") fileType: FileType?,
#RequestParam("fileContentType") fileContentType: FileContentType?,
#RequestParam("projectId", required=false) projectId: UUID?,
#RequestParam("fileId", required = false) fileId:UUID?,
#RequestParam("description", required=false) description: String?,
#RequestParam("file") file: MultipartFile): UUID {
My objective is to test this service. I need to upload a file and in the same time give to service wrong "fileId", then parse ErrorMessage. Please tell me how to perform such request? What should I use JAX-RS? ResteasyClient? I have tried ResteasyClient
val inputStream: InputStream = Thread.currentThread().contextClassLoader.getResourceAsStream("application.properties")
val upload = MultipartFormDataOutput()
upload.addFormData("file", inputStream, MediaType.MULTIPART_FORM_DATA_TYPE, "mytarfile.tar")
var request = ClientRequest("http://localhost:$port/api/v1.0/files/uploadFile")
request.formParameter("fileId","test")
request.header("Authorization", "Bearer $accessToken")
request.body(MediaType.MULTIPART_FORM_DATA_TYPE, upload)
val response = request.post(String::class.java)
but it doesn't work
java.lang.RuntimeException: RESTEASY003100: You cannot send both form parameters and an entity body
Moreover ClientRequest is depricated and it is recommended to move to JAX-RS 2.0, could you tell me how to do that??

WebTestClient with multipart file upload

I'm building a microservice using Spring Boot + Webflux, and I have an endpoint that accepts a multipart file upload. Which is working fine when I test with curl and Postman
#PostMapping("/upload", consumes = [MULTIPART_FORM_DATA_VALUE])
fun uploadVideo(#RequestPart("video") filePart: Mono<FilePart>): Mono<UploadResult> {
log.info("Video upload request received")
return videoFilePart.flatMap { video ->
val fileName = video.filename()
log.info("Saving video to tmp directory: $fileName")
val file = temporaryFilePath(fileName).toFile()
video.transferTo(file)
.thenReturn(UploadResult(true))
.doOnError { error ->
log.error("Failed to save video to temporary directory", error)
}
.onErrorMap {
VideoUploadException("Failed to save video to temporary directory")
}
}
}
I'm now trying to test using WebTestClient:
#Test
fun shouldSuccessfullyUploadVideo() {
client.post()
.uri("/video/upload")
.contentType(MULTIPART_FORM_DATA)
.syncBody(generateBody())
.exchange()
.expectStatus()
.is2xxSuccessful
}
private fun generateBody(): MultiValueMap<String, HttpEntity<*>> {
val builder = MultipartBodyBuilder()
builder.part("video", ClassPathResource("/videos/sunset.mp4"))
return builder.build()
}
The endpoint is returning a 500 because I haven't created the temp directory location to write the files to. However the test is passing even though I'm checking for is2xxSuccessful if I debug into the assertion that is2xxSuccessful performs, I can see it's failing because of the 500, however I'm still getting a green test
Not sure what I am doing wrong here. The VideoUploadException that I map to simply extends ResponseStatusException
class VideoUploadException(reason: String) : ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, reason)

Upload APK file via Gradle/Groovy Multipart Request task

I'm trying to implement a gradle task to upload an APK file to my web service using http-builder-ng. I'm struggling with the encoding part.
An APK file effectively is a ZIP format file, so I tried using the content type application/zip but it's not recognized by the encoders provided:
task publish(...) {
// ...
post {
request.contentType = 'multipart/form-data'
request.encoder 'multipart/form-data', OkHttpEncoders.&multipart
request.body = multipart {
part 'file', 'myApp.apk', 'application/zip', new File(System.getProperty('user.dir'), 'myApp.apk')
}
response.success { fs, content ->
prinln "success"
}
}
}
The error message is following:
Could not find encoder for content-type (application/zip)
Can anybody help me which encoder to use and how?

Resources