Micronaut rules for choosing between multiple possible endpoints? - java

What rules does Micronaut use to decide between the following 2 endpoints when responding to a HTTP request?
#Get(value = "/{param1}/{param2}/{param3}")
public HttpResponse<?> getSomething(String param1, String param2, String param3){
....
}
#Get(value = "/{param1}/not_a_param1/not_a_param2")
public HttpResponse<?> getSomethingElse(String param1){
....
}
A request GET /hello/not_a_param1/not_a_param2 could match to either endpoint - how does Micronaut decide which one is right? (From testing I've done Micronaut seemed inconsistent, sometimes choosing one or the other, and never giving the 'More than 1 route matched the incoming request' error message listed here).
I'm testing against Micronaut 3.2.0. Googling hasn't come up with any obvious answer.

Related

What is wrong with my PACT Test and how to fix it?

I am writing a Pact Consumer and Provider Test .
Basically I have 3 problems at the moment.
#Pact(provider = PROVIDER, consumer = CONSUMER)
public RequestResponsePact getAddress(PactDslWithProvider builder) {
PactDslJsonBody body = new PactDslJsonBody()
.stringType("key1", "73501")
.stringType("key2", "value");
final Map<String,String> headers = new HashMap<>();
headers.put("Authorization","Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1");
return builder
.given("Something.")
.uponReceiving("Dto")
.path("/amz/ags")
.query("code=9999")
.method("GET")
.headers(headers)
.willRespondWith()
.status(200)
.body(body)
.toPact();
}
1) If I add a header in my Consumer Test I get a 500 status Error back
2) As you just saw in the Consumer I tried to add Authorisation Header , but in the Provider it will be expired, so I have to find a way to hack something and provide a valid token.
3) In the provider REST Api other services are getting called but it seems I have to mock them at least whenever they are called an Exception gets thrown. Honestly I also don't know how to do this. In which method I need to do it. Why at all do I have to mock them because the external Apis are running.
for 2) I found a solution
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void pactVerificationTestTemplate(PactVerificationContext context, HttpRequest httpRequest) {
httpRequest.addHeader("Authorization", "Bearer " + "eyJ0eXAiOiJKV1Qi");
context.verifyInteraction();
}
But now I get in context.verifyInteraction() an Exception. Very strange.
I can't answer the JVM specific question, however.
If I add a header in my Consumer Test I get a 500 status Error back
Usually, this means that you're told Pact you are going to do something but did not do it. In this case, my guess is the bearer token didn't match or it didn't receive the correct header. There should be logs or a junit report with the details.
As you just saw in the Consumer I tried to add Authorisation Header , but in the Provider it will be expired, so I have to find a way to hack something and provide a valid token.
For dealing with authentication/authorization, you may want to read the strategies here:
https://docs.pact.io/provider/handling_auth
In the provider REST Api other services are getting called but it seems I have to mock them at least whenever they are called an Exception gets thrown. Honestly I also don't know how to do this. In which method I need to do it. Why at all do I have to mock them because the external Apis are running.
Pact is intended to be closer to a unit test, running external services during Pact tests is not recommended, because it makes tests less deterministic. See also this section which discusses the provider test coverage: https://docs.pact.io/5-minute-getting-started-guide#scope-of-a-provider-pact-test.
On the question of how to handle token expiry, I did like this.
The given:
JWT token contains an expire_at claim
I wrote a small library to share within all the projects where I have a class like JwtTestHelper which generates any JWT with token started_at date as a constant date and expire_at is started_at plus like 100 years.
It's important here to make it generate the same token for the same input parameters from run-to-run or the header will be different which will cause a new pact to be considered by the broker. This dramatically changes the approach - you basically need to verify every new pact each time.
On the question of handling exceptions. Do not cheat like this
httpRequest.addHeader("Authorization", "Bearer " + "eyJ0eXAiOiJKV1Qi");
Give your client class code a chance to pass the values naturally, pass it somehow or mock using the same JwtTestHelper

Errorhandling between frontend and backend

at work we building an web application with java spring backend and vue frontend.
At the moment we uses 2 or 3 http response code to pass errors between frontend and backend.
If you call and endpoint with wrong parameters, you'll get an BAD_REQUEST. If some exception was thrown in the backend (which isn't related with the parameters) the backend returns an INTERNAL_SERVER_ERROR and if you pass some ids which aren't in the database the backend returns an NOT_FOUND.
This method has multiple problems:
we have no structure in error case which we can use to pass information to the user (frontend)
we want to indicate problems to the user, which can't be classified by HTTP response codes. For example if an external service isn't available, we want to pass the service name to the frontend. But I don't know if "SERVICE_UNAVAILABLE" fits here...
I found this already: https://www.baeldung.com/spring-response-status-exception
We could use the message field to pass detailed information about an error (specific error json in message field).
Is this a good idea?
Opinions?
T
You can certainly pass information back in this field but using ResponseStatusExceptions. Depending on how much information the frontend needs (e.g. if it's just surfacing a user friendly message to the user) this may be enough for your needs.
Another approach, if you want to use a custom object in the response (esp. per exception/response code), is using #ControllerAdvice and extending ResponseEntityExceptionHandler.
e.g. say you have a custom exception ExternalServiceUnavailableException which had some underlying ServiceInformation you could retrieve from it. Then you could do something like
public class ServiceInformation {
private final String name;
private final String status;
private final String statusMessage;
//snip
}
#ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({ ExternalServiceUnavailableException.class })
public ResponseEntity<Object> handleExternalServiceUnavailable(ExternalServiceUnavailableException ex, WebRequest request) {
final ServiceInformation si = ex.getServiceInformation();
return ResponseEntity
.status(503) // or whatever code you want
.body(si); // or map to some other object/format
// or use the constructor to supply headers etc.
}
}
When you throw a ExternalServiceUnavailableException this would result in a response body like
{
"name": "my-external-service",
"status": "timeout",
"statusMessage": "Service timed out after 30 seconds"
}
A more complete example of this can be found in the below article where the same custom error object is used for each of the exceptions of consequence as well as a default handler.
https://www.baeldung.com/exception-handling-for-rest-with-spring
This makes it easier for the frontend to interpret (as does your proposed approach) since there is only a single format to expect and parse, but you are free to return different response shapes per exception.
Edit: it's worth remembering that there are also response codes 502 (bad gateway) and 504 (gateway timeout) which can be used to indicate an external service is either unavailable or timing out. If these are appropriate you could just use appropriate ResponseStatusExceptions with a message set to include the service name (or other info). As above, it depends on what you need/want the fronted to receive.

Programmatically created Feign client and Eureka target

I have started a few days ago to learn about fault tolerance solutions in microservices. I have some microservices in my ecosystem and they are now interconnected with Eureka service lookup. I used FeignClient to call from one to another. As I heard and read, that Hystrix is getting into maintenance, I wondered if I could use Resilience4J in Feign instead of Hystrix. Well, at least not from annotation level right now as it seems. I found a great Feign.Builder adapter to add resilience4j fault tolerance features above a FeignClient as a decorator (https://github.com/resilience4j/resilience4j/tree/master/resilience4j-feign) so I wanted to use it.
So I used this, added together the features and added the default encoder, decoder, etc. items into the feign builder. Turns out I have to finish of course my code with a .target call which creates my client proxy and I could not really do this with Eureka in a good way:
The first constructor, which takes the class type and the URL is hardcoded, so if I add an eureka next server query into this parameter, it is just a hardcoded url for one of the instances, this is not load balanced. Some kinda workaround could be that I create prototype-scope or similar short lived scoped beans of this client and always get the "next url" for the call. This adds lots of burden to use the clients in every class I make. At least as I saw it. Maybe I could add some kind of singleton helper bean around the prototyping, but again this is not a good design as I see
I thought maybe I could create an EurekaTarget from the Target interface, but of course none of the methods indicate any "end of lifecycle" things, not even the apply method. I thought maybe that is one point which is called before doing a service call, but I saw multiple calls towards it so I had to change the url for all calls.
Do you know any better solution to do this migration?
I guess you are using Spring Boot?
The next version v1.0.0 of Resilience4j will support the #FeignClient annotation.
There was a PR which added the functionality -> https://github.com/resilience4j/resilience4j/pull/579
You can then use it as follows:
#FeignClient(name = DUMMY_FEIGN_CLIENT_NAME)
#CircuitBreaker(name = DUMMY_FEIGN_CLIENT_NAME)
public interface DummyFeignClient {
String DUMMY_FEIGN_CLIENT_NAME = "dummyFeignClient";
#GetMapping(path = "/api/{param}")
void doSomething(#PathVariable(name = "param") String param);
}

Using wiremock, can I return a body that is dependent on the post request

I am trying to test an openid provider class. The openid consumer class is making an http request. I am mocking the response to this request using wiremock. I am trying to mock a valid openid response. However, the valid response depends on the request parameters. Using wiremock, can I set up a mock request where the body of the response is dependent on the request parameters?
This is possible, you just have to make use of a ResponseTansformer. In the below example code the responseDefinition is determined by the stubbing given below. Here I mock an encoding service by simply returning the body bytes back to the caller. Although in the transformer I am free to return whatever I like based on the contents of the request.
int port = 8080;
WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().port(port).extensions(new ResponseTransformer() {
#Override
public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files) {
return new ResponseDefinitionBuilder().like(responseDefinition)
.withBody(request.getBodyAsString().getBytes())
.build();
}
#Override
public String name() {
return "request body returning request transformer";
}
}));
wireMockServer.start();
WireMock.configureFor("localhost", port);
stubFor(post(urlEqualTo("/encode"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/octet-stream")
.withStatus(200)));
stubFor(post(urlEqualTo("/decode"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/octet-stream")
.withStatus(200)));
Wiremock supports extensions that you can write yourself that act as a middleware used to intercept the request and response bodies so you can format it however you like. It's very flexible and allows you to make up new response bodies dynamically or even no response at all.
As an example, we wrote an extension for this at Opentable and open sourced it on Maven Central. It allows you treat the json attributes as variables and interpolate them into your response body. Check it out. Let us know how it goes or if you have any questions.
https://github.com/opentable/wiremock-body-transformer
As far as I know and my experience with WireMock, no.
You can't parameterize a response with arguments passed through request. The best you can do is use matchers to make your mocked server respond accordingly.
I would recommend you making some unit or integration tests with plain jUnit in order to test requests/responses in such cases. They should be quicker if you want to test that receipt requests are responding correctly. I see WireMock as an alternative to do acceptance test, to ensure that your interface with other REST services are not getting broken.
I've never used wiremock. But according to their online documentation you can write a mock that matches URL and Request body parameters. So you should be able to return different mocks depending on the parameters in either the URL itself or embedded in the request body.
Yes it is possible to create a stub with the request matching in wiremock.
Following attributes are supported by for Request matching request.
URL
HTTP Method
Query parameters
Headers
Basic authentication (a special case of header matching)
Cookies
Request body
Multipart/form-data
In your scenario if you want to apply matching on the values in the request body you can use the below approach for generating stub for it.
{
"request": {
...
"bodyPatterns" : [ {
"equalToJson" : "{ \"total_results\": 4 }"
} ]
...
},
...
}
Follow the link for more details: http://wiremock.org/docs/request-matching/

How do I unit test code which calls the Jersey Client API?

I wrote code which calls the Jersey client API which in turn calls a web service which is out of my control. I do not want my unit test to call the actual web service.
What is the best approach for writing a unit test for code which calls the Jersey client API? Should I use the Jersey server API to write a JAX-RS web service and then use the Jersey Test Framework for the unit test? Or should I mock out the Jersey web service calls? I have access to JMock. Or should I try another approach?
During my research, I found this discussion describing various options, but I did find a complete solution. Are there any code examples available showing a suggested JUnit approach? I could not find any in the Jersey documentation.
Here is the relevant source code:
public String getResult(URI uri) throws Exception {
// error handling code removed for clarity
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource service = client.resource(uri);
String result = service.accept(accept).get(String.class);
return result;
}
Here are examples of test code I would like to pass. I would like to test (1) passing in a valid URI and getting a valid string back and (2) passing in an invalid (for whatever reason -- unreachable or unauthorized) URI and getting an exception back.
#Test
public void testGetResult_ValidUri() throws Exception {
String xml = retriever.getResult(VALID_URI);
Assert.assertFalse(StringUtils.isBlank(xml));
}
#Test(expected = IllegalArgumentException.class)
public void testGetResult_InvalidUri() throws Exception {
retriever.getResult(INVALID_URI);
}
Everything above is the simple description of what my code does. In reality, there is a layer on top of that that accepts two URIs, first tries calling the first URI, and if that URI fails then it tries calling the second URI. I would like to have unit tests covering (1) the first URI succeeds, (2) the first URI fails and the second URI succeeds, and (3) both URIs fail. This code is sufficiently complex that I want to test these different scenarios using JUnit, but to do this I either need to run actual stand-in web services or mock out the Jersey client API calls.
Try to use Mockito or Easymock for mocking service calls. You need to mock only these methods which are actually used - no need to mock every method. You can creat mock object for WebResource class, then mock accept method call.
In #BeforeClass/#Before JUnit test method write something like (Mockito example)
WebResource res = mock(WebResource.class);
when(res.accept(something)).thenReturn(thatWhatYouWant);
Then in your tests you can use res object as if it was real object and call mock method on it. Instead of returning value you can also throw exceptions. Mockito is pretty cool.
Typically what you are really after is "does the way I use the Jersey Client DSL produce a request to the correct URL with the correct payload and URL parameters". Testing this with Mockito is really verbose and the setup code will usually end up looking something like this:
when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication);
when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication);
when(testAuthentication.request(
MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder);
when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse);
when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse());
And this is basically just for a single REST request. It's overly verbose, and instead of testing the hoped outcome you are just replicating the steps you think are correct in using the Jersey Client DSL.
Instead of the above, I would aim for mocking a simple service. For this I've used WireMock which starts a Jetty server and where I can stub things like "expect a request to this URL, respond with this message and verify that the payload is this".
I know this is edging on an integration test and it is a bit slower than just using Mockito but I value testing the real outcome and I value the readability of the tests way more in this case.
Setup for a WireMock based Jersey Client test looks something like this:
#Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
Just implement a work-alike service and in your unit test setup start the service using HttpServerFactory.

Categories

Resources