WireMock does not transform response - wiremock

I'm having an issue using WireMock, I've extended ResponseTransformer and implemented all required methods, it looks like this:
public class TempResponseTransformer extends ResponseTransformer {
#Override
public Response transform(Request request, Response response, FileSource fileSource,
Parameters parameters) {
return Response.Builder.like(response).but().status(404).body("1").build();
}
#Override
public boolean applyGlobally() {
return false;
}
#Override
public String getName() {
return "temp-response-transformer";
}
}
Now I want to apply this particular transformer to one of the stubs, that I wrote, stub looks like this:
private static void initTempStub() {
stubFor(post(urlPathEqualTo("/api/v1/temp"))
.withHeader("AccessToken", matching("[a-zA-Z0-9]+"))
.withHeader("CliendID", matching("[a-zA-Z0-9]+"))
.withHeader("ClientSecret", matching("[a-zA-Z0-9]+"))
.willReturn(aResponse()
.withTransformers("temp-response-transformer")));
}
When I start service and perform post calls I do see that transformer is applied, however responses actually not being transformed.
I've tried to apply transformer in config section when starting service as well, but it doesn't help.
So my question is how should I apply ReponseTransformer correctly so it would transform my responses?

Ok, think I've figured it out.
Here is an issue(?) with WireMock that I was able to figure out while looking at the internals, here is how I passed config:
new WireMockServer(wireMockConfig()
.extensions(TempResponseTransformer.class)
.options().notifier(new ConsoleNotifier(true)))
And an issue with this code is when you call options() from wireMockConfig it would create new instance of WireMockConfig, so I had to extract this config into separate piece of code like this:
var wireMockConfig = new WireMockConfiguration();
wireMockConfig
.extensions(SamplesResponseTransformer.class)
.notifier(new ConsoleNotifier(true));

Related

How to removing response header with a RestFilter

Is it possible to remove response headers with a RestFilter? Looking at this cookbook you would say it should be possible. However, the filter is only called when the request is incoming, before the call to the resource class. I was expecting to have a hook where I can modify the response headers before sending it back to the client.
i had a look at CORSFilter as an example, but it only sets headers, not remove them.
To be more specific, I want to remove the WWW-Authenticate header that is set by the Auth provider when the session has expired. This header causes a popup in the browser (chrome) that is undesirable.
what you need is a javax.ws.rs.container.ContainerRequestFilter. In jax-rs such filters can be registered in a javax.ws.rs.core.Application. The application used in ICM is com.intershop.component.rest.internal.application.DefaultRestApplication which can be adapted using an com.intershop.component.rest.internal.application.ApplicationClassesProvider that can be registered using a Set-Binding.
So you could create a Guice-Module and your filter:
public class MyRestModule extends AbstractModule
{
#Override
protected void configure()
{
Multibinder<ApplicationClassesProvider> binder = Multibinder.newSetBinder(binder(),
ApplicationClassesProvider.class);
binder.addBinding().toInstance(c->c.accept(MyResponseFilter.class));
}
}
public class MyResponseFilter extends ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
{
response.getHeaders().remove("WWW-Authenticate");
}
}
Please note that this filter will be applied to all requests, so please make sure you remove headers only for requests you really care about.

Dumping bad requests

I have a service implemented with Dropwizard and I need to dump incorrect requests somewhere.
I saw that there is a possibility to customise the error message by registering ExceptionMapper<JerseyViolationException>. But I need to have the complete request (headers, body) and not only ConstraintViolations.
You can inject ContainerRequest into the ExceptionMapper. You need to inject it as a javax.inject.Provider though, so that you can lazily retrieve it. Otherwise you will run into scoping problems.
#Provider
public class Mapper implements ExceptionMapper<ConstraintViolationException> {
#Inject
private javax.inject.Provider<ContainerRequest> requestProvider;
#Override
public Response toResponse(ConstraintViolationException ex) {
ContainerRequest request = requestProvider.get();
}
}
(This also works with constructor argument injection instead of field injection.)
In the ContainerRequest, you can get headers with getHeaderString() or getHeaders(). If you want to get the body, you need to do a little hack because the entity stream is already read by Jersey by the time the mapper is reached. So we need to implement a ContainerRequestFilter to buffer the entity.
public class EntityBufferingFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
ContainerRequest request = (ContainerRequest) containerRequestContext;
request.bufferEntity();
}
}
You might not want this filter to be called for all requests (for performance reasons), so you might want to use a DynamicFeature to register the filter just on methods that use bean validation (or use Name Binding).
Once you have this filter registered, you can read the body using ContainerRequest#readEntity(Class). You use this method just like you would on the client side with Response#readEntity(). So for the class, if you want to keep it generic, you can use String.class or InputStream.class and convert the InputStream to a String.
ContainerRequest request = requestProvider.get();
String body = request.readEntity(String.class);

FlatFileItemWriter write header only in case when data is present

have a task to write header to file only if some data exist, other words if reader return nothing file created by writer should be empty.
Unfortunately FlatFileItemWriter implementation, in version 3.0.7, has only private access fields and methods and nested class that store all info about writing process, so I cannot just take and overwrite write() method. I need to copy-paste almost all content of FlatFileItemWriter to add small piece of new functionality.
Any idea how to achieve this more elegantly in Spring Batch?
So, finally found a less-more elegant solution.
The solution is to use LineAggregators, and seems in the current implementation of FlatFileItemWriter this is only one approach that you can use safer when inheriting this class.
I use separate line aggregator only for a header, but the solution can be extended to use multiple aggregators.
Also in my case header is just predefined string, thus I use PassThroughLineAggregator by default that just return my string to FlatFileItemWriter.
public class FlatFileItemWriterWithHeaderOnData extends FlatFileItemWriter {
private LineAggregator lineAggregator;
private LineAggregator headerLineAggregator = new PassThroughLineAggregator();
private boolean applyHeaderAggregator = true;
#Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(headerLineAggregator, "A HeaderLineAggregator must be provided.");
super.afterPropertiesSet();
}
#Override
public void setLineAggregator(LineAggregator lineAggregator) {
this.lineAggregator = lineAggregator;
super.setLineAggregator(lineAggregator);
}
public void setHeaderLineAggregator(LineAggregator headerLineAggregator) {
this.headerLineAggregator = headerLineAggregator;
}
#Override
public void write(List items) throws Exception {
if(applyHeaderAggregator){
LineAggregator initialLineAggregator = lineAggregator;
super.setLineAggregator(headerLineAggregator);
super.write(getHeaderItems());
super.setLineAggregator(initialLineAggregator);
applyHeaderAggregator = false;
}
super.write(items);
}
private List<String> getHeaderItems() throws ItemStreamException {
// your actual implementation goes here
return Arrays.asList("Id,Name,Details");
}
}
PS. This solution assumed that if method write() called then some data exist.
Try this in your writer
writer.setShouldDeleteIfEmpty(true);
If you have no data, there is no file.
In other case, you write your header and your items
I'm thinking of a way as below.
BeforeStep() (or a Tasklet) if there is no Data at all, you set a flag such as "noData" is 'true'. Otherwise will be 'false'
And you have 2 writers, one with Header and another one without Header. In this case you can have a base Writer acts as a parent and then 2 writers inherits it. The only difference between them is one with Header and one doesn't have HeaderCallBack.
Base on the flag, you can switch to either 'Writer with Header' or 'Writer without Header'
Thanks,
Nghia

Jackson and REST Android Annotations: Deserialize JSON Array of Objects

I have a REST service which returns data that looks like this:
[
{ bookmark object json here },
{ bookmark object json here },
{ bookmark object json here },
...
]
My REST client class looks like this:
#Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
#Get("/bookmark/read?id={identifier}")
public BookmarkList getBookmarks(String identifier);
}
BookmarkList looks like this:
public class BookmarkList {
List<Bookmark> bookmarks;
#JsonValue
public List<Bookmark> getBookmarks() {
return bookmarks;
}
#JsonCreator
public void BookmarkList(#NotNull List<Bookmark> bookmarks) {
this.bookmarks = bookmarks;
}
}
However, when I utilize this setup, I get the following error:
Could not read JSON: Can not deserialize instance of com.whatever.entity.BookmarkList out of START_ARRAY token
What I want is something like the EventList example at https://github.com/excilys/androidannotations/wiki/Rest-API#get, but that doesn't seem to work for me out of the box.
Is there a way to get this working?
Ho... We have to update this part of documentation. The wrapper solution works but doesn't fit APIs.
If you're looking at the generated code for #Get("url") MyReturnedType testService(), you should see something like this :
return restTemplate.exchange(rootUrl.concat("url"), //
HttpMethod.GET, //
null, //
MyReturnedType.class, //
urlVariables)//
.getBody();
The returned class is injected as a parameter of exchange call. In case of generics collection (like List<MyReturnedType>), we can't inject List.class because of type checking in the return of exchange method.
However, you should be able to use this little trick in your #Rest annotated method :
public class BookmarkList extends List<Bookmark> {
}
I think I misunderstood the example at https://github.com/excilys/androidannotations/wiki/Rest-API#get. I think the array still must be wrapped inside a JSON object in that example (It'd be nice if they included example JSON data).
The data the service I'm connecting to does not return an object wrapping the array like that, so, I altered the REST client to look like this:
#Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
#Get("/bookmark/read?id={identifier}")
public ArrayNode getBookmarks(String identifier);
}
And I wrote a method in another class to iterate the ArrayNode and build the bookmarks:
public List<Bookmark> getBookmarks(Content content) {
ArrayList<Bookmark> bookmarks = new ArrayList<Bookmark>();
ArrayNode bookmarksData = apiClient.getBookmarks(content.getAcid());
for(JsonNode bookmarkData : bookmarksData) {
Bookmark bookmark = objectMapper.convertValue(bookmarkData, Bookmark.class);
bookmarks.add(bookmark);
}
return bookmarks;
}
So it's not as convenient (I had to write more code myself), but I got it working.

extracting the complete envelope xml from MessageContext

I have an interceptor like this:
public class WebServiceInterceptor extends EndpointInterceptorAdapter {
#Inject
private Jaxb2Marshaller myJaxb2Marshaller;
#Inject
private WebServiceHistoryDao webServiceHistoryDao;
#Override
public boolean handleRequest(MessageContext messageContext, Object endpoint)
throws Exception {
Source payloadSource = messageContext.getRequest().getPayloadSource();
Object unmarshaled = myJaxb2Marshaller.unmarshal(payloadSource);
//EXTRACT XML HERE
//is there a better way than this:
String extractedXml = myJaxb2Marshaller.marshal(unmarshaled);
return true;
}
}
How can i extract the whole xml of envelope (for logging purposes - to write it to the DB)
You don't need to write one, there's an existing one in the API - SoapEnvelopeLoggingInterceptor. See the javadoc.
SOAP-specific EndpointInterceptor that logs the complete request and response envelope of SoapMessage messages. By default, request, response and fault messages are logged, but this behaviour can be changed using the logRequest, logResponse, logFault properties.
If you only need to see the payload, rather than the entire SOAP envelope, then there's PayloadLoggingInterceptor.