org.ksoap2.transport.HttpResponseException 400 bad request error when calling .svc from Kotlin - kotlin

I've seen other posts on this, but none seem to help. The issue seems to be adding the parameter to the request. Note this is a .svc -- not wsdl. The C# .svc file has a data contract of:
[DataContract]
public class MyMethod_In
{
[DataMember]
public string rc;
}
Kotlin code: (constants take out for easier reading, and names changed to protect the innocent)
val soapObject = SoapObject("https://qa.mysite.com/ws/MyService.svc/", "MyMethod")
soapObject.addProperty("rc", "xyz")
val envelope = SoapSerializationEnvelope(SoapEnvelope.VER11)
envelope.setOutputSoapObject(soapObject)
envelope.dotNet = true
val httpTransport = HttpTransportSE("https://qa.mysite.com/ws/MyService.svc/MyMethod")
try {
httpTransport.call("https://qa.mysite.com/ws/MyService.svc/MyMethod", envelope)
blah blah
}
catch (e: Exception) {
exception happens with 400 error
}
The problem seems to be the soapObject.addProperty line. I've also tried other code where I construct the property info and set the name, type, and value, but I still always get the 400 error. I tried that with a type of String and a type of JSON, and it made no difference.
I'm not totally sure of some of the hard coded values, but I seem to be calling the service correctly, because I tried another service with no input parameters, and this worked fine and got the response.
I'm probably missing one small thing, but can't find it. Any ideas on why the bad request? Thanks

Figured it out for okhttp3, version 4.2.0. As I suspected, I need to pass JSON data. This code does it:
val json = "{ \"rc\":\"xyz\" }"
val mediaTypeJson = "application/json; charset=utf-8".toMediaType()
val requestBody = json.toString().toRequestBody(mediaTypeJson)
val request = Request.Builder()
.url("https://qa.mysite.com/ws/MyService.svc/MyMethod")
.post(requestBody)
.build()
Should probably clean it up and use gson or something, but at least this works.

Related

How to send a List<Map<String, String>> as parameter for a GET API

I have a requirement to pass List<Map<String, String>> as a parameter for REST GET API.
I need help to know how this can be passed from Postman or similar tool.
I tried to set it as a BODY for a GET API, it is giving me errors.
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.
Any help is appreciated.
You can very well !
I tried and this worked for me
Create a model class which has variable of type List<Map<String, String>> myList;
Define a controller similar to below
#PostMapping("/addList")
public ResponseEntity<List<Map<String, String>>> passList(#RequestBody ListModel listModel) {
System.out.println("List mapped " + listModel);
return new ResponseEntity<>(HttpStatus.CREATED);
}
Create a request from Postman or any tool like this
{
"myList": [
{
"one": "1",
"two": "2"
}
]
}
Response I got
List mapped ListModel [myList=[{one=1, two=2}]]
Make sure you map correct variable name ( for e.g. I have defined myList, so that must be passed so it gets properly mapped in Controller class ) also assuming toString, GetterSetters , and your familiarity with few basic REST annotations related to Spring/SpringBoot :)

Ktor Client, how to specify body parameters

I'm trying to send a POST request to the server, this post requires parameters "email" and "password".
but I don't know how to specify parameters, I read the documentation but I didn't understand.
this is my code:
val request=client.post<String> {
url(BASE_URL+"login.php")
body="email=$email,password=$password"
}
fwiw I use something like following here....though I would have thought specifying url like you do should also work. What issue do you see? The body might also be some json for example, or maybe a data class etc if you have serialization setup.
response = client.post(url) {
body = "some params/data etc"
}
It should work if you use serialization, but I solved my problem by using 'Uploading multipart/form-data'
val request=client.post(url) {
body=MultiPartFormDataContent(formData {
append("email","data")
append("password","data")
})
}
see Documentation

How to get status code of HttpCall with Ktor and kotlinx serialization

I am trying to figure out how to check the http status code of a http request with Ktor
I have a simple GET request like this with a HttpResponseObject that holds the data the server returns and any errors server side that I control
val response:HttpResponseObject<MyObject> = client.get<HttpResponseObject<MyObject>>(url)
Now what I need to also be able to check are is if there are unhandled exceptions or Authentication exceptions that get thrown by the server. In these cases nothing would be returned by the server and a status code of 500 or 401 error would be returned.
I see the documentation has you can get the full http response with something like this
val response:HttpResponse client.get(url)
but then how do lose my serialized data coming back and I couldnt find any examples on how to serialize it from the HttpResponse object.
Does anyone have any suggestions? is there a way to get the http status code from my first example?
You can try getting the status code by using the following code:
val response = client.get<HttpResponse>(url) after that, to get the bytes from the response and serialize it you can try using val bytes: ByteArray = response.readBytes()
You can find full documentation here :
https://ktor.io/clients/http-client/quick-start/responses.html
What I ended up doing was using the HttpResponseValidator in the HttpClientConfig to catch the status codes then throw exceptions
HttpResponseValidator{
validateResponse { response: HttpResponse ->
val statusCode = response.status.value
when (statusCode) {
in 300..399 -> throw RedirectResponseException(response)
in 400..499 -> throw ClientRequestException(response)
in 500..599 -> throw ServerResponseException(response)
}
if (statusCode >= 600) {
throw ResponseException(response)
}
}
}
By doing so I was then able to pass the error through my custom object back up to the UI
private suspend fun getCurrentWeatherForUrl(url:String, callback: (HttpResponseObject<MyObject>?) -> Unit){
var response:HttpResponseObject<MyObject>? = null
response = try{
client.get<HttpResponseObject<MyObject>>(url){
header("Authorization", "Bearer $authKey")
}
}catch (e:Exception){
HttpResponseObject(null, e.toString())
}
callback(response)
}
Also you can use HttpResponse.receive() to get a serialized object AND the response data
val response:HttpResponse = client.get(url)
val myObject:MyObject = response.receive<MyObject>()
HttpResponse is deprecated, you need to use HttpStatement and then get the status after calling execute() on it.

Proper way to retrieve the Request.Content from global error handler

I have register a global exception handler, and it fires and contains all of the information I need with the exception of the Request.Content which is always empty... I need the values that were passed in when I am debugging...
Public class MyExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
try
{
... other code
var methodName = context.Request.Method.ToString();
var errorUri = context.Request.RequestUri.ToString();
var errorMessage = context.Exception.Message;
var errorStackTrace = context.Exception.StackTrace.ToString();
var payload = context.Request.Content.ReadAsStringAsync().Result;
..... other code
}
}
}
What is the proper way to retrieve the Request.Content from global error handler ? In the code above the Content property has already been read by the model binders and as such is always empty.
How can I consistently get the posted body from an exception ?
Should I retrieve and save the posted body in a custom MessageHandler ?
Thanks
Greg
In experimenting with reading the buffer of the request.Content in a custom message handler.. It appears that if I read it with this code:
var payload = context.Request.Content.ReadAsStringAsync().Result;
and do NOTHING with it... The buffer will not be emptied when the model binders read it, because its always there in my exception logger now... I don't know if this is by design or what but its exasperating !

An interesting Restlet Attribute behavior

Using Restlet 2.1 for Java EE, I am discovering an interesting problem with its ability to handle attributes.
Suppose you have code like the following:
cmp.getDefaultHost().attach("/testpath/{attr}",SomeServerResource.class);
and on your browser you provide the following URL:
http://localhost:8100/testpath/command
then, of course, the attr attribute gets set to "command".
Unfortunately, suppose you want the attribute to be something like command/test, as in the following URL:
http://localhost:8100/testpath/command/test
or if you want to dynamically add things with different levels, like:
http://localhost:800/testpath/command/test/subsystems/network/security
in both cases the attr attribute is still set to "command"!
Is there some way in a restlet application to make an attribute that can retain the "slash", so that one can, for example, make the attr attribute be set to "command/test"? I would like to be able to just grab everything after testpath and have the entire string be the attribute.
Is this possible? Someone please advise.
For the same case I usually change the type of the variable :
Route route = cmp.getDefaultHost().attach("/testpath/{attr}",SomeServerResource.class);
route.getTemplate().getVariables().get("attr") = new Variable(Variable.TYPE_URI_PATH);
You can do this by using url encoding.
I made the following attachment in my router:
router.attach("/test/{cmd}", TestResource.class);
My test resource class looks like this, with a little help from Apache Commons Codec URLCodec
#Override
protected Representation get() {
try {
String raw = ResourceWrapper.get(this, "cmd");
String decoded = new String(URLCodec.decodeUrl(raw.getBytes()));
return ResourceWrapper.wrap(raw + " " + decoded);
} catch(Exception e) { throw new RuntimeException(e); }
}
Note my resource wrapper class is simply utility methods. The get returns the string of the url param, and the wrap returns a StringRepresentation.
Now if I do something like this:
http://127.0.0.1/test/haha/awesome
I get a 404.
Instead, I do this:
http://127.0.0.1/test/haha%2fawesome
I have URLEncoded the folder path. This results in my browser saying:
haha%2fawesome haha/awesome
The first is the raw string, the second is the result. I don't know if this is suitable for your needs as it's a simplistic example, but as long as you URLEncode your attribute, you can decode it on the other end.