Reputation: 51
I'm implementing an API-gateway for my rest microservice using Quarkus. I want to forward requests to another (Quarkus) rest-api. I'm trying to forward a POST request with multiform data. I'm expecting to get a 201 but I'm getting a 500 internal server error. RESTEASY throws the following error:
RESTEASY002020: Unhandled asynchronous exception, sending back 500: javax.ws.rs.ProcessingException: RESTEASY004655: Unable to invoke request: javax.ws.rs.ProcessingException: RESTEASY003215: could not find writer for content-type multipart/form-data type: org.acme.rest.client.multipart.MultipartBody
I've tried upgrading my Quarkus version from 1.4.2 to 1.5.2 because I saw the following issue: https://github.com/quarkusio/quarkus/issues/8223
Also tried Intellij invalidate cache/restart, re-import maven
Code
MultiPartBody:
package org.acme.rest.client.multipart;
import org.jboss.resteasy.annotations.providers.multipart.PartType;
import javax.ws.rs.FormParam;
import javax.ws.rs.core.MediaType;
public class MultipartBody {
@FormParam("sample_id")
@PartType(MediaType.TEXT_PLAIN)
public Long sampleId;
@FormParam("username")
@PartType(MediaType.TEXT_PLAIN)
public String username;
@FormParam("content")
@PartType(MediaType.TEXT_PLAIN)
public String content;
}
Interface:
package org.acme.rest.client;
import io.smallrye.mutiny.Uni;
import org.acme.rest.client.multipart.MultipartBody;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@RegisterRestClient
@Consumes(MediaType.MULTIPART_FORM_DATA)
public interface SocialService {
@POST
Uni<Response> create(@MultipartForm MultipartBody data);
}
Resource:
package org.acme.rest.client;
import io.smallrye.mutiny.Uni;
import org.acme.rest.client.multipart.MultipartBody;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/comments")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public class SocialResource {
@Inject
@RestClient
SocialService socialService;
@POST
public Uni<Response> create(@MultipartForm MultipartBody data) {
return socialService.create(data);
}
}
Test:
package org.acme.rest.client;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
@QuarkusTest
public class SocialResourceTest {
@Test
public void create(){
given().contentType("multipart/form-data")
.multiPart("sample_id", "1")
.multiPart("username", "testuser")
.multiPart("content", "test message")
.when()
.post("/comments")
.then()
.statusCode(201);
}
}
Upvotes: 5
Views: 6590
Reputation: 3588
The ProcessingException with message RESTEASY003215: could not find writer for content
indicates no serializer was bound for the request type. This usually means you're missing the rest client dependency needed for the type.
In your case that might be today (as of Quarkus 2.5.0)
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-multipart</artifactId>
</dependency>
Another possibility for this very same error is you're trying to implement a REST client with the reactive API and missing the reactive client API bindings. You can have both reactive and regular rest-client at the same time in your project.
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-reactive-jackson</artifactId>
</dependency>
It might seems unrelated because it brings the Json writers in that case, but the exception and error message you'll get is exactly the same.
Upvotes: 0
Reputation: 92
To fix this issue with Resteasy and quarkus, I had to add the MultipartFormDataWriter to resteasy client registry, this is my new code : Any question click connect to my twitter @AIDeveloper
MultipartFormDataOutput output = new MultipartFormDataOutput();
output.addFormData("file", fileInputStream, MediaType.APPLICATION_OCTET_STREAM_TYPE);
output.addFormData("status", "status1", MediaType.TEXT_PLAIN_TYPE);
Response uploadResponse = newClient()
.target(uploadUri)
.register(MultipartFormDataWriter.class)
.request()
.post(Entity.entity(output
, MediaType.MULTIPART_FORM_DATA_TYPE));
Upvotes: 4
Reputation: 1
I've had the same issue (could not find writer for content-type multipart/form-data). I solved it by making the MultiPartBody extend MultipartFormDataOutput
.
In your case this would be:
...
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
...
public class MultipartBody extends MultipartFormDataOutput {
...
}
I found this solution by looking at how Quarkus / Resteasy internally resolves the output writers. This is done in the resolveMessageBodyWriter()
method of org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl
. The relevant writer is org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataWriter
. There, the isWriteable()
method checks if MultipartFormDataOutput
is a superclass of your class (MultipartBody
).
However, I don't know why it works without extending MultipartFormDataOutput
in the Quarkus examples.
My Quarkus version is 1.8.2.Final and I use the io.quarkus.quarkus-resteasy-multipart
maven dependency, not org.jboss.resteasy.resteasy-multipart-provider
.
Upvotes: 0
Reputation: 151
Everything looks fine, but maybe you are missing this dependency
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
</dependency>
That info is available at this quarkus guide
Upvotes: 0