unable to use 'call' method in lagom - lagom

I am experimenting with Lagom to check how call, pathCall and namedCall are invoked. I am following lagom's tutorial. I created a new service and opened url using following urls but I get error
URL used (I expect to see hello2 response)
http://localhost:9000/
Error
GET\Q/stream\EService: hello-stream (http://0.0.0.0:58322)
2GET\Q/api/hello/\E([^/]+)Service: hello (http://0.0.0.0:57797)
3POST\Q/api/hello/\E([^/]+)Service: hello (http://0.0.0.0:57797)
**4POST\Q/hello2\EService: hello (http://0.0.0.0:57797)**
I have done following steps
After downloading template (see https://www.lagomframework.com/documentation/1.3.x/scala/IntroGetStarted.html), I have changed the code to add a new service call (called hello2). Following is teh code I have added in HelloService.scala
named("hello")
.withCalls(
pathCall("/api/hello/:id", hello _),
pathCall("/api/hello/:id", useGreeting _),
call(hello2) //added this line in default template.
)
I have defined hello2 as (in HelloService.scala)
def hello2: ServiceCall[String, String]
The code in HelloServiceImpl.scala is
override def hello2 = ServiceCall {
Future.successful("Hello2")
}
Questin 1 - What is the mistake (I guess I am not invoking the service correctly from the browser)?

When you say, "I guess I am not invoking the service correctly from the browser", do you mean you're just navigating to the URL in your browser? If so, this won't work because hello2 is defined as a POST endpoint and your browser will be sending a GET request.
hello2 is defined as a POST endpoint because in your ServiceCall definition it takes a request message. (See https://www.lagomframework.com/documentation/1.3.x/java/ServiceDescriptors.html for more info.)
If you change the request message type from String to NotUsed then Lagom should start generating a GET endpoint instead.

Related

FeignClient error: url values must be not be absolute

I have an error when starting SpringBootApplication:
Unexpected exception during bean creation; nested exception is java.lang.IllegalArgumentException: url values must be not be absolute.
I'm a beginner is SpringCloud, but I worked with Openshift (On first look it's basically the same things).
I have a cluster with GatewayApplication and some business microservices in it, wrote on Kotlin. Inside cluster microservices communicate by FeignClient without authentification. In consumer-service it looks like it:
#FeignClient(name = "producer-service")
#Headers("Content-Type: application/json")
interface MarketServiceFeign {
#GetMapping("https://somehost.ru/{id}/orders")
fun getUserDevices(
#PathVariable id: String,
): ResponseEntity<List<UserOrder>>
}
I tried find same case, but couldn't.
I tried to:
use #RequestLine from feign-core, but it doesn't work with #FeignClient
use feign.#Param for argument instead of org.springframework.web.bind.annotation.#PathVariable
use url with http instead of https
The thing I didn't take into account is that FeignClient goes to services into cluster by name, not by host. So I fixed it like that:
#FeignClient(name = "producer-service")
#Headers("Content-Type: application/json")
interface MarketServiceFeign {
#GetMapping("/{id}/orders")
fun getUserDevices(
#PathVariable id: String
): ResponseEntity<List<UserDevice>>
}
How I understand, instead of "https://somehost.ru" FeignClient uses service name "producer-service". Result url for FeignClient is "producer-service/{id}/orders".
I hope this helps someone.
If you want to use an absolute URL instead of using load-balancing, you need to pass it via the url attribute in the #FeignClient annotation. It's going to be a URL per Feign client, so you cannot pass it per-request via #RequestMapping annotations. You can only use them to provide the path segments that follow the host url. If you do not pass the url in #FeignClient, the name will be used as serviceId to fetch all the instances of that service (for example, from a service registry) and load-balancing will be performed under the hood to select an instance to send the request to.

In karate mocking (karate-netty), how can we override request header value?

Objective:
We want few API calls should go to mock-server(https://192.x.x.x:8001) and others should go to an actual downstream application server(https://dev.api.acme.com).
Setup :
On local, mock server is up with standalone jar on port 8001. e.g https://192.x.x.x:8001
In application config file (config.property)downstream system(which need to mock) defined with mockserver IP i.e https://192.x.x.x:8001
Testing scenario and problem:
1.
Scenario: pathMatches('/profile/v1/users/{id}/user')
* karate.proceed('https://dev.api.acme.com')
* def response = read ('findScope.json')
* def responseStatus = 200ˀˀ
* print 'created response is: ' + response
Now, when we hit API request via postman or feature file then it does karate.proceed properly to https://dev.api.acme.com/profile/v1/users/123/user instead of 192.x.x.x. However, in this request, host is referring to https://192.x.x.x:8001 instead of https://dev.api.acme.com which create a problem for us.
How can we override request header in this case? I did try with karate.set and also with header host=https://192.x.x.x:8001 but no luck.
Thanks!
Please see if the 1.0 version works: https://github.com/intuit/karate/wiki/1.0-upgrade-guide
Unfortunately https proxying may not work as mentioned. If you are depending on this, we may need your help (code contribution) to get this working
If the Host header is still not mutable, that also can be considered a feature request, and here also I'd request you to consider contributing code

How to send custom http response code back from spring cloud functions in gcp?

We are using the new gcp cloud functions using Java / Kotlin.
As in the current reference implementations, we are returning org.springframework.messaging.support.GenericMessage objects.
So our code looks like this (Kotlin):
fun generatePdfInBase64(message: Message<Map<String, Any>>): Message<*> {
val document = process(message)
val encoded = Base64.getEncoder().encodeToString(document.document)
return GenericMessage(encoded)
}
We were not able to find any way to include a custom http response code to our message, e.g. 201 or something. The function only responds 200 in case of no exception or 500.
Does someone know of a way to do this?
Best wishes
Andy
As it is mentioned at the official documentation, the HttpResponse class has a method called setStatusCode where you are able to set the number of the status as your convenience
For example:
switch (request.getMethod()) {
case "GET":
response.setStatusCode(HttpURLConnection.HTTP_OK);
writer.write("Hello world!");
break;
On the other hand the constructor of the GenericMessage receives as parameter a payload, therefore I think you can create a string with a json format and use the constructor for create your GenericMessage instance with the status response you need.
If you want to know more about the statuds codes take a look at this document.

Flask Error: If something fails in the flask backend, how does the error propagate to the front end?

Consider a simple application where a user fills a form to divide two numbers, in the routes the form data is proceeded [made into float] and then passed as parameters to a python script's function that has the division logic.
The logic fails due to division by 0 is handled as a custom message in the terminal. How does one send this custom message back to the front end UI along with a 500 error message? Trying to make a restful flask app here.
So far I can abort and show a custom message but not the one that propagated from the backend. Also looked into custom error handling but I want to writer of the external python script to be able to write the custom message.
You can Flask errorhandler(errorcode) to manage your errors and display those on the frontend.
#app.errorhandler(500)
def code_500(error):
return render_template("errors/500.html", error=error), 500
You can put whatever else you want in the html template.
You can also call the code_500(error) func directly.
Same principle applies for any other HTTP error code if you want to customize the page and the message (401, 403, 404, etc...).
If you're inside a blueprint, you can use app_errorhandler instead.
You could use the abort() function. From the docs:
When using Flask for web APIs, you can use the same techniques as above to return JSON responses to API errors. abort() is called with a description parameter. The errorhandler() will use that as the JSON error message, and set the status code to 404.
You could implement it like this
#app.route("/div")
def divide():
x, y = request.form['x'], request.form['y']
try:
result = x / y
except ZeroDivisionError:
abort(400, description="Your message here")
else:
# Proper response
From there, the important step is properly catching that message on your frontend.

How to get the current TraceId and SpanId

This article, https://devblogs.microsoft.com/aspnet/improvements-in-net-core-3-0-for-troubleshooting-and-monitoring-distributed-apps/, tells me that the field TraceId is available as a correlation id, which is great!
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
=> ConnectionId:0HLR1BR0PL1CH
=> RequestPath:/weatherforecastproxy
RequestId:0HLR1BR0PL1CH:00000001,
SpanId:|363a800a-4cf070ad93fe3bd8.,
TraceId:363a800a-4cf070ad93fe3bd8,
ParentId: Executed endpoint 'FrontEndApp.Controllers.WeatherForecastProxyController.Get
(FrontEndApp)'
In fact, I can see that in our log sink this works as advertised: When web application A serves a request and in doing so invokes web application B, both of them write the same TraceId value to the log.
As far as I understand, any ASP.NET Core application that receives an incoming Request-Id header will attach the same header to outgoing requests, but if the header does not exist on the incoming request, an new value will be generated for the outgoing request.
We have been asked to add that value to the response from web application A, but it is (not surprisingly) not available on the incoming request.
I have been looking at the System.Diagnostics.Activity class, but accessing Activity.Current isn't giving me an instance with anything useful - the TraceID is just {} - i.e. empty.
My question is this: How can I access the TraceId value in the context of a web application?
-S
I had the same problem when I tried to add a header with TraceId value.
Doing some tests with ModelValidation, I saw then in this kind of error response the "traceId" value was correct, but I couldn't obtain this value from http context variable in any way.
Then I went to net core source code to see DefaultProblemDetailsFactory implementation and surprise! The "traceId" value is obtained doing this:
var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
Yes, you can get THE traceId using Activity static variable.
You can get tracid and spanid in dictionary.
using var subject = _tracer.BuildSpan($"Operation").StartActive();
var spanContext = subject.Span.Context;
var dictionary = new Dictionary<string, string>();
_tracer.Inject(spanContext, BuiltinFormats.TextMap, new TextMapInjectAdapter(dictionary));