Seems like this is an infrequently answered questions that's frequently asked. The documentation is somewhat ambiguous.
I want to post a set of parameters as described below.
Web service:
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response post(#FormParam("param") String param){
// code..
}
javascript:
//var paramData = {"startDate":$("#startDate").val()};
var paramData = {startDate:$("#startDate").val()};
$.ajax({
type : 'POST',
url : 'mysite.com/post',
data: paramData,
contentType: 'application/x-www-form-urlencoded',
processData: false,
});
I've changed the contentType to false, tried serializing and stringfying the param data, etc. Either the argument comes in as null in the service or it returns an unsupported media type HTTP error code.
You are doing it wrong...
1. By default, your contentType will be application/x-www-form-urlencoded, so it's not necessary to specify it.
2. Why are you using processData: false? you should read the documentation from here:
http://api.jquery.com/jQuery.ajax/
processData (default: true)
Type: Boolean
By default, data passed in
to the data option as an object (technically, anything other than a
string) will be processed and transformed into a query string, fitting
to the default content-type "application/x-www-form-urlencoded". If
you want to send a DOMDocument, or other non-processed data, set this
option to false.
3. Since processData is true by default and you don't need this to be false then it's not necessary to specify it.
4. You are just passing an Object as the data but where did you specify the param since that's the name that you used for your method? Take a look: public Response post(#FormParam("param") String param)
5. Since your param is a String you will need to convert your Object into a queryString (same as if we were serializing a form) and you can do it easily with jQuery, you should read the following: http://api.jquery.com/jquery.param/
6. So, at the end your code must look like this:
var data = {
name: 'Oscar',
lastname: 'Jara'
};
$.ajax({
type: 'POST',
url: 'rest/service',
data: {
param: $.param(data)
}
});
7. Now, if you print what your param variable contains inside your REST service, you will get this:
name=Oscar&lastname=Jara
Related
Why would a JSON be rendered in bracket notation when bound to a Web Request?
I have an application that makes 2 REST Controller calls in a row.
First, an address is read from a form, serialized, AJAXed to a validation endpoint, and returned to the UI/JS as a Response object payload. This part works fine.
$.ajax({
method: 'POST',
url: '/validate-shipping-address',
data: $shippingInfoForm.serialize()
}
#PostMapping(path = "/validate-shipping-address")
public RestResponse<Address> validateShippingAddress(
#ModelAttribute("shippingForm") ShippingForm shippingForm) {
return validateAddress(shippingForm.getAddress());
}
If the response is successful, that payload (the address) is sent directly into the AJAX call for the second endpoint. This request blows up with a 400 and never enters the actual method.
$.ajax({
method: 'POST',
url: '/shipping-stuff',
data: {
"shippingAddress": validationResponse.payload,
"shipDate": shipDate,
"csrfToken": csrfToken
}
}
#PostMapping(path = "/shipping-stuff")
public RestResponse<?> doShippingStuff(
#RequestParam(name = "shippingAddress") Address shippingAddress,
#RequestParam(name = "shipDate") #DateTimeFormat(pattern = "yyyy-MM-dd") Date shippingDate) {
doStuff(); // Never hit
}
After much analysis, the issue is that Spring MVC cannot deserialize the address passed as an Address object. In the request, I see that the address fields are rendered as address[city], address[state], etc. instead of the standard dot notation address.city, address.state (as the first request has it). If I manually access them via the request using the bracket notation as the param name, it will pull out the value. e.g. request.getParameter("address[city]");.
When I use Chrome dev tools debugger to inspect the response from the first and the object entering the second AJAX call, they look like valid JSON. The Network:Form Data section in Chrome differs though - It shows the dot notation for the first, successful call and the bracket notation for the second, unsuccessful call.
Form Data (first call):
address.firstName=John&address.lastName=Doe&address.addressLine1=123+Main+St&address.city=New+York+City&address.state=NY&address.postalCode=12345&csrfToken=XXXX
Form Data (second call): (%5B = '[' and %5D = ']')
shippingAddress%5BfirstName%5D=John&shippingAddress%5BlastName%5D=Doe&shippingAddress%5BaddressLine1%5D=123+MAIN+ST&shippingAddress%5Bcity%5D=New+York+City&shippingAddress%5Bstate%5D=NY&shippingAddress%5BpostalCode%5D=12345&shippingAddress%5BzipFour%5D=6789&shipDate=2019-05-25&csrfToken=XXXX
So there really are 2 sub-questions:
(1) Is there something in the JS handling that would cause the address to be passed in the bracket form instead of the normal JSON form? I'd think if I could get around this then Spring MVC should work like normal.
(2) Is there a way to make Spring MVC able to handle this without resorting to JSON.stringify and then parsing with Gson/ObjectMapper directly in the controller code?
I've tried all permutations I can think of involving custom wrapper objects, JSON.stringify, #RequestParam, #ModelAttribute, and bare (no annotations). I also tried stringify-ing the whole AJAX payload and using #RequestBody on a wrapper object in the controller, but then the call fails as the csrfToken is not detected.
I've read through this, this, and this, which informed the attempts above.
For now, I've worked around the issue with JSON.stringify and Gson (option 2 above), but would rather make Spring MVC do the work automatically.
Work around:
$.ajax({
method: 'POST',
url: '/commercial-checkout/shipping-stuff',
data: {
"shippingAddress": JSON.stringify(shippingAddress),
"shipDate": shipDate,
"csrfToken": csrfToken
}
});
#PostMapping(path = "/shipping-stuff")
public RestResponse<?> doShippingStuff( //
#RequestParam(name = "shippingAddress") String shippingAddressJson,
#RequestParam(name = "shipDate") #DateTimeFormat(pattern = "yyyy-MM-dd") Date shipDate) {
Address address = gson.fromJson(shippingAddressJson, AddressImpl.class);
}
As per your comment,
I also tried stringify-ing the whole AJAX payload and using
#RequestBody on a wrapper object in the controller, but then the call
fails as the csrfToken is not detected.
When you use #RequestBody you need to create corresponding POJO object to deserialise your JSON. Also you need to add content-type property in your AJAX to indicate the server that you are sending an JSON.
$.ajax({
method: 'POST',
data: 'json',
content-type: 'application/json',
url: '/commercial-checkout/shipping-stuff',
data: {
"shippingAddress": JSON.stringify(shippingAddress),
"shipDate": shipDate,
"csrfToken": csrfToken
}
});
Add a POJO as I mentioned,
public class AddressPOJO {
shippingAddress,
shipDate,
csrfToken
//getter / setters
}
Modify your controller method,
#PostMapping(path = "/shipping-stuff", consumes = "application/json")
public RestResponse<?> doShippingStuff( #RequestBody AddressPOJO addressPJO) {
// do your logic..
}
I am trying to pass an array of bytes to my WebMethod through JavaScript.
The problem is that my WebMethod returns with the message "The test form is only available for primitive methods as parameters."
When I change data type to string or any other kind of primitive variables the WebMethod accepts it goes on.
I'm transforming an object into a byte[], named msgpackEnvio using MessagePack(The transformation itself occurs well), and then sending to WebService.
Here's my request to WebService using jquery
$.ajax({
beforeSend: function (request) {
request.setRequestHeader("Content-Type", "application/json");
},
processData: false,
dataType: "json",
url: url,
data: msgpackEnvio,
type: "POST",
error: function (data) {
$('#upload-load').hide();
$('.bt-enviar-excel').removeAttr('disabled', 'disabled');
var msg = document.getElementsByClassName('msg')[0];
msg.style.color = 'red';
msg.innerHTML = 'Erro interno servidor!';
},
success: //some code
In fact, the code above doesn't matters at all, my problem is in the webService, and how to make it receive an array or perhaps an object.
And here's my WebMethod that should be able to receive a byte[]
[WebMethod]
public string TestMessagePack(byte[] name)
{
//my code
return "Finish";
}
You can use base64 encoding and decoding to send byte arrays as strings. Anything more than that and you might want to use post requests and JSON serialization/deserialization instead. There's not going to be a generic one size fits all conversion between complex C# objects and javascript objects which is why only primitive parameters are allowed, so for nonprimitive things you'll need a translation layer. That's normally going to mean some form of string serialization and deserialization.
I'm new to AJAX and I'm not too clear about how to use the format of the AJAX call
ex
$.ajax({
type: "POST",
url: "Default.aspx/function",
data: '{ searchBy: id }',
contentType: "application/json; charset=utf-8"
}).success(function (result) {
alert(result);
})
I have a function in the .cs file that should take in a string ID and return a list of all the objects that contain that ID.
I want to call this function in the javascript to check that the returned list is null (therefore the ID does not already exist) before inserting new objects into the database.
How could I go about doing this?
All the examples I see return a string from the server side function.
If you have control of the server-side endpoint, then return whatever you want to indicate no matches - an empty list, null, empty string, etc. Then in the success function check for that.
Note the dataType ajax parameter. That tells the ajax function how to format the response for you to consume. If you are expecting JSON to be returned, use dataType: json and in the success function check for an empty json array result.length === 0. In the case of null or empty string, use a dataType: text and check for result == "null" or result == "". Etc.
If you don't have control of server side then you will need to conform to whatever data it sends back to you. The dataType is still the key though.
[WebMethod]
public static int function(int Id)
{
return Id;
}
If you need use only ajax, the best option is XMLHttpRequest, is Vanilla JS and more fast.
If you decide use ajax with jquery the function is:
$.ajax({
type: "POST",
url: "Default.aspx/function",
data: { searchBy: id },
dataType: 'json',
success: function(result) {
// Do something
}
});
I've never done C#, but your url parameter must be a path to a file (e.g. url: Default.aspx). In your file, you should have the logic to handle the request and call the right function. This function will check the DB, and will print the result.
// inside Default.aspx
// 1- is there a POST parameter? If so, call foo()
public static string foo(string postParam) {
// check DB, process
Print(result)
}
Inside your success callback, check if null:
.then(function(result) {
if (result === null) // do stuff
})
I'm sending a call like so:
$.ajax({
url: myURL+functionName,
contentType: "application/json; charset=utf-8", //also tried application/javascript
cache: false,
dataType: "jsonp",
data: parameter,
success:function(response){
alert("great success!");
},
error:function(error) {alert("boo-urns");}
Which is fine and everything looks like it should. The parameter object comes in with a value like so:
{ac:"a8d8e6ef-5907-4978-11cf-39add52b996c",
date:"20160626",
deviceId:"W-eXXX9680-13X3-9317-f1b3-eXXXXe50",
komponenten:Array[5],
menu_kf_nr:1,
mz_nr:"3",
pt_kf_nr:1,
pt_nr:"311701",
sessionId:"b22bXXX6-20XX-4XXX-9ed6-0dXXb297"}
Here is the server side method:
public bool functionName(string ac, string date, string deviceId, List<komponenten> komponenten, int? menu_kf_nr, string mz_nr, int pt_kf_nr, string pt_nr, string sessionId) {
//do stuff with the data
}
And then on the server side though my params only come as follows:
ac "a8d8e6ef-5907-4978-11cf-39add52b996c" string
date "20160626" string
deviceId null string
komponenten null System.Collections.Generic.List<kompnenten>
menu_kf_nr null int?
mz_nr "3" string
pt_kf_nr 1 int
pt_nr "311701" string
sessionId null string
Can anyone tell me where I need to look in order to eliminate the nulls?
Thanks in advance
You should pass your parameters individually in the aJax call, also, the C# side is probably expecting JSON data to be received.
Take a look here to see how to pass multiple parameters in an aJax call.
Note the second part of the accepted answer, using JSON.Stringify
This is a weird one, although it should be very simple.
The code:
var recipients = [];
recipients.push(uuid1);
recipients.push(uuid2);
$.ajax({
url: '/api-url/',
type: 'POST',
data: {'recipient': recipients, 'message': message, 'subject': subject},
dataType: 'json'
}) ...
This is caught in the Chrome Network inspector:
recipient[]:8b99fa41-0f8f-4882-b14f-dc258a765b15
recipient[]:add61999-9baa-4096-a92f-fbb144a4a981
subject:test
message:testtest
This arrives to the server:
{u'recipient[]': [u'8b99fa41-0f8f-4882-b14f-dc258a765b15', u'add61999-9baa-4096-a92f-fbb144a4a981'], u'message': [u'testtest'], u'subject': [u'test']}
As you can see, we have a 'recipient' in the ajax call, two instances of 'recipient[]' in network inspector and one 'recipient[]' on the server with correct data, but wrong param name.
Any ideas how is that '[]' in 'recipient[]' getting there?
This is what JQuery does to your data object:
Data to be sent to the server. It is converted to a query string, if
not already a string. It's appended to the url for GET-requests. See
processData option to prevent this automatic processing. Object must
be Key/Value pairs. If value is an Array, jQuery serializes multiple
values with same key based on the value of the traditional setting
(described below).
To send it as JSON you need to convert it to JSON string:
...
type: 'POST',
data: JSON.stringify({'recipient': recipients, 'message': message, 'subject': subject}),