Scalatra params not working on HTTP POST request - scala

im getting "" for username and country_code with the correct request body but params are working fine in GET request so whats the problem here?
post("/api/clients") {
try {
val username = params.getOrElse("username", "")
val country_code = params.getOrElse("country_code", "")
val client = new Client(username, country_code)
if (client.getId == 0) {
db.save(client)
Ok(client.getId)
} else {
BadRequest("Bad Request")
}
} catch {
case e: Exception => BadRequest("Bad Request")
}
}

Related

How to send POST request to another microservice containing enum #RequestParam in kotlin?

I tried to send request to another service containing enum #RequestParam but it always fails.
Here's the example of my request;
fun upsertExclusionOverride(
request: request
): ExcOve? {
val builder = UriComponentsBuilder.fromUriString("/v1/p-b/e/bulk")
val httpEntity = RestTemplateUtils.getHttpEntityCustomHeaders(request, headers)
try {
val body = restTemplate
.exchange(
builder.toUriString(),
HttpMethod.POST,
httpEntity,
Response::class.java
)
.body
?: throw Exception("Fail")
return body.toDomain()
} catch (e: RestClientException) {
log.error(e.message)
throw Exception("Fail")
}
}
This is the other microservice;
#PostMapping("/e/bulk")
#ApiOperation("Exclude")
fun exclusionsInBulk(
#RequestParam(name = "operation", required = true) operation: Operation,
#RequestPart("file") #ApiParam(
value = "File",
required = true,
format = "byte"
) file: MultipartFile
): ResponseEntity<Response> {
.....
}
How should I prevent 400 Bad Request?
I added enum converter but it didn't work.
I expect it to not to get 400 Bad Request.

Play Framework - Respond with JSON after uploading a file (multipartFormData)

I am using this code to upload an image on server , that i get from this link play upload
def upload = Action(parse.multipartFormData) { request =>
request.body
.file("picture")
.map { picture =>
val dataParts = request.body.dataParts;
val filename = Paths.get(picture.filename).getFileName
val fileSize = picture.fileSize
val contentType = picture.contentType
val picturePaths =
picture.ref.copyTo(
Paths.get(
s"/opt/docker/images/$filename"
),
replace = true
)
if (dataParts.get("firstPoint") == None) {
val pointlocation = new Point_LocationModel(
dataParts.get("step").get(0),
dataParts.get("backgroundTargetName").get(0),
dataParts.get("x").get(0),
dataParts.get("y").get(0),
dataParts.get("z").get(0),
dataParts.get("rotation").get(0),
dataParts.get("note").get(0),
dataParts.get("tag").get(0),
dataParts.get("work_session_id").get(0),
(picturePaths).toString
)
point_LocationRepository.create(pointlocation).map { data =>
Created(Json.toJson(data._2))
}
} else {
val jValuefirstPoint =
Json.parse(dataParts.get("firstPoint").get(0)).as[PointModel]
val jValuesecondPoint =
Json.parse(dataParts.get("secondPoint").get(0)).as[PointModel]
val pointlocation = new Point_LocationModel(
dataParts.get("step").get(0),
dataParts.get("backgroundTargetName").get(0),
Some(jValuefirstPoint),
Some(jValuesecondPoint),
dataParts.get("rotation").get(0),
dataParts.get("note").get(0),
dataParts.get("tag").get(0),
dataParts.get("work_session_id").get(0),
(picturePaths).toString
)
point_LocationRepository.create(pointlocation).map { data =>
logger.info(s"repoResponse: ${data}");
Created(Json.toJson(data._2))
}
}
Ok(s"picturePaths ${picturePaths}")
}
.getOrElse(Ok("Invalid Format"))
}
This code works very well, but on the response I want to get the response from the repository. How can i await for the response of the repository to return this?
Can you give me any idea how can i do it?
Thanks in advance.
If we simplify your code to the essential bits, you have:
def upload = Action(parse.multipartFormData) { request =>
request.body
.file("picture")
.map { picture =>
if (someConditionA) {
someBusinessLogicA().map { data =>
Created(Json.toJson(data._2))
}
} else {
someBusinessLogicB().map { data =>
Created(Json.toJson(data._2))
}
}
Ok(s"picturePaths ${picturePaths}")
}
.getOrElse(Ok("Invalid Format"))
}
There are 2 problems:
the return of your if/else is swallowed by the Ok(s"picturePaths ${picturePaths}")
assuming your business logic returns Future[_] you need to "propagate" the Future everywhere
Something like this should work:
def upload = Action.async(parse.multipartFormData) { request =>
request.body
.file("picture")
.map { picture =>
if (someConditionA) {
someBusinessLogicA().map { data =>
Created(Json.toJson(data._2))
}
} else {
someBusinessLogicB().map { data =>
Created(Json.toJson(data._2))
}
}
}
.getOrElse(Future.successful(Ok("Invalid Format")))
}
Notice the Action.async and the Future in the getOrElse.

Scala polling loop without vars

What's the Scala best-practice for polling and API?
I'm trying to write a Scala method that polls an API, checking if it reached "SUCCESS". While polling, it also might reach bad stated like "FAILED" or "TIMEOUT".
In Java, I'd write something like:
public String pollEndpoint() {
boolean isPolling = true;
String result = "NA";
while (isPolling) {
Response response = getResponse("http://myAPI.com/ready?id=1234");
if (response.status == "FAILED") { throw new FailedException(response.reason);}
else ... //Some other bad conditions
else if (response.status == "SUCCESS") {
isPolling = false;
result = response.result;
}
System.out.println("Current state is " + response.status); // When running, will be "RUNNING"
Thread.sleep(1000);
}
}
In Scala I can do:
def pollEndpoint():String = {
var isPolling = true
var result = "NA"
while (isPolling) {
val response = getResponse("http://myAPI.com/ready?id=1234")
if (response.status == "FAILED") { throw new FailedException(response.reason)}
else ... //Some other bad conditions
else if (response.status == "SUCCESS") {
isPolling = false
result = response.result
}
println("Current state is " + response.status); // When running, will be "RUNNING"
Thread.sleep(1000)
}
}
But this solution uses vars.
Is there any nice way of doing this, using only vals?
As Luis mentioned in comment, you can just write a recursive for that:
def pollEndpoint():String = {
val response = getResponse("http://myAPI.com/ready?id=1234")
println("Current state is " + response.status); // When running, will be "RUNNING"
if (response.status == "FAILED") { ??? }
else if (response.status == "SUCCESS") {
response.result
} else {
Thread.sleep(1000)
pollEndpoint()
}
}
The following will mock getResponse:
var i = 5
def getResponse(str: String): Response = {
if (i < 0) {
Response("SUCCESS", "Great success")
} else {
i = i - 1
Response("Wait", "Not done yet.")
}
}
And the call:
pollEndpoint()
Will produce:
Current state is Wait
Current state is Wait
Current state is Wait
Current state is Wait
Current state is Wait
Current state is Wait
Current state is SUCCESS
Having said all of that, it is way better instead of defining getResponse as it is, we might do:
def getResponse(str: String): Future[Response]
And then simply:
getResponse("http://myAPI.com/ready?id=1234").map { response =>
// Handle response
}
It depends on what information determines the repetition (i.e. when to loop) and what information is returned to the outside world, but under the right circumstances you might iterate() instead of looping or recursing.
def pollEndpoint():String = {
Iterator.iterate(getResponse("<yadda-yadda>")){ response =>
response.status match {
case "FAILED" => //log error, throw exception, etc.
case stat => //log whatever
Thread.sleep(1000)
}
getResponse("<yadda-yadda>")
}.dropWhile(_.status != "SUCCESS") //test for exit condition/s
.next().result
}

Using Post Request return a multiple values in Unity

I am new to Unity i have created a Post Request from that i want to return the Authentication-Token Header and authorization header and some required json data here is my code
private IEnumerator BasketId()
{
string url = "http://hololens5.northeurope.cloudapp.azure.com/INTERSHOP/rest/WFS/inSPIRED-inTRONICS-Site/-/baskets/";
using (UnityWebRequest request = UnityWebRequest.Post(url, "Hello"))
{
yield return request.SendWebRequest();
string token = request.GetResponseHeader("Authentication-token");
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
}
else
{
string jsonResut = System.Text.Encoding.UTF8.GetString(request.downloadHandler.data);
obj = JsonConvert.DeserializeObject<BasketId>(jsonResut);
Debug.Log(obj.Uri);
Debug.Log("Authentication-Token: " + token);
yield return obj.Title;
yield return token;
}
}
}
so i could i return the values. Please help me.
Because Coroutine is not immediate (blocking) so you won't be able to return the response directly. What you need to do is to have an event or callback that will be called when your request completed.
Here is how you can achieve it by passing the callback as argument:
private IEnumerator GetBasketId(System.Action<string, BasketId> callback)
{
string url = "http://hololens5.northeurope.cloudapp.azure.com/INTERSHOP/rest/WFS/inSPIRED-inTRONICS-Site/-/baskets/";
using (UnityWebRequest request = UnityWebRequest.Post(url, "Hello"))
{
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
if (callback != null)
{
callback(null, null);
}
// callback?.Invoke(null, null); // for short
}
else
{
if (callback != null)
{
string token = request.GetResponseHeader("Authentication-token");
string jsonResut = System.Text.Encoding.UTF8.GetString(request.downloadHandler.data);
obj = JsonConvert.DeserializeObject<BasketId>(jsonResut);
if (callback != null)
{
callback(token, obj);
}
// callback?.Invoke(token, obj); // for short
}
}
}
}
so when you want to start the request simply call something like:
StartCoroutine(GetBasketId((token, basketId) =>
{
if (string.IsNullOrEmpty(token))
{
// Handle error
}
else
{
// Handle success
Debug.Log("Token: " + token);
Debug.Log(basketId.Title);
}
});

return/break a function from the derived base class

In my REST API service layer, I have a class ProductService.
The following logic exists in all my functions: Do Validate, if validation fails i throw invalid exception, if passes, i continue to the next try-catch and throw general-error in case of failure:
def addProduct(request:AddProductRequest): BaseResponse[String] =
{
try
{
request.validate
}
catch
{
case ex: Exception => {
Logger.error("Failed to add product, Validation failed", ex);
val errorResponse:ErrorResponse[String] = new ErrorResponseList().InvalidParameters
errorResponse.addMessage(ex.getMessage)
return errorResponse
}
}
try
{
val addedProductId = productRepository.addProduct(request.language, request.tenantId, request.product)
DTOResponse(addedProductId)
}
catch
{
case ex: Exception => {
Logger.error("Failed to add product to tenant Id="+request.tenantId+" language="+request.language, ex);
val errorResponse:ErrorResponse[String] = new ErrorResponseList().GeneralError
errorResponse.addMessage(ex.getMessage())
return errorResponse
}
}
}
Now, instead of repeating the request.validate with the same try and catch for all functions, i created a base class with the following function:
abstract class ServiceBase {
def validate[T](request:BaseRequest)
{
try
{
request.validate
}
catch
{
case ex: Exception => {
Logger.error("Validation failed", ex);
val errorResponse:ErrorResponse[String] = new ErrorResponseList().InvalidParameters
errorResponse.addMessage(ex.getMessage)
return errorResponse
}
}
}
So now, my addProduct(..) will look like:
validate(request)
..the rest of the code - the 2nd try-catch
This saves alot of lines.
The problem is that if validation fails, it will never return. I get the following errors in ServiceBase:
Multiple markers at this line
- enclosing method validate has result type Unit: return value discarded
- enclosing method validate has result type Unit: return value discarded
- a pure expression does nothing in statement position; you may be omitting necessary
parentheses
validate has no return type (and thus defaults to returning Unit), in ServiceBase your signature for validate should look like this:
def validate[T](request:BaseRequest): BaseResponse[String] =
(assuming you want to return a BaseResponse[String])
this may be useful to someone, someday, functional programming.. Did we say ^_^
Changed the ServiceBase validate to:
def validate[T](request:BaseRequest):Option[BaseResponse[T]] =
{
try
{
request.validate
None
}
catch
{
case ex: Exception => {
Logger.error("Validation failed", ex);
val errorResponse:ErrorResponse[T] = new ErrorResponseList().InvalidParameters
errorResponse.addMessage(ex.getMessage)
return Some(errorResponse)
}
}
}
And now i do:
def getProducts(request:GetProductsRequest) :BaseResponse[ProductSearchResults] =
{
validate[ProductSearchResults](request).getOrElse(
{
try
{
val products = productRepository.getProducts(request.language,request.tenantId,request.productIds)
val foundProducts = for (product <- products) yield (product.id)
val notFoundProducts = request.productIds filterNot (foundProducts.toSet)
val responseWrapper = new ProductSearchResults(products, notFoundProducts)
DTOResponse(responseWrapper)
}
catch
{
case ex: Exception => {
Logger.error("Failed to get products from tenant Id="+request.tenantId+" language="+request.language, ex);
val errorResponse:ErrorResponse[ProductSearchResults] = new ErrorResponseList().GeneralError
errorResponse.addMessage(ex.getMessage())
return errorResponse
}
}})
}