Ktor returns 415 from endpoints where receive() is used with ContentNegotiation - kotlin

I have parameter classes with the #Searializable annotation:
#Serializable
data class ShowPostURL(
val date: String,
val titleSlug: String,
override val redirectTo: String? = null
)
and no matter what I do call.receive() won't work. I'm getting HTTP 415 errors and Ktor doesn't log anything. I've added the serialization support as well:
install(ContentNegotiation) {
json()
}
How do I fix this? This is how I'm trying to use it:
accept(ContentType.Any) {
get("/foo/{date}/{titleSlug}") {
val input = call.receive(ShowPostURL::class)
call.respondText("foo")
}
}
If I do a trace I can see that my route is matched, but it can't receive the parameters. Is this json() setup is supposed to work when I'm deserializing from url parameters like this?

Firstly, ContentNegotiation feature works only for receiving custom objects from the payload of POST, PUT and PATCH requests:
POST, PUT and PATCH requests have an associated request body (the payload). That payload is usually encoded.
In order to receive custom objects from the payload, you have to use the ContentNegotiation feature. This is useful for example to receive and send JSON payloads in REST APIs.
When receiving, the Content-Type of the request will be used to determine which ContentConverter will be used to process that request
Secondly, there are three out of the box ContentConverter available:
GsonConverter, JacksonConverter and SerializationConverter.
Each of these converters has its own configuration function: gson, jackson and serialization respectively. You use json configuration function which is most likely is not appropriate for the configuration of ContentNegotiation.
To solve your problem you can access URL parameters by referring them with call.parameters and manually create ShowPostURL object. Then serialize it with the kotlinx.serialization framework if needed.
Also, you can write your own ContentConverter to implement custom logic for receiving typed objects.

Related

can not send int to respond in ktor

I'm trying to send int response but get an error but when I use both as a string then response get successfully.
post("/employee") {
call.respond(mapOf("hey" to "Hey","if" to 1))
}
LOGCAT
java.lang.IllegalStateException: Serializing collections of different element types is not yet supported. Selected serializers: [kotlin.String, kotlin.Int]
at io.ktor.serialization.kotlinx.SerializerLookupKt.elementSerializer(SerializerLookup.kt:45)
at io.ktor.serialization.kotlinx.SerializerLookupKt.guessSerializer(SerializerLookup.kt:29)
at io.ktor.serialization.kotlinx.KotlinxSerializationBase.serialize$ktor_serialization_kotlinx(KotlinxSerializationBase.kt:34)
at
You can't pass different types in response "yet" like mentioned in stacktrace. As a workaround you can pass 1 as string or create custom class for this response and serialize it to json and send it like that

Karate API -> JSON Request -> Base field in JSON not being sent in request (works in Postman)

My JSON request has a base value that is the top object.
Sample:
{
"partner_id": "6f4a3092-1b11-48c0-8a11-ae455b327ed8",
"borrowers": [
{
"loan": {
"loan_number": "89898989898222",
The partner_id is not being sent with the rest of the request.
Does this first object require special treatment to be sent with the rest of the request?
It feels like it should 'just work'
In my steps to file a bug, it started working in picking up the base object.

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.

Native way to send custom object in JMS queue? (citrus-simulator)

I'm looking for a native (correct, in terms of the framework) way to send thirdparty (custom) Object to JMS in citrus-simulator?
I have tried:
scenario
.send()
.payloadModel(myObject);
but in JMS queue myObject appears as com.consol.citrus.message.DefaultMessage instead of com...myObject.
Example:
Scenario - receives http POST request (as trigger) and send's JMS Object to message queue.
config
...
.useObjectMessages(true)
...
scenario
...
import com.temafon.data.MORequest;
#Scenario("morequest")
#RequestMapping(value = "/simulator/morequest",method = RequestMethod.POST)
public class JmsMoRequestScenario extends AbstractSimulatorScenario {
#Override
public void run(ScenarioDesigner scenario) {
MORequest request = new MORequest(12345678901L, "USSD", "1172", "ON",
11L);
request.setSourcePort(3);
scenario
.receive()
.payload("getmorequest");
scenario
.send("jms.queue.destination")
.payloadModel(request);
After this case, I expect to get in jms.queue.destination something like screen 1
Expectation
Reality
P.S. I have implemented workaround already, with JavaActionBuilder and jmsTemplate.send in additional class and
scenario
.java(//Object).method(//instance");
But it doesn't seems like correct citrus-simulator way
Setting the payloadModel() in Citrus Java DSL will always result in some kind of marshalled representation of the object and this is not what you want. Neither is using .useObjectMessages(true) working for you because this results in the whole Citrus message object to be used as message payload.
You need to define a complete Citrus message object and that will remain untouched in terms of payload creation for the JMS destination. Citrus is then automatically using a JMS object message with proper object payload.
MORequest request = new MORequest(12345678901L, "USSD", "1172", "ON", 11L);
request.setSourcePort(3);
scenario
.receive()
.payload("getmorequest");
scenario
.send("jms.queue.destination")
.message(new JmsMessage(request));
Note that I am using the .message() fluent API instead of the payloadModel() API. The message API receives a Citrus message object such as com.consol.citrus.jms.message.JmsMessage or com.consol.citrus.message.DefaultMessage
Your custom domain model object request is used as constructor arg and will result in the JMS message as object payload as is. Of course MORequest must be of type java.io.Serializable

how to see actual body sent from restassured

I have created a jax-rs rest api and tested it with rest-assured. All tests are green. Now I am trying to create an html/js front end for it.
My problem is I do not know how my json objects should look like to be accepted by my rest api. Thanks to restassured/jax-rs I never handled request strings. I fill in objects and I get objects, (un)marshaling (json) is invisible.
Is there any way I can see (debug) what strings are created by rest-assured/java and sent over the "wire"?
If you want to log the request body you can do:
given().log().body(). ..
Or if you want to log the response body you can do:
.. .then().log().body(). ..
See documentation on logging for more details.
I'm not a RestAssured used, so I can't answer your question directly, but here are some ideas that may help you out.
I don't know what serializer RestAssured uses under the hood, but Resteasy on Wildfly uses Jackson by default. I would get familiar with this library. For less trivial application, you may need to dig into its APIs directly to get your desired results. Here is it's documentation. For your particular case you can do something as simple as
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(yourObject);
System.out.println(jsonString);
This will print out the POJO in JSON format, based on your getters in the class. This is at the most basic level. If you don't already have Jackson as a dependency, you can add
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.0</version>
</dependency>
A really good friend (tool) to have is cURL. It's a command line tool that allows you to make REST/HTTP (other protocols also) requests. Though for this particular case it wouldn't help, you could send a GET request to one your resources that serves up the same type that you accepted in your POST. That way, you can see the resulting JSON. This may be a little much at this point, but I would definitely look into this tool if you're going to be doing a lot of REST development.
You might also want to check out a Browser tool like [Postman for Chrome]
You should really get familiar with JSON format. Once you get familiar with it, and you start working with JSON framework, you'll notice that at a basic level, they all work similarly.
Java Object == JSON Object ( {} )
Java Collection/Array == JSON Array ( [] )
Java fields/properties == JSON keys
Getters are used for they keys and their values (for serialization)
Setters are used for deserialization
So for example you have this class
public class Person {
String name;
List<Person> friends;
public String getName() { return name; }
public void setName(String name) { return name; }
// Getter and Setter for friends
}
An instance of Person would produce the following JSON
{
"name" : "Peeskillet",
"friends": [
{
"name": "Lebron James"
},
{
"name": "Steph Curry"
}
]
}
It's actually pretty simple once you get the hang of it.
Oh and another thing you can do is add a logging filter on the server side as mentioned here.
As far as working with Javascript, there is a JSON.stringify(javascriptObject) that will serialize your Javacript objects to JSON strings. So generally, you can model your Javascript object like your Java objects.
Hope this helped.
In RestAssured just use this:
String body = resp.asString();
System.out.println(body);
Try this for Request Body
RequestSpecification httpRequest = RestAssured.given().urlEncodingEnabled(true);
..
..
..
System.out.println(" Body ==> "+ httpRequest.log().body());
And for response body:
System.out.println("Res Body ===>"+ response.getBody().prettyPrint());