I checked in different existing questions that was asked for similar problem but I didn't get any help for my problem.
In fact I can't use #RequestBody like in this question or this one.
I'm trying to pas some parameters from Angular controller to a Spring MVC controller, but I'm getting this error message
errorCode:500
message:"Required String parameter 'licenceplate' is not present"
here is my Angular Service:
myApp.httpEnterVehicle = function(levelNumber, placeNumber, licenceplate, placeType) {
return $http.put("/myApp/rest/vehicle/entervehicle", {
params : {
'licenceplate' : licenceplate,
'placeType' : placeType,
'placeNumber' : placeNumber,
'levelNumber' : levelNumber
},
});
};
and nothing was detected on my backend side wich seems to be strange
#RequestMapping(value = "/entervehicle", method = RequestMethod.PUT)
public ResponseEntity<Void> enterNewVehicle(#RequestParam("licenceplate") String licenceplate, #RequestParam("placeType") String placeType, #RequestParam("levelNumber") int levelNumber, #RequestParam("placeNumber") int placeNumber){
....
}
do you have any idea what's going on? I already tried toc check the content of my Angular service param and they are correct :(
You have incorrect put request call, it should look like below
$http.put('url', //1st parameter
{}, //request body
{} //request configuration here
);
If you compare you current put call you can see what wrong thing you were doing. You just need to pass {}(empty object) in request body the pass your config object in place of request body
myApp.httpEnterVehicle = function(levelNumber, placeNumber, licenceplate, placeType) {
return $http.put("/myApp/rest/vehicle/entervehicle",
{}, //added blank object as request body
{
params : {
'licenceplate' : licenceplate,
'placeType' : placeType,
'placeNumber' : placeNumber,
'levelNumber' : levelNumber
},
});
};
Related
I have a REST service which returns all the students.
URL : rest/students
I can add optional parameters to it like,
URL : rest/students?department=1001&valid=true
For this use case I have created an angular service,
angular.module('app.student').
factory('StudentService',StudentService);
StudentService.$inject = ['$http','ENV_CONSTANTS'];
function StudentService($http,ENV_CONSTANTS){
var service = {
getAllStudents : getAllSTudents,
getValidStudents : getValidStudents,
getValidStudentByDepartment : getValidStudentByDepartment
};
return service;
function getAllStudents(){
return $http.get(ENV_CONSTANTS.baseUrl+'/students');
}
function getValidStudents(){
return $http.get(ENV_CONSTANTS.baseUrl+'/students?valid=true');
}
function getValidStudentByDepartment (departmentId){
return $http.get(ENV_CONSTANTS.baseUrl+
'/students?valid=true&departmentId'+departmentId);
}
}
But I feel that it's not a good design, because for every query param or the combination of query param I need to create a method. Could anybody suggest a proper way to do this?
The url building ( baseUrl + "/my-suffix" ) is not of bad design imho.
The query parameter building is. $http.get can take a map for this :
$http.get(myUrl, { params : myParamMap })
I.E :
$http.get(myUrl, { params : { valid : true, departmentId : "myDepId" } });
This allow parameter building to be easier and prettier
You could also pre-generates your url constants :
var STUDENT_URL = ENV_CONSTANTS.baseUrl+'/students';
to avoid the url building in each of your methods
$http.get(STUDENT_URL, { params : myParams });
Which would be way more maintainable
Then you could factorize :
function performStudentCall(paramMap) {
return $http.get(STUDENT_URL, { params : paramMap });
}
to be able to call :
function getValidStudentByDepartment (departmentId) {
return performStudentCall({ valid : true, departmentId : departmentId });
}
here you would have one service method per action, which is the correct approach, while keeping only one method to performs all http calls.
You can create a function and pass the query param object with field value pair in function parameter.
something like
function getStudents(queryParamObject){
return $http.get(ENV_CONSTANTS.baseUrl+'/students', { params : queryParamObject });
}
I'm posting a very simple JSON object. The WebApi endpoint is successfully hit, but the JSON data I'm passing doesn't seem to get mapped to my Dto object, I'm always getting null. This used to work fine in previous MVC versions. I've tried a couple of things, even adding [FromBody], as suggested in a similar post. Any idea why this is not working? Thanks
Angular Service:
app.service('Issue', [ '$resource',
function($resource) {
return $resource('api/issue', {}, {
save : { method: 'POST', url: 'api/issue/save' }
});
}]);
Angular call:
Issue.save({ id: 1, test: "test_string" });
Issue.save({ Id: 1, Test: "test_string" }); //this call works if I remove the camel case settings from the startup
Dto object:
public class IssueMinDto {
public int Id { get; set; }
public string Test { get; set; }
}
WebAPI method:
[HttpPost("save")]
public void SaveIssue([FromBody]IssueMinDto issue) { //issue is null here
//process data
}
Later Edit: If I remove the camel case settings from the startup (settings below) and I use capital first letters on the call, then it works, but this is not acceptable as all my data across the app was based on that initial setting (lowercase first letter). Is there anything I can improve in my current settings to get this working?
Startup settings - problem should be tackled here:
services.AddMvc().Configure<MvcOptions>(options => {
options.InputFormatters.Clear();
var jsonOutputFormatter = new JsonOutputFormatter();
jsonOutputFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
options.OutputFormatters.Insert(0, jsonOutputFormatter);
});
Later Later Edit
Turns out the following line of code in my startup settings caused this issue:
options.InputFormatters.Clear();
I replaced the settings with the following line and everything works fine now:
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Turns out the following line of code in my startup settings caused this issue:
options.InputFormatters.Clear();
I replaced the settings with the following line and everything works fine now:
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Almost, the Json parameters must be equals to the C# parameters
Issue.save({ Id: 1, Test: "test_string"});
Update 1
Try to change $resource with $http
app.service('Issue', ['$http', function ($http) {
this.save = function (data) {
return $http.post('api/issue/save', data );
}
}]);
I'm using Angular's $http service to make web api requests. When I use the GET method, the two param values are added to the query string:
// http://foo.com/api/test?heroId=123&power=Death+ray
$http.get("/api/test", {
params: { heroId: 123, power : "Death ray" }
})
However, when I use the PUT method the params are JSON-encoded and sent as the request payload:
// {"params":{"heroId":123,"power":"Death ray"}}
$http.put("/api/test", {
params: { heroId: 123, power : "Death ray" }
})
How can I force the params to be added to the query string when using PUT?
With $http.put, $http.post or $http.patch, the config object containing your url parameters goes as the third argument, the second argument being the request body:
$http.put("/api/test", // 1. url
{}, // 2. request body
{ params: { heroId: 123, power : "Death ray" } } // 3. config object
);
$http.put documentation for reference
AngularJS send json data and not x-www-form-urlencoded format data.
Though you can try the below one:
$http.put("/api/test", { heroId: 123, power : "Death ray" });
If your api url is "api/test/heroId/power",
var data = 123+'/Death ray'
$http.put("api/test"+data);
I am using AngularJs and Resources module. I want to do a GET to obtain an object.. to do this GET I do not have to pass simply the ID to the server, but I should pass a complex object with different properties and values..
Here the code I am using:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
request: $scope.activationStatus
}, function () { });
}
};
On server side I have:
[HttpGet]
public IHttpActionResult GetActivationStatus(MyComplexObject request)
{
//I will do something here later...
return Ok();
}
The problem is that "request" arrive on server equals to NULL...
I have solved the problem passing two strings to the server... in this way:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
codiceFiscale: $scope.activationStatus.CodiceFiscale,
codiceRichiesta: $scope.activationStatus.CodiceRichiesta
}, function () { });
}
};
And server side:
[HttpGet]
public IHttpActionResult GetActivationStatus(string codiceFiscale, string codiceRichiesta)
{
return Ok();
}
In this way everything works... but I don't like this solution because I will have more than two input...
And this is a get, not a post (not a save, an update)...
How can I pass a complex object doing a GET?
Thank you...
It's best to use the POST method if you want to send data in the body of the request. While it's possible with Angular, some servers might ignore the body of GET requests.
This approach allows to send complex objects with arrays and sub objects:
Angular:
$http({
url: '/myApiUrl',
method: 'GET',
params: { param1: angular.toJson(myComplexObject, false) }
})
C#:
[HttpGet]
public string Get(string param1)
{
Type1 obj = new JavaScriptSerializer().Deserialize<Type1>(param1);
...
}
This is not an elegant solution but it works using HTTP GET:
$http.get(url + "?" + $.param(obj).replace(/%5b([^0-9].*?)%5d/gi, '.$1'))
It converts the complex object into a string with dot notation to define levels. Most of the server side frameworks like ASP.NET Core can bind it to complex objects.
This is an example of the string I send for a complex object:
StartDate=2021-06-11&EndDate=2021-06-11&TimeRange.TimeFrom.Time=07%3A00&TimeRange.TimeFrom.TimeFrame=AM&TimeRange.TimeTo.Time=10%3A00&TimeRange.TimeTo.TimeFrame=AM
Request body can only be sent by POST. With get you could at best URL Encode the OBJECT and then send it as query string params. But thats not the best solution to post some data to the server
I have these "methods" in my angular service that use restangular to get remote data where the respose is this:
{
"1105":{"title":"","field_nazione":{"und":[{"value":null,"format":null,"safe_value":""}]},"field_redazionale":{"und":[{"value":null}]}},
"1110":{"title":"","field_nazione":{"und":[{"value":null,"format":null,"safe_value":""}]},"field_redazionale":{"und":[{"value":null}]}}
};
function restfulService(ipCookie,Restangular) {
return {
//Setta la directory di partenza del service rest. In questo modo non devo sempre definirlo
restfulBase : function() {
return Restangular.oneUrl('rest','http://MYREMOTEHOST/rest');
},
getAllCity : function () {
return this.restfulBase().get('cities', {'all':1}, {}, {'X-CSRF-Token': tokenVar});
},
....
};
Why when I call getAllCity() the url is :
http://MYDOMAIN/rest?0=c&1=i&2=t&3=i&4=e&5=s
?
If I use this :
Restangular.oneUrl('rest','http://MYDOMAIN/rest/cities').get({all : 1});
I have no problems.
I have tried changing my app to set Restangular.setBaseUrl() in .config() method and then changing my service to use Restangular.all('cities').get() but I have an error about "strings".
If I use getAll() I have an error about "getLists() want array and not objects".
So: which is the correct way to use Restangular ? I have read online documentation and tutorial, but I have not understand how to retrieve elements in the right way. And to "post".
Thanks and sorry for this stupid question.
I believe the problem is that you set your base as "one" type of resource. The "one" method is not for setting the base urls. The way I set the base url is like this:
angular.module('app')
.config(['RestangularProvider', function (RestangularProvider) {
// Set the base URL
RestangularProvider.setBaseUrl('http://MYREMOTEHOST/rest');
}]);
And then I access each resource, depending on its type with "one" or "all", like so:
function restfulService(ipCookie,Restangular) {
return {
getAllCity : function () {
return Restangular.all('cities').getList();
},
....
};
You can also set the default params in the config phase, or per request at runtime.
The "getLists() want array and not objects" error you get when you use "all" is because it accepts only arrays as a response, therefore you need to intercept the data before and parse it in an array. In your case, you are getting an object, so you can parse it like this:
// this happens at runtime, either in your implementation code or in a more global config file, like:
Restangular.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
// If the what is set, than just grab it and return it
if (data.hasOwnProperty(what)) {
return data[what];
} else {
// Otherwise make it an array
var arr = [];
for (var key in data) {
arr.push(data[key]);
}
return arr;
});
Hope this helps.