Error 400 when POST'ing JSON in angularjs + Spark Single Page Application - angularjs

I'm new to Single Page Application area and I try to develop app using angularjs and Spark framework. I get error 400 bad request when I want to post JSON from my website. Here is code fragment from client side:
app.controller('PostTripCtrl', function($scope, $http) {
$scope.newTrip = {};
$scope.submitForm = function() {
$http({
method : 'POST',
url : 'http://localhost:4567/trips/add',
data : $scope.newTrip,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
}
}).success(function(data) {
console.log("ok");
}).error(function(data) {
console.log("error");
console.log($scope.newTrip);
});
};
});
Values that are to be assigned to newTrip are read from appropriate inputs in html file. Here is server-side fragment:
post("/trips/add", (req, res) -> {
String tripOwner = req.queryParams("tripOwner");
String startDate = req.queryParams("startDate");
String startingPlace = req.queryParams("startingPlace");
String tripDestination = req.queryParams("tripDestination");
int tripPrice = Integer.parseInt(req.queryParams("tripPrice"));
int maxNumberOfSeats = Integer.parseInt(req.queryParams("maxNumberOfSeats"));
int seatsAlreadyOccupied = Integer.parseInt(req.queryParams("seatsAlreadyOccupied"));
tripService.createTrip(tripOwner, startDate, startingPlace, tripDestination, tripPrice, maxNumberOfSeats,
seatsAlreadyOccupied);
res.status(201);
return null;
} , json());
At the end I obtain error 400 bad request. It is strange for me that when I want to see output on the console
System.out.println(req.queryParams());
I get json array of objects with values written by me on the website. However, when I want to see such output
System.out.println(req.queryParams("tripOwner"));
I get null. Does anyone have idea what is wrong here?

I think the main problem is that you are sending data to your Spark webservice with the 'Content-Type' : 'application/x-www-form-urlencoded' header. Try sending it as 'Content-Type' : 'application/json' instead, then in your Java code declare a String to receive req.body(), you'll see all your data in there.
Note: When you try to acces your data like this req.queryParams("tripOwner"); you're not accessing post data, but you're seeking for a get parameter called tripOwner, one that could be sent like this http://localhost:8080/trips/add?tripOwner=MyValue.

I would advise using postman to post a request to your server and see if it works. Try a different content type too. Try using curl and play with the various headers you are sending. 400 suggests the wrong data is being sent or expected data is missing or the data is the wrong type but based on your code you've provided I can see nothing wrong (but see below).
When your server receives a request log all request headers being received and see what changing them does. If it works in postman then you can change your client code to mirror the headers postman is using.
Does your spark server validate the data being sent before your controller code is hit? If so ensure you are adhering to all validation rules
Also on looking at your code again your client is sending the data in the post data but your server is expecting the data in the query string and not in the post data?
What happens if your server just sends a 201 response and does nothing else? Does your client get a 201 back? If so it suggests the hook up is working but there is something wrong with the code before you return a 201, build it up slowly to fix this.

Ok, I managed to cope with that using another approach. I used Jackson and ObjectMapper according to Spark documentantion. Thanks for your answers.
You can see more about that here: https://sparktutorials.github.io/2015/04/03/spark-lombok-jackson-reduce-boilerplate.html

You're probably just needed to enable CORS(Cross-origin resource sharing) in your Spark Server, which would have allowed you to access the REST resources outside the original domain of the request.
Spark.options("/*", (request,response)->{
String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
if (accessControlRequestHeaders != null) {
response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
}
String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
if(accessControlRequestMethod != null){
response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
}
return "OK";
});
Spark.before((request,response)->{
response.header("Access-Control-Allow-Origin", "*");
});
Read more about pre-flighted requests here.

Related

Axios .get request weird behaviour

I have the following get request:
return axios
.get<ArticlesResponse>(SUGGESTED_ARTICLES, {
headers: {
'Content-Type': 'application/json',
},
})
.then(onRequestSuccess)
.catch(onRequestError);
It returns me an object with the data I need, however, the data field inside the object is a string instead of an actual object. Anyone has any ideea about why? I looked it up and saw that adding that header above will fix the issue but it doesn't. Thanks in advance!
My onRequestSucces is:
export function onRequestSuccess<T = any>(response: AxiosResponse<T>) {
console.log('Request Successful!', response);
return response.data;
}
JSON.Parse() also won't fix it.
The problem may be due to the API returning a response that contains invalid JSON data, now JSON.parse would throw an error, but Axios manages the exception by setting the invalid JSON as string in the data property. Try using the Fetch API.
Since you're using a GET request (doesn't have a body) the 'Content-Type' is not being useful. This header is used to tell the server which type of content you're sending, but you're sending none. You should use it only on POST/PUT requests.
See this question for more details on this.
In order for your request to be read as JSON you have to set the header in the server. This will tell the browser you're receiving a JSON, which will then be parsed automatically by axios.

Receiving Json data in groovy app

I´m working on this app which will be a frontend consuming data from other applications but in first stance, it will be posting credentials to another app already running in production, and after credentials are accepted it should redirect to that app with user logged in.
Here comes the problem. I´ve already tested sending data to the other application data is being received as
params: [{"j_username":"username","j_password":"password","instance":"http:8080/TERA/authAuto"}:, action:authAuto, controller:login]
username: null
Prueba: null
I have tried to receive this as it follows all without success
request.JSON.j_username
params.j_username
params["j_username"]
The params: is actually params received by groovy being printed.
I´ll now add my angularJs code
vm.login = function(){
$http({
method: 'POST',
url: "http://t0002161750:8080/TERA/authAuto",
data: {j_username: vm.user.username, j_password: vm.user.password, instance: "http://t0002161750:8080/TERA/authAuto"},
headers:{
'Content-Type': 'application/x-www-form-urlencoded;charset=utf8'
}
}).success(function(response){
$window.location.href = "http://t0002161750:8080/TERA/";
});
}
}
Im doing this tests with a companion having the other app running on his PC.
I may be doing something wrong conceptually speaking. I know that by sending the params in the $window.location.href = url+params will work but i dont want the credentials travelling in the url. I know i can encode them but lets try something else before giving up if it is possible.
The problem here is using the wrong Content-Type for the submission. The server will look for POST-vars in the body. The proper value to use is:
Content-Type: application/json
(instead of application/x-www-form-urlencoded;charset=utf8)

Angular REST returning Syntax error on JSON parse

I am getting an error "syntax error JSON parse unexpected end of data at line 1 column 1 of json data". The RESTful service is runnning, a straight test returns valid json data (verified at http://jsonlint.com/)
[{"id":2,"name":"Flourescent Penetrant Inspection","description":"The fluorescent penetrant inspection process.","abbreviation":"FPI","tempId":null,"processType":"INSPECTION","indicationTypes":[{"id":1,"name":"Crack","description":"An identified crack on the piece.","abbreviation":"","tempId":null,"groupName":"","markupType":"LINE","useSizeDescription":true,"sizeDescription":"<= 1 in.::> 1 in.","rejectReason":"Crack","defaultDisposition":"MRB"},{"id":2,"name":"Inclusion","description":"An identified inclusion on the piece.","abbreviation":"","tempId":null,"groupName":"","markupType":"DOT","useSizeDescription":false,"sizeDescription":"","rejectReason":"Inclusion","defaultDisposition":"REWORK"}]},{"id":4,"name":"CMM","description":"The CMM process.","abbreviation":"CMM","tempId":null,"processType":"INSPECTION","indicationTypes":[]}]
The error in the HTTP response, yet it is returning a 200 message. The angular app is seeing it as an empty array. Any ideas?
The applicable part of the Controller is:
indicationTypeController.constant("indicationTypeUrl", "http://localhost:8080/services/api/indication-types.json");
indicationTypeController.controller('indicationTypeController', function ($scope, $http, $resource, indicationTypeUrl) {
$scope.indicationTypeResource = $resource(indicationTypeUrl+":id", { id: "#id" },
{ 'create': {method: "POST"}, 'update': {method: "PUT"}
});
$scope.listIndicationTypes = function () {
$http.get(indicationTypeUrl)
.success(function(data){
$scope.indicationTypes = data;
});
//$scope.indicationTypes = $scope.indicationTypeResource.query();
}
. . . .
As you can see I am currently using a $http.get, I also tried a query().
Any
Usually, the $http promise returns an object that contains the headers and the data. In your success handler for the $http, you have
$http.get(indicationTypeUrl)
.success(function(data){
$scope.indicationTypes = data;
});
I'm pretty sure that data is the full response and you need to get the specific data by using the data property of this object. Therefore, this would become the following:
$http.get(indicationTypeUrl)
.success(function(data){
$scope.indicationTypes = data.data;
});
In other implementations, instead of the passed in parameter being called data, it's usually called result, so that you can reference the contained data like result.data instead of data.data
The other thing to make sure of is that the Content-Type is set appropriately between the server and client. If it's not application\json you'll probably run into issues.
This is an CORS issue, please add the following to the response header, before sending the result.
"Access-Control-Allow-Origin" : "*"
For instance, if you are using play server (Java code) to serve the request, the following statement should be added to the method where you are returning the data from
response().setHeader("Access-Control-Allow-Origin", "*");

angularjs custom REST action and error handling

I'm having some trouble with error handling in a little angularjs application. I'm interacting with a Flask backend and a Postgres DB.
I have a factory service
appointServices.factory('Appointments', ['$resource', function($resource){
return $resource(someUrl, {}, {
query: { ... }
,
create: {
method: 'POST'
,url: 'http://somedomain:port/new/:name/:start/:end/:treatment'
,params: { start: '#start', end: '#end', name: '#name', treatment: '#treatment' }
,isArray:false
}
});
}
]);
Inside a controller I'm making the following call
Appointments.create($scope.appointment, function(value, responseHeaders) {
// success handler
console.debug('success: ', JSON.stringify(value));
}, function(httpResponse) {
// error handler
console.debug('error: ', JSON.stringify(httpResponse));
});
Here $scope.appointment contains the relevant parameters for the create action.
Now, in the backend I'm able to catch DB errors involving constraints and I'm trying to return an error code with a 'meaningful' message. So I have a python method
def create(name, start, end, treatment):
try:
...
transaction_status = 'ok'
code = 200
except IntegrityError as e:
...
transaction_status = 'IntegrityError'
code = 500
finally:
...
return make_response(transaction_status, code)
Everything works fine, I'm able to talk to the backend, create new data and insert this in the DB. As I said, any violation of the constraints is detected and the backend responds
curl -X POST "http://somedomain:port/new/foo/bar/baz/qux" -v
...
< HTTP/1.0 500 INTERNAL SERVER ERROR
...
IntegrityError
So, the problem is, no matter whether the action create was successful or not, the intended error handler specified inside the controller is always fired. Moreover, I always end up with a status code 404 in the httpResponse. Firebug shows correctly the code 500 as above, though.
Anybody has any idea of why I'm getting this behavior?
Any suggestions on how to improve the error handling mechanism are also welcome.
Thx in advance.
P.S. Following the documentation on $resource I have also tried variations on the factory service call, e.g.
Appointments.create({}, $scope.appointment, successCallback, errorCallback);
Appointments.create($scope.appointment, {}, successCallback, errorCallback);
with the same results.
Update:
Forgot to mention the important fact that I'm interacting with the backend via CORS requests. The POST request in create above is having place with the OPTIONS method instead. As I mentioned everything is working correctly except for the error response.
Under further investigation, I tried to isolate the factory service, in case I did something wrong, and I also tried the approach shown in the credit card example ($resource docs), but with no positive result.
However, I came up with two workarounds. Firstly, I was able to create a plain JQuery POST request, as in the example shown in the docs. This time, the request is not replaced by OPTIONS and I got the error code correctly.
I also managed to connect to the backend with the low-level $http service as follows:
var urlBase = 'http://somedomain:port/new/:name/:start/:end/:treatment';
var url = urlBase.replace(/:name/g, $scope.appointment.name);
url = url.replace(/:start/g, $scope.appointment.start);
url = url.replace(/:end/g, $scope.appointment.end);
url = url.replace(/:treatment/g, $scope.appointment.treatment);
// force method to be POST
var futureResponse = $http({ method: 'POST', url: url });
futureResponse.success(function (data, status, headers, config) {
console.debug('success: ', JSON.stringify(data));
});
futureResponse.error(function (data, status, headers, config) {
console.group('Error');
console.debug(JSON.stringify(status));
console.debug(JSON.stringify(data));
console.groupEnd();
});
This time, as in the case of JQuery, the request is done effectively with POST and error codes are correctly received.
Notice also that I'm not calling $http.post but I set the method to POST as part of the object parameter to $http, otherwise the connection takes places with OPTIONS as before.
Still trying to figure out what is happening with $resource.

Restangular POST data not being read by Django

I've done a lot of searching and nothing seems to fully address this. I've created a REST API that has a resource to send a message. The path is /api/v1/conversation/{type}/{id}/message. Placing a POST call to that URI will create a message for the given conversation.
Everything works great if I just use $.post('/api/v1/conversation/sample/sample/message', {message: "All your base are belong to us"});
However, I'd like to use Restangular, and for some reason, it is sending the POST data in a way that I have to work with request.body instead of request.POST.get('message'). This is terribly inconvenient if I have to do this with every single server side API.
Here's my Restangular code:
conversation = Restangular.one('conversation', scope.type).one(scope.type_id);
conversation.post('message', {message: "All your base..."})
To clarify, it is POSTing to the correct URI, it just is sending the post data as a payload instead of as form data. How can I configure it to send the post as form data?
Edit:
As a side note, I was able to mitigate this issue by creating a utility function:
def api_fetch_post(request):
post = request.POST
if not post:
try:
post = json.loads(request.body.decode(encoding='UTF-8'))
except:
pass
return post
This way I can accept either type of POST data. Regardless, is there a way to send form data with Restangular?
Yes, there is.
var formData = new FormData();
formData.append('message', $scope.message);
// Or use the form element and have formData = new FormData(formElement).
Restangular.one('conversation', $scope.type).one($scope.type_id)
.withHttpConfig({transformRequest: angular.identity})
.post(formData, null, {'Content-Type': undefined})
.then(function(response){
// Do something with response.
});

Resources