Vertx POST HttpClientRequest with body parameter - vert.x

I have to implement a Vertx POST request. Via Postman, the request is done as shown in the following picture:
The tricky part is that the server expects the key "upgrade_file" for the body. I could not find out how to do that with Vertx. This is what I have so far:
Buffer bodyBuffer = Buffer.buffer(body); // body is byte[]
HttpClientRequest request = ...
request.handler( response -> ...
request.end(bodyBuffer);
How can I set "upgrade_file" as the key for the body?

Use a WebClient instead of the HTTP client, it provides dedicated support for submitting forms.
WebClient client = WebClient.create(vertx);
or if you already have created an http client:
WebClient client = WebClient.wrap(httpClient);
Then create the form data as map and send the form using a the right content type
MultiMap form = MultiMap.caseInsensitiveMultiMap();
form.set("upgrade_file", "...");
// Submit the form as a multipart form body
client.post(8080, "yourhost", "/some_address")
.putHeader("content-type", "multipart/form-data")
.sendForm(form, ar -> {
//do something with the response
});
More example see https://vertx.io/docs/vertx-web-client/java/

If you want to send files, the simplest way is using the sendMultipartForm method of Vertx WebClient.
Create a Multipartform firstly.
MultipartForm form = MultipartForm.create()
.attribute("imageDescription", "a very nice image")
.binaryFileUpload(
"imageFile",
"image.jpg",
"/path/to/image",
"image/jpeg");
Then invoke WebClient.sendMultipartForm(form) to send the request.
The generic Vertx HttpClient is a low-level API, you should searialize the form data into a string or buffer, the format is similar to this example file in Vertx GraphQL testing codes. Then send the buffer to the server side.

Related

Feign REST Client: How to get the HTTP status?

I have Feign client setup with Hystrix and I am trying to log all the HTTP status codes that I get from my API calls into a database. So this means, if one of my calls give me a 201, I would want to log that into DB. If my call results in a failure, my fallback handler can obviously log that but I want to do the DB inserts in one place. Does feign have a way to get access to responses or some kind of general callback?
You have to provide custom decoder to get your response in ResponseEntity<Object>.
NotificationClient notificationClient = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(customDecoder())
.target(Target.EmptyTarget.create(NotificationClient.class));
Here you define your custom decoder bean. You can define your own by implementing Decoder but I'm using spring decoder.
#Bean
public Decoder customDecoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper());
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
Now collect your response in ResponseEntity<Object>
ResponseEntity<Object> response = notificationClient.notify();
int status = response.getStatusCodeValue();
Another option is to create your own feign.Logger implementation, overriding the logAndRebufferResponse method:
protected Response logAndRebufferResponse(
String configKey, Level logLevel, Response response, long elapsedTime);
This may be simpler than creating a Decoder and is guaranteed to be called when a response is received regardless of status. Decoders are only called if the request does not trigger an error.

Using SOAPUI as a kind of gateway

I want to ask you if it is possible in SOAPUI to alter a mock response, and link it to the real web service operation in which the MockService is based on.
I need to do that because within SOAPUI I can reach to external webservices; BUT for security/configuration reasons, I can’t access to this external webservices inside my local code in my Eclipse (I have tried several proxy configurations in my Eclipse without success).
What I want to do is to pass the request that reach to the mock service to the original web service and return the response without manipulation.
You can create a mockService in SOAPUI to redirect your request to a 3rd party service as follows:
First creat a mockService in your project: right click on your project > New SOAP MockService
Then creat a mockOperation on it: right click on your MockService > New MockOperation
Inside your mockOperation there is a request created, open it an put for example the follow code as a response: ${myResponse}. This name is bind to a variable which will fill then with a script.
Finally open your mockOperation and use the follow script to hit your 3rd party service redirecting the original request:
final HttpURLConnection connection = 'http://yourService:8080'.toURL().openConnection()
connection.setDoOutput(true)
// copy the headers
mockRequest.getRequestHeaders().each { name, value ->
connection.setRequestProperty(name,value.toString())
}
// write the request
connection.outputStream.withWriter { Writer writer ->
writer << mockRequest.requestContent
}
// get the response
String response = connection.inputStream.withReader { Reader reader -> reader.text }
// set the response in your variable
requestContext.myResponse = response
Hope this helps,
I finally did it turning 'Dispatch' to SCRIPT and adding this script:
// import all the namespaces to trim the lines of codes
import com.eviware.soapui.impl.wsdl.WsdlProject
import com.eviware.soapui.impl.wsdl.WsdlInterface
import com.eviware.soapui.impl.wsdl.WsdlRequest
import com.eviware.soapui.impl.wsdl.WsdlSubmitContext
import com.eviware.soapui.impl.wsdl.WsdlSubmit
import com.eviware.soapui.model.iface.Response
import com.eviware.soapui.model.mock.MockResponse
// get reference to project
WsdlProject project = (WsdlProject)mockOperation.mockService.project
// get reference to request
WsdlRequest request = (WsdlRequest)project.interfaces["TheRealWebService"].operations["TheRealOperation"].getRequestByName("TheRealRequest")
// set request content from incoming mockRequest
request.setRequestContent(mockRequest.getRequestContent())
// submit request asynchronously
WsdlSubmit submit=request.submit( new WsdlSubmitContext( request ), false )
// wait for the response
Response response = submit.getResponse();
// get reference to MockResponse
MockResponse mockResponse=mockOperation.getMockResponseByName("Response1")
// set the mock response content from response received by the request.
mockResponse.setResponseContent(response.getContentAsString())

Web API calls with RestSharp - prepends application/json to body causing null parameter on action

I have a Web API service that I'm trying to access via the console using RestSharp. My RestSharp code looks like this:
RestClient client = new RestClient(baseUrlString);
RestRequest request = new RestRequest("controllername/actionname");
request.RequestFormat = DataFormat.Json;
ProcessQuestion model = new ProcessQuestion()
{
Id = "123456",
InstanceId = "123",
UniqueId = "bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626",
PostedAnswer = new Dictionary<string, string>() { { "question_7907_1", "selected" }, { "question_7907_2", "selected" } }
};
request.AddBody(model);
var response = client.Execute(request)
My Web API action takes a model that has the same parameters as the above model. When the call executes, the binding fails and the parameter is null. I suspect this is due to the RestRequest.AddBody method prepending application/json to the body value as shown below:
{application/json={"Id":"123456","InstanceId":"123","UniqueId":"bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626","PostedAnswer":{"question_7907_1":"selected","question_7907_2":"selected"}}}
If I post using Fiddler the body binds to the model properly. Below is the body value I provided in Fiddler:
{'Id':'123456','InstanceId':'123','Uniqueid':'bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626','PostedAnswer':{'question_7907_1':'selected','question_7907_2':'selected'}}
Note that the body value in fiddler is the same with the exception of prepending the application/json key.
Also to note: I've tried what seems like everything...I've separated the parameters out in the action, used FromBody and FromUri attributes, tried custom DictionaryModelBinder's, tried custom ValueBinders, tried changing the way I'm using RestSharp (AddParameter with a RequestBody parameter, AddObject, different URL styles, etc.).
Has anyone else encountered this, and if so, did you solve it? I chose Web API for this service with hopes the model binding would work as it does in MVC, but I'm seeing that isn't the case.
Thanks
EDIT (resolved):
RestSharp automatically uses the JsonSerializer for objects passed in the AddBody method. I figured I was missing something simple, and indeed I was... Adding the Method.Post parameter to the RestRequest instantiation solved the problem.
Specify the method when creating the request:
RestRequest request = new RestRequest("controllername/actionname", Method.POST);
Not sure what the default serializer is for body - you can try making it explicit:
request.AddBody(request.JsonSerializer.Serialize(model));
I'm not sure where the 'application/json' is coming from - that's the Content-Type header you should be sending with your request, definitely not part of the body. So do this instead:
request.AddHeader("Content-type", "application/json; charset=utf-8");
If this doesn't help, try making your code as similar to the example on their site as possible. Try removing complexity (even if it means changing the required functionality) - get it to a point when it works and build additional functionality on that.
http://restsharp.org/

Auto-generating a WebRequest

I am trying to consume a binary stream from a ServiceStack service, as described here:
How to consume a file with a ServiceStack client
I realize that I must use a custom WebClient, since I want direct access to the response stream. However, I would still like to avoid making this client by hand. Instead, I'd like to write something like,
var webClient = new JsonServiceClient(baseUrl)
.ConfigureWebClient(new MyRequestDto { Foo = "bar" }));
This way, I wouldn't have to assemble the URL and query string by hand; and when I change my request DTO, I wouldn't have to remember to change my custom WebClient setup code, either.
Is there a way to accomplish this, somehow ? I've looked at ServiceClientBase.PrepareWebRequest(...), and it does a whole lot of useful stuff that I don't feel like copy/pasting into my own code. I'd love to inherit ServiceClientBase and call that method directly, but it's private, so I can't. Anyone got any other ideas ?
All of ServiceStack's C# Service Clients have both a Global and a Local Request Filter allowing you to initialise the Request and Global and Local Response Filters allowing fine-grained access to the returned HttpWebResponse.
Initializing the WebRequest of all ServiceClients using a Global Request Filter:
ServiceClientBase.HttpWebRequestFilter = httpReq => ConfigureWebClient(httpReq);
Using the Local Request Filter:
var client = new JsonServiceClient(baseUrl) {
LocalHttpWebRequestFilter = httpReq => ConfigureWebClient(httpReq)
};
Although if you just want the binary response All Service Clients allow you to specify either a string, byte[], Stream or HttpWebResponse as your Generic Response type and it will return what was requested. See the Service Client wiki page for more examples of these.
Here's how you can retrieve binary responses:
byte[] responseBytes = client.Get<byte[]>("/poco/World");
var dto = responseBytes.FromUtf8Bytes().FromJson<PocoResponse>();
Or with a Stream:
using (Stream responseStream = client.Get<Stream>("/poco/World")) {
var dto = responseStream.ReadFully().FromUtf8Bytes().FromJson<PocoResponse>();
}
Or from the underlying HttpWebResponse:
HttpWebResponse webResponse = client.Get<HttpWebResponse>("/poco/World");
using (var stream = webResponse.GetResponseStream())
using (var sr = new StreamReader(stream)) {
var dto = sr.ReadToEnd().FromJson<PocoResponse>();
}
You can change Open Source Software, you don't have to work around it
ServiceStack is Open Source software, there's no need to look for hacks or try to work around something that's not accessible or not available, make a pull-request to change what you want and if it's a valid request for a common use-case it will likely be accepted. Otherwise feel free to take a fork of the Source code and customize it as you wish.

RestSharp Usage

Recently I was using RestSharp to consume my Restful Resouce. and expected exchanging data with JSon between server and client. Below is my C# code.
var client = new RestSharp.RestClient();
var request = new RestRequest(sUrl,Method.POST);
request.RequestFormat = DataFormat.Json;
request.Timeout = TIME_OUT_MILLISECONTS ;
request.AddHeader("Content-Type", "application/json");
request.AddBody(new { appID = sAppId, loginName = sUserName, password=sPassword });
var response = client.Execute(request);
string s=response.Content;//It is always XML format.
The result is not what I expected for(Json data format), although I had set the RequestFormat Json and add Http header Content-Type. So I decided to use the .Net Reflector to found out What happened in the RestClient.Execute method. Here is the code of the method.
public RestClient()
{
...
this.AddHandler("application/json", new JsonDeserializer());
this.AddHandler("application/xml", new XmlDeserializer());
this.AddHandler("text/json", new JsonDeserializer());
this.AddHandler("text/x-json", new JsonDeserializer());
this.AddHandler("text/javascript", new JsonDeserializer());
this.AddHandler("text/xml", new XmlDeserializer());
this.AddHandler("*", new XmlDeserializer());
...
}
I have some questions about it:
As the RestClient adds many kinds of Content-Type into the HttpWebRequest. Is it right way to build a Request? And I think Maybe that is the reason why Response.Content always XML.
I don't know why the RestClient needs to build a HttpWebRequest like that. Any meaning to do that?
If we specified both JSon and XMl message format in a Http Request, which one works finally? Is it allowed?
Thanks. Have a good day.
RestSharp will use the correct handler based on the content type of the response. That's what those AddHandlers are doing; its configuring the RestClient to accept certain content types in the response and mapping those types to deserializers. Normally you would want to set an accept header for the json content type which notifies the server to send json in the response.
request.AddHeader("Accept", "application/json")
Of course, this assumes that the server you are hitting is configured to respond with json.