RESTful Express Mongoose & Backbone - Backbone model.remove() not working - ajax

I'm developing a Node app using Express, Mongoose and Backbone with Marionette.
All routes are working well except the delete route.
If I call this.model.destroy, I always get this error:
DELETE http://localhost:3000/api/user 404 (Not Found)
The 404 is returned in Express's delete route, like if Express didn't support it, but I've seen numerous examples across the web using it.
Here's my setup:
Mongoose Schema:
var UserSchema = new mongoose.Schema(
{
name: String,
email: String,
age: Number
});
User = mongoose.model('User', UserSchema);
ExpressJS Route: (not working)
app.del('/api/user/:id', user.remove);
OR
app.delete('/api/user/:id', user.remove);
This route is called by backbone model.destroy(), but returns error 404.
ExpressJS user.js controller: (works but is not reached because of the 404 before)
exports.remove = function(req, res)
{
var id = req.params.id;
User.findById(req.params.id, function(err, user)
{
user.remove(function(err)
{
if(err) res.json(err);
res.json('all good');
});
});
};
BackboneJS Model
var User = Backbone.Model.extend({
idAttribute: "_id",
url: '/api/user/',
});
BackboneJS client View
var UserView = Backbone.Marionette.ItemView.extend(
{
template: Handlebars.compile($('#userView').html()),
events:
{
'click .delete-button': 'deleteUser'
},
deleteUser: function(event)
{
this.model.remove();
}
});
I always get this error:
DELETE http://localhost:3000/api/user 404 (Not Found)
HOWEVER it works if I use this direct ajax call:
jQuery.ajax({
url:'/api/user/' + this.model.id,
type: 'DELETE',
success:function(data, textStatus, jqXHR)
{
}
});
So, why does this work if I call the route via Ajax, if Backbone internally also uses Ajax? Why does Backbone fail to make such a simple model.destroy()?
Is there a way to configure Backbone Model.destroy method to work well like the Ajax example above? Thanks

Found the problem. Backbone model.remove() was not sending the id because I was using "url" in this way:
Backbone.Model.extend({
url: '/users',
//...
});
That will tell Backbone to use exactly /users as the URL for all actions.
To ensure sending the id using "url", one can use a function:
url: function() {
return '/list_items/' + encodeURIComponent(this.id)
}
Or even better use "urlRoot" instead of "url", let the default "url" function add the id:
urlRoot: '/users'
Working like a charm with urlRoot

Related

I can't use json to make a Post request to my web api using react

I created a webapi in ASP.NET Core, and I need to consume it using React, the web api works normally, if I use curl or postman among others, it works normally. The problem starts when I'm going to use React, when I try to make any requests for my API with js from the problem.
To complicate matters further, when I make the request for other APIs it works normally, this led me to believe that the problem was in my API, but as I said it works with others only with the react that it does not. I've tried it in many ways.
The API is running on an IIS on my local network
Attempted Ways
Using Ajax
$ .ajax ({
method: "POST",
url: 'http://192.168.0.19:5200/api/token',
beforeSend: function (xhr) {
xhr.setRequestHeader ("Content-type", "application / json");
},
date: {
name: 'name',
password: 'password'
},
success: function (message) {
console.log (message);
},
error: function (error) {
/ * if (error.responseJSON.modelState)
showValidationMessages (error.responseJSON.modelState); * /
console.log (error);
}
});
Using Fetch
const headers = new Headers ();
headers.append ('Content-Type', 'application / json');
const options = {
method: 'POST',
headers,
body: JSON.stringify (login),
mode: 'cors' // I tried with cors and no-cors
}
const request = new Request ('http://192.168.0.19:5200/api/token', options);
const response = await fetch (request);
const status = await response.status;
console.log (response); * /
// POST adds a random id to the object sent
fetch ('http://192.168.0.19:5200/api/token', {
method: 'POST',
body: JSON.stringify ({
name: 'name',
password: 'password'
}),
headers: {
"Content-type": "application / json; charset = UTF-8"
},
credentials: 'same-origin'
})
.then (response => response.json ())
.then (json => console.log (json))
Using Request
var request = new XMLHttpRequest ();
request.open ('POST', 'http://192.168.0.19:5200/api/token', true);
request.setRequestHeader ('Content-Type', 'application / json; charset = UTF-8');
request.send (login);
ERRORS
Console
Network tab
When I do this without being change the content type to JSON it works
because the API returns saying that it is not a valid type.
Apart from allowing CORS in you .NET configuration. You also need to return 200 OK for all OPTION requests.
Not sure how it's done in .NET but just create a middleware that detects the METHOD of the request, and if it's OPTIONS, the finish the request right there with 200 status.
Well I had the same issue and it seems that you need to add the action to the HttpPost attribute in the controller.
Here is an example.
[HttpPost("[action]")]
public void SubmitTransaction([FromBody] SubmitTransactionIn request)
{
Ok();
}
Try like this
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(option => option.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
app.UseAuthentication();
app.UseMvc();
}

POST binary data from browser to JFrog / Artifactory server without using form-data

So we get a file (an image file) in the front-end like so:
//html
<input type="file" ng-change="onFileChange">
//javascript
$scope.onFileChange = function (e) {
e.preventDefault();
let file = e.target.files[0];
// I presume this is just a binary file
// I want to HTTP Post this file to a server
// without using form-data
};
What I want to know is - is there a way to POST this file to a server, without including the file as form-data? The problem is that the server I am send a HTTP POST request to, doesn't really know how to store form-data when it receives a request.
I believe this is the right way to do it, but I am not sure.
fetch('www.example.net', { // Your POST endpoint
method: 'POST',
headers: {
"Content-Type": "image/jpeg"
},
body: e.target.files[0] // the file
})
.then(
response => response.json() // if the response is a JSON object
)
You can directly attach the file to the request body. Artifactory doesn't support form uploads (and it doesn't look like they plan to)
You'll still need to proxy the request somehow to avoid CORS issues, and if you're using user credentials, you should be cautious in how you treat them. Also, you could use a library like http-proxy-middleware to avoid having to write/test/maintain the proxy logic.
<input id="file-upload" type="file" />
<script>
function upload(data) {
var file = document.getElementById('file-upload').files[0];
var xhr = new XMLHttpRequest();
xhr.open('PUT', 'https://example.com/artifactory-proxy-avoiding-cors');
xhr.send(file);
}
</script>
Our front-end could not HTTP POST directly to the JFrog/Artifactory server. So we ended up using a Node.js server as a proxy, which is not very ideal.
Front-end:
// in an AngularJS controller:
$scope.onAcqImageFileChange = function (e) {
e.preventDefault();
let file = e.target.files[0];
$scope.acqImageFile = file;
};
// in an AngularJS service
createNewAcqImage: function(options) {
let file = options.file;
return $http({
method: 'POST',
url: '/proxy/image',
data: file,
headers: {
'Content-Type': 'image/jpeg'
}
})
},
Back-end:
const express = require('express');
const router = express.Router();
router.post('/image', function (req, res, next) {
const filename = uuid.v4();
const proxy = http.request({
method: 'PUT',
hostname: 'engci-maven.nabisco.com',
path: `/artifactory/cdt-repo/folder/${filename}`,
headers: {
'Authorization': 'Basic ' + Buffer.from('cdt-deployer:foobar').toString('base64'),
}
}, function(resp){
resp.pipe(res).once('error', next);
});
req.pipe(proxy).once('error', next);
});
module.exports = router;
not that we had to use a PUT request to send an image to Artifactory, not POST, something to do with Artifactory (the engci-maven.nabisco.com server is an Artifactory server). As I recall, I got CORS issues when trying to post directly from our front-end to the other server, so we had to use our server as a proxy, which is something I'd rather avoid, but oh well for now.

how to make a restAPI call to laravel using react

Currently, my restAPI and my App are both hosted on XAMPP. My restAPI url is laravel.dev.
My POST route looks as so...
Route::post('/content', 'Test#save');
and my Controller...
class Test extends Controller
{
public function save()
{
return "here";
}
}
Pretty simple, but now I want to make a POST request to this route from my App. I am trying to that using react's fetch, but I do not know what URL to put since my attempt does not work...
fetch('laravel.dev', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
});
I don't care about passing anything to the route, I just want a successful call to the restAPI server. Right now I'm getting...
POST http://localhost/App/src/laravel.dev 404 (Not Found)
That is also the wrong path as well, as /App is my app and I am trying to call the restAPI server.
What do I need to change to make a successful call?
fetch needs a protocol. Right now it tries to request a "local" resource. Also, add your endpoint:
fetch('http://laravel.dev/content', {
// ...
});

Updating documents of mongodb using react nodejs and ajax

Hii I started practicing react and mongodb with nodejs.
By using react I get the data with the help of nodejs...
Now I am trying to update or delete documents of mongodb with the help of nodejs....
I wrote services for them in nodejs but I am not getting any clue of how to connect it with React.
Plz help me to overcome this problem.
Thanks in advance...
If you go to the react website, and look at their tutorial they have a great example of a ajax call done.
Basically you write your ajax function first so it might look something like this if it is a GET request :
your nodejs code:
//the route we get our users at is allUsers
app.get('/allUsers, function(req, res) {
User.find({}, function(err, userarray) { //we grab all users from our mongo collection, and that array of users is called userarray
res.json(userarray); //we return the json with it
});
});
Now for the react part:
var Users = React.createClass({
getUsers : function() { //we define a function for getting our users
$.ajax({ //call ajax like we would in jquery
url: '/allUsers', //this is the url/route we stored our users on
dataType: 'json',
success: function(data) { //if we get a Success for our http get then..
this.setState({user:data}); //set the state of our user array to whatever the url returned, in this case the json with all our users
}.bind(this),
error: function(xhr, status, err) { //error logging and err tells us some idea what to debug if something went wrong.
console.log("error");
console.error(this.props.url,status, err.toString());
}.bind(this)
});
},
getInitialState: function() { //setting our initial state for our user array we want to use in our react code
return {
users: [], //initialize it empty, or with whatever you want
}
},
componentDidMount : function() {
this.getUsers(); //we are invoking our getUsers function here, therefore performing the ajax call
},
render : function() {
return(
//do what we want to do with our array here I guess!
<div>
<PrintArray users = {this.state.users} />
</div>
)
}
});
//Our new Class called Printarray
var PrintArray = React.createClass({
render : function() {
//Psuedocode
return(
ul {
this.props.users.map(function(user){ //we are mapping all our users to a list, this.props.users is inheritance what we passed down from our Users class
return (
<li key = user.id> user.name </li>
)
})
)
}
</ul>
});
And then finally just call our main class,
React.render(<Users />,
document.getElementById(domnNode)); //your div's id goes here
I commented out the code, if you have anymore questions feel free to ask! I don't know if you wanted to do a post method either, but its similar. You just change the GET to a POST, and instead of the function having no parameters, you most likely want a parameter for it, so it might be something like :
sendNewUser : function(data) {
//do ajax post stuff here
}
and in render:
render : function(){
sendNewUser(blah);
}
except you would probably have a form or something or even another class that deals with adding a new user. The question seemed really broad so I just gave a general overview of how I would do it!

NodeJS unable to response.write to the browser when there is delay in callbacks

i'm using simple MVC structure by Nathan Broslawsky. i have these code below.
ArticleProviderDBController.prototype.Show = function(data) {
//Init Model
var res = this.Response;
var model = this.getModel();
var view = this.getView("ArticleProviderDB");
model.findAll(function(error, article_collections){
if( error ) console.log(error);
view.renderGH(res, data, article_collections); //this will actually call the renderGH function to serve a html file with data from DB but it is not working.
res.write('inside callback'); //this will not.
//res.end();
});
//console.log(_self.Response);
res.write('outside callback'); //this will be shown on my browser.
//res.end();
}
actually i try to follow what people have done using expressjs
app.get('/', function(req, res){
articleProvider.findAll( function(error,docs){
res.render('index.jade', {
locals: {
title: 'Blog',
articles:docs
}
});
})
});
but seems like it is not working.
i also saw a post NodeJS response.write not working within callback posted recently but his solution is not working for me. My main objective is to use simple MVC structure created with Nodejs without the use of other templates such as expressjs to serve html with DB query. thank you.

Resources