JS Fetch api and Symfony2 FOSRestBundle - javascript

Currently I am trying to get a response from my Symfony2 FOSRest Controller using Javascript Fetch API. In my controller I am serving a response with the following code:
return View::create()
->setStatusCode(200)
->setData(array('success'=>true));
And in my JS I am getting it with this:
fetch(url, 'get').then(
function (response) {
if (response.status !== 200) {
console.log('Problem, status: ' + response.status);
return;
}
response.json().then(function (data) {
console.log('OK');
if (typeof callback == 'function')
return callback(data);
});
}
).catch(function (err) {
Console.log(err);
});
As a result my controller is giving me a pure json which I can see (in Chrome Dev Tools under Response section) if I type my url directly into browser, but when js code is executed I see the following error:
Uncaught (in promise) SyntaxError: Unexpected token <
which is related to my initial file which begins from !doctype html. In my debugger if I log response.body I see that it is ReadableByteStream, but not my json. I think that the problem is somewhere in Symfony because I can read my json if I send it from regular .php file but not from RESTFul controller. Any help would be appreciated.
UPD:
when I changed response.json() to response.text() I finally got the data)) Is there any reason for that? And in addition in my url I have query string parameters (like ?par1=1&par2=2) which I want to pass to my REST Controller and which I get when I again type my url into browser directly with the following method:
$data = $request->query->get('data');
But when I pass it with JS fetch (in url parameter) no data is transferred to controller. Any idea what to do in this case? Thank You
UPD2
My symfony config.yml
fos_rest:
param_fetcher_listener: true
body_listener: true
format_listener: true
view:
formats:
json: true
xml: false
html: false
rss: false
templating_formats:
json: false
xml: false
html: false
rss: false
view_response_listener: 'force'
sensio_framework_extra:
view: { annotations: false }
router: { annotations: true }

Try to add this in your config :
fos_rest:
# ...
view:
# ...
formats:
json: true
If it doesn't work, add the following :
fos_rest:
# ...
format_listener:
rules:
- { path: '^/yourApiPrefix', priorities: ['json'], fallback_format: json, prefer_extension: false }

Related

Multiple parameters are not being send properly in get method using Angular 5 and Node js backend

I am trying to create a API using nodejs and access it using GET method by sending parameters using Angular 5 GET method. When I am testing my API using Postman, it works fine, but sending the GET request from Angular is not giving me the result. My node js router for receiving multiple parameters code is as follow:
router.get('/:min&:max',(req,res,next)=> {
Image.find({hue: {$gt:req.params.min,$lt:req.params.max}})
.select('name url hue')
.exec()
.then(docs => {
const response={
images: docs.map(doc=> {
return {
name: doc.name,
url: doc.url,
hue: doc.hue,
_id: doc._id,
}
})
}
res.status(200).json(docs);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
})
My angular GET method goes like this :
getSearchedImages(min, max) {
let params = {
'min': String(min),
'max': String(max)
}
this.http.get('http://localhost:3000/', { params: params})
.subscribe(val=> console.log(val))
}
Is there any problem in Angular part or is my code in Node is to be adjusted
Use POST if you want to pass parameters in request body. Otherwise, if you like GET, pass parameters in URL.
HTTP itself doesnt restrict this, but some front-end implementations do

Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing From a Fetch Call

I want to fetch an JSONArray that includes a json and a file to my server, but i get this error
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public java.lang.String
controllers.IngestController.ingestDataFile(org.json.JSONArray)
My fetch call consists of
var data = [
{
"header": headerIngestion
},
{
"body": this.state.csv
}
];
fetch('http://localhost:8080/ingest', {
method: 'POST',
body: data
})
.then...
headerIngestion is just a regular JSON, csv is a csv file upload.
My server method is
#PostMapping(INGEST_URL)
public String ingestDataFile(#RequestBody JSONArray jsonArr) {
System.out.println(jsonArr.toString());
return "temporary return";
}
Your json is not formatted correctly so it failed to transform to JSONArray. Try this. I have not tested it myself by running it so may not be prefectly framed json but you get the point
body: JSON.stringify({[ { header: 'headerIngestion' }, { body: 'this.state.csv' } ]})

JsTree and Laravel Trouble

I'm following this guide to setup JsTree with lazy load using Ajax in my Laravel 5.5 app .
This is my controller: https://gist.github.com/aaronr0207/7fa0a38f40bfd2f728a15d655254f82d
My View:
https://gist.github.com/aaronr0207/f87720263e3d6026b04b00c08bae5cb2
My JsTree class is exactly the same I didn't make any change.
Actually I'm getting the following error on chrome's console:
d9973d3e-1476-4453-a013-9e9c8430bcba:1 Uncaught TypeError: Cannot read property 'children' of undefined
But when I dump the response to debug it (at the end of TreeViewController data method):
dd(response()->json($tree->build()));
It works...
My response looks like this (when I die-dump it):
Any idea? Thank you
EDIT1: If I return a simple json_encode($tree->build) there are no errors but it shows an empty tree... and the response looks like this:
EDIT2: got it! But now there are a new issue... All I did to solve it was change the url string with a callback:
$('#jstree').jstree({
'core': {
'data': {
'url': function (node) {
return '{!! route('tree.data') !!}' ;
},
'data': function (node) {
console.log(node);
return {'id': node.id};
}
}
}
});
But now when I fetch next level directories, if they have another directorie inside it fails without error:
Test1 content is the following:
If I delete test1/test2 folder, it works showing:
Same when I delete the txt file...What is happening now? Maybe this is a new question so I'll post my solution to the main problem and I'll accept it.
I suspect your named route is not working correctly. In your TreeController.php, change the route tree/route as follows:
Route::get('tree/route', 'TreeController#data')->name('tree.data');
got it! All I did to solve it was change the url string with a callback:
$('#jstree').jstree({
'core': {
'data': {
'url': function (node) {
return '{!! route('tree.data') !!}' ;
},
'data': function (node) {
console.log(node);
return {'id': node.id};
}
}
}
});
This could be caused by the escaping in the response. Can you dd($request->id) when the id is set?

Symfony: Send variable throught GET to handler from Ajax

I would like to use AJAX in my Symfony3.0.3 project.
The communication works, but I can't get variable from JS to the handler. In the direction handler to JS, it works fine.
I'm trying to get the variable from the request with "$request->query->get('id'))" but I only get "null".
In an other way I'm trying to use the variable from the URL but I get this error:
"An exception has been thrown during the rendering of a template ("Some mandatory parameters are missing ("id") to generate a URL for route "admin_ajax".") in CommonBundle:Default:index.html.twig at line 421."
I don't mind using a solution or an other (I'll use the best one depending of your advices), but I still would like the solution for both error.
JS
function selectClient(idClient)//idClient = 1
{
alert(idClient);
$.post('{{path('admin_ajax')}}',{idClient: id},
function(response)
{
if(response.code == 100 && response.success)
{
alert(response.id);//Show null if using $request->query->get('id')) in handler but should be 1
}}, "json");
}
routing:
admin_ajax:
defaults: { _controller: CommonBundle:Default:getClient }
path: /ajax/{id}
handler:
public function getClientAction($id)
{
$request = $this->container->get('request_stack')->getCurrentRequest();
$isAjax = $request->isXMLHttpRequest();
if ($isAjax)
{
$response = array("code" => 100, "success" => true, "id" => $request->query->get('id'));
return new Response(json_encode($response));
}
$response = array("code" => 0, "success" => false);
return new Response(json_encode($response));
}
EDIT:
Thank for Rim, and Rvanlaak answer, I used the FOSJsRoutingBundle.
JS
function selectClient(idClient)
{
$.get(Routing.generate('ajax_getclient', { id:idClient }),
function(response)
{
if(response.code == 100 && response.success)
{
alert(response.id);
}
else
}, "json");
}
routing:
ajax_getclient:
defaults: { _controller: CommonBundle:Default:getClient }
path: /ajax/{id}
options:
expose: true
Note that the option "expose: true" was necessary to works.
Thats because the twig is executing before javascript so he is not reconizing the client id param
i had the same problem and resolve it using FOSJSRoutingBundle see this post :
Ajax url parametetr using Twig path

Backbone model.destroy() invoking error callback function even when it works fine?

I have a Backbone.js model that I'm trying to destroy when the user clicks a link in the model's view. The view is something like this (pseudocode because it's implemented in CoffeeScript which can be found at the bottom of the question).
var window.ListingSaveView = Backbone.View.extend({
events: {
'click a.delete': 'onDestroy'
},
onDestroy: function(event){
event.preventDefault();
this.model.destroy({
success: function(model, response){
console.log "Success";
},
error: function(model, response){
console.log "Error";
}
});
}
});
When I click the delete link in the browser, I always get Error logged to the console even though my server records successful destruction of the associated database record and returns a 200 response. When I refresh the page (causing the collection to re-render from the DB) the model I deleted will be gone.
One interesting this is that when I log the response in the error callback, it has statuscode 200 indicating success but it also reports statusText: "parseerror" whatever that means. There is no error in my server logs.
What am I doing wrong?
This is the response from the server:
Object
abort: function ( statusText ) {
always: function () {
complete: function () {
done: function () {
error: function () {
fail: function () {
getAllResponseHeaders: function () {
getResponseHeader: function ( key ) {
isRejected: function () {
isResolved: function () {
overrideMimeType: function ( type ) {
pipe: function ( fnDone, fnFail ) {
promise: function ( obj ) {
readyState: 4
responseText: " "
setRequestHeader: function ( name, value ) {
status: 200
statusCode: function ( map ) {
statusText: "parsererror"
success: function () {
then: function ( doneCallbacks, failCallbacks ) {
__proto__: Object
Here is the server action that destroy interacts with (Ruby on Rails)
# DELETE /team/listing_saves/1.json
def destroy
#save = current_user.team.listing_saves.find(params[:id])
#save.destroy
respond_to do |format|
format.json { head :ok }
end
end
And here is the actual CoffeeScript implementation of the Backbone View for people who prefer it like that:
class MoveOutOrg.Views.ListingSaveView extends Backbone.View
tagName: 'li'
className: 'listing_save'
template: JST['backbone/templates/listing_save']
events:
'click a.delete_saved': 'onDestroy'
initialize: ->
#model.bind 'change', this.render
render: =>
renderedContent = #template(#model.toJSON())
$(#el).html(renderedContent)
this
onDestroy: (event) ->
event.preventDefault() # stop the hash being added to the URL
console.log "Listing Destroyed"
#model.destroy
success: (model, response)->
console.log "Success"
console.log model
console.log response
error: (model, response) ->
console.log "Error"
console.log model # this is the ListingSave model
console.log response
#David Tuite comment:
"Ok I figured it out. It seems that Backbone expects the JSON response to be a JSON serialization of the record that was destroyed. However, Rails controller generators only return head :ok by default. I changed my JSON response to be render json: #listing_save where #listing_save is the record I just destroyed and it registers a success."
FYI - when you're doing a destroy, you don't need to return the full json for the destroyed model. you can return an empty json hash and it will work just fine. the only time you need to return the json for the model is on a save / update.
I had this same problem. In my delete method on the server (java), I didn't return anything. Just status 200/OK (or 204/No content). And so the "parsererror" problem was caused by jquery trying to convert the empty response into JSON, which failed (since "json" is the default data type).
My solution was to use the "text" dataType instead, which can be set in the options:
model.destroy({ dataType: "text", success: function(model, response) {
console.log("success");
}});
Your response must have status code 204 as you won't return any content. Since backbone uses a REST interface you should return different http status codes depending on the task.
Are you sure of your URL ? Do you append a .json at the end of the Backbone.Model url ? Since you check this on your server side (respond_to do |format| ... end), you might not send the correct head :ok response
Try with this destroy rails method to test if this is the problem :
def destroy
#save = current_user.team.listing_saves.find(params[:id])
#save.destroy
head :ok
end
Using the Slim Framework on an LAMP server you can add a Response Status to DELETE routes (or custom routes that don't return anything)
$app->response()->status(204);//204 No Content
this also sets the Content-Type back to text/html to allow for the empty body

Categories