Wiremock: choose body file name based on request parameter - wiremock

I am using wiremock to mock http server and I am returning responses from json files (using withBodyFile method).
Now I want to choose and return response json file based on request parameter. For the example below, I want to define one stub so that the body file is chosen based on request parameter.
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key1"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key1.json")
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key2"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key2.json")
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key3"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_key3.json")
Any idea how this would be possible? I tried defining transformer but it was not possible to get Stream Source Path from Response object in overridden method so can't use that appraoch. Thanks a lot..

Body File name can't be parameterized in wiremock as of now. I had a similar requirement, I needed to return the file based on the request URL. So I implemented a transformer as below:
public class BodyFileNameResponseTransformer extends ResponseDefinitionTransformer {
public ResponseDefinition transform(Request request, ResponseDefinition rd,
FileSource fileSource, Parameters parameters) {
if (rd.getBodyFileName().startsWith("{{")) {
return new ResponseDefinitionBuilder().**withBodyFile**(request.getUrl().substring(1))
.withStatus(rd.getStatus())
.withHeaders(rd.getHeaders())
.withTransformers(
rd.getTransformers().toArray(new String[rd.getTransformers().size()]))
.build();
}
return rd;
}
public String getName() {
return "BodyFileNameTransformer";
}
}
you can use request.queryParameter(key) instead of request.getUrl() and form any
file path. Create the file path based on your need and set it as bodyFile on returned ResponseDefinition.
Don't forget to start wiremock with --extensions: Extension class names
More details at Extending Wiremock

This is possible by using the inbuilt template helpers provided by Handlebar.
myMockServer.stubFor(
get(urlEqualTo(myEndPoint+ "?key=key3"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json")
.withBodyFile("response_{{request.query.key}}.json")
Check for the various models available at http://wiremock.org/docs/response-templating/.

Related

ASP.NET Core 6 - Use URI's extension to get Accept header value

I'm migrating an application from NancyFx to Kestrel in ASP.NET Core 6.
In Nancy, you could specify the Accept value in the URI. For example, these Uris:
http://localhost:5000/my/resource.json
http://localhost:5000/my/resource.protobuf
http://localhost:5000/my/resource.xml
Would be the equivalent of setting the Accepts header to application/json, application/protobuf or application/xml respectively.
Does this exist in Kestrel? I remember finding one example, long ago, of regex-ing the route and doing it somewhat manually. But
I can't find that post again, and
If I have to do that, I'm not sure I want to :)
Is there a way to configure this behavior in ASP.NET Core 6?
The object returned from my handler in the controller is already capable of being serialized to json/xml/whatever. I just need to check the URI to set the content-type of the response so the correct formatter will be invoked.
At the moment, I have a client that will speak to both Nancy and Kestrel and it was written to use the URI to get the type. I'm fine to rewrite/update the client so it will use the Accept header. But getting the URI method to work will make the initial integration easier and a refactor to use the headers can come next.
I created a very simple middleware that reads the accept value from the query string and sets the Accept header to the request:
public class AcceptHeaderFromQueryString
{
private readonly RequestDelegate _next;
public AcceptHeaderFromQueryString(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var accept = context.Request.Query["accept"];
if (!string.IsNullOrEmpty(accept))
{
context.Request.Headers.Accept = accept;
}
await _next(context);
}
}
Register the middleware:
app.UseMiddleware<AcceptHeaderFromQueryString>();
I added [Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)] attribute to my api controller action (this step is not required):
[HttpGet]
[Produces(MediaTypeNames.Application.Json, MediaTypeNames.Application.Xml)]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
Finally I added support for xml serialization in Program.cs:
builder.Services.AddControllers()
.AddXmlDataContractSerializerFormatters();
Then I tried these urls and they both gave appropriate response:
https://localhost:7258/weatherforecast?accept=application/json
https://localhost:7258/weatherforecast?accept=application/xml
You possibly want the [Consumes] attribute. This allows you to specify a controller action that only gets called from a route of the specified content type.
Obviously this is not using the Accepts header but the content type of the request.

Setting headers and content length and mediatype in a Quarkus REST-SErvice

I'd like to migrate a JAX-RS-REST-Restservice (running under Tomcat) to Quarkus.
I could solve most of my problems along the way but I still have a problem with one method.
In this function I do a OTA-download (firmware for a device). I set some headers and the MediaType and the content length.
In the original service my code looked as follows:
public HomeAutomationService
{
...
#Context
private HttpServletRequest request;
...
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#Path("/v1/DownloadFirmware")
public Response getFirmware()
{
...
response.setHeader("X-OTA-SIGNATURE", signatureString);
response.setContentLength((int) file.length());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM).build();
}
}
Unfortunately I can't find anything like a HttpServletResponse in Quarkus.
So I now use a ResponseBuilder to create a Response, where I can add headers as needed:
ResponseBuilder responseBuilder;
However, I am not sure how to instantiate the ResponseBuilder. There is a method to set headers for the ResponseBuilder, but I did not find anything on how to the content length and the content type.
I am not sure if I have to set the content-type since I already use a #Produces-annotation - but what about the content length? Is it set automatically? If no (that's what I guess) how can I set it correctly?
Thanks for reading and answering,
Rudi
You don't need to use #Produces in this case and your return should be something like the code below:
return Response.ok(yourFileBytes[])
.type(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_LENGTH, <yourFileLength>)
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; ")
.build();
The code above can be written as:
ResponseBuilder resp = Response.ok(yourFileBytes[]);
resp.type(MediaType.APPLICATION_OCTET_STREAM);
resp.header(HttpHeaders.CONTENT_LENGTH, <yourFileLength>);
resp.header(HttpHeaders.CONTENT_DISPOSITION, "inline; ");
return resp.build();

Is it possible for a restful webservice to have a parameter in the url?

I was instructed to create webservices ( with Spring-Boot ). My colleague gave me the url of the webservice and it looks like this : http://172.20.40.4:8080/Oxalys_WS/stock/ITM=1559
In general we create a RestController with the url :
#RestController
#RequestMapping("stock")
public class StockController {
#Autowired
private StockService stockService;
#GetMapping(value = "/{code}", produces = "application/json")
public JsonModel getByCode(#PathVariable String code) {
JsonModel jsonModel = new JsonModel();
final Map<String, Object> data = new HashMap<>();
List<Stock> stock = stockService.getByCode(code);
data.put("stock", stock);
data.put("stockTotal", stockService.getTotal(code));
jsonModel.setDatas(data);
return jsonModel;
}
}
So is it normal to create a Restful Spring-Boot webservice with a parameter in the url ?
Spring provides parameter in two standard way.
Query Param : http://172.20.40.4:8080/Oxalys_WS/stock?ITM=1559
Path Variable : http://172.20.40.4:8080/Oxalys_WS/stock/1559
Query Param :- It is a typical old way to pass some value as QueryParam with using of some variable starts with ?(Question Mark) and value is assigned using =(equals).
PathVariable :- this is a newer pattern introduce for REST-api Services. URL must be structured such in a way that this should not look too messy if multiple parameters need to pass within a URL.
For more info Navigate this link
Yes, you can have the one in your URL
When you are required to have the path variable, you can give in the Request URL

#BeanParam gives exception A message body reader for Java class was not found

I am trying to make a jersey based web service. In this if i take input params using #FormParam it works fine:
#POST
#Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, "application/x-www-form-urlencoded"})
#Path("/registeruser")
public Response registerUser(#FormParam ("email") String email,#FormParam ("name") String name ){
System.out.println("Inside register device");
System.out.println("registered" + email);
return null;
}
but when I try using #BeanParam it does not works and gives me an exception
#POST
#Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, "application/x-www-form-urlencoded"})
#Path("/registeruser")
public Response registerUser(#BeanParam UserForm userForm ){
System.out.println("Inside register device");
service.registerUser(userForm);
System.out.println("registered" + userForm.getEmail());
return null;
}
A message body reader for Java class com.stc.dms.forms.UserForm, and Java type class com.stc.dms.forms.UserForm, and MIME media type application/octet-stream was not found.
You don't need to use #BeanParam to pass an object as input. Just pass it like this :
#POST
#Path("register")
#Consumes(MediaType.APPLICATION_JSON)
public Response registerUser(UserForm dto) {
// ...
}
Just make sure to include the libraries for producing/consuming json. If the client is in javascript you don't need anything else (just use JSON.stringify() on your form object), for the server add some json libraries such as Jackson
EDIT :
If you want to stick with #BeanParam, take a look at this tutorial here. Basically it seems that you don't need to specify the mediatype, as Jersey will handle that for you.

jaxrs/resteasy custom method paramater

I would like to have my JaxRs resource to take a custom method argument that is built from some parameter in the request.
Something to be used in conjunction with another object created from the body.
Something like:
#Resource
public class MyResource {
#Path("/resource")
public Object resource(MyResourceDTO body, AConfiguration conf){
}
}
For which the AConfiguration is created from some headers in the request.
How can I achive it?
I need something like th spring webargumentresovler: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/support/WebArgumentResolver.html
For my case MyResource is a subresource, the method should work also in this case...
If you add a DTO as parameter of your resource method your JAX-RS runtime will try to convert the body of the request into this type. You can additionally add any of the #xParam parameters like #QueryParam as parameters of your resource method. (The only exception is #FormParam as they are found in the body).
If you want to encapsulate multiple of your Params in one object you can use #BeanParam. Your Configuration class could look like this:
public class Configuration {
#QueryParam("foo")
private String foo;
#HeaderParam("bar")
private String bar;
// getters + setters
}
And can be used like this:
#POST
public Response someMethod(Dto dto, #BeanParam Configuration conf) {}
You can use something like below. Your conf object have be sent as json from the client. If the parameters in conf object have to change dynamically you have to follow the second approach.
#Resource
public class MyResource {
#POST
#Consumes("application/json")
#Path("/resource")
public Object resource(AConfiguration conf){
// This method can receive multiple objects here. Currently it receives
// conf object only as the payload of the post method.
}
}
To change the conf object dynamically, You can send json String.
public Object resource(String confJson){
// Collect parameters manually here.
}
In your pom.xml, you should include,
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>2.3.1.GA</version>
</dependency>
Edit:
You can set a json string as a header param (But, not the best practice.) Or you can set different headers at you will and access them using HttpHeaders. Here is an example.
public Object resource(#Context HttpHeaders confHeaders){
// Collect parameters manually.
String confJson = confHeaders.getRequestHeader("confJson").get(0);
// cast your `confJson` to `AConfiguration aConf` here.
// process query params and set them to aConf here.
}