I am implementing REST APIS using Express and Postgres. In an endpoint, I would like to first delete all the instances from a table by FK user_id, and then insert several new instances with the same user_id. I'm wondering which http method should I use in this case? Currently I use POST but I don't know if this is the appropriate way. It seems that using PUT also works fine.
router.post('/myTable', auth, async (req, res) => {
const client = await pool.connect();
try {
await client.query('BEGIN');
const { records } = req.body;
await client.query('DELETE FROM my_table WHERE user_id=$1', [req.user_id]);
for (i in records) {
await client.query('INSERT INTO my_table (name, user_id) VALUES ($1, $2)',[records[i], req.user_id]);
}
await client.query('COMMIT');
res.send();
} catch (error) {
console.log(error);
await client.query('ROLLBACK');
} finally {
client.release();
}
});
PUT is for creating/replacing the resource at the URI you specified.
So if a resource exists, it has a URI that client knows, and with a PUT request you are replacing what's there, PUT makes the most sense.
One great benefit of PUT over POST is that PUT is idempotent.
So if you are sending a PUT request to a /myTable endpoint, the implied meaning is that you are replacing myTable, and a subsequent GET request on that same endpoint would give you a semantically similar response of what you just sent.
If any of my above assumptions are wrong, chances are you'll want POST, which is more of a general catch-all method for making changes with fewer restrictions. The downside is that I think it's less obvious what the operation of a given POST request is without inspecting/understanding the body and you lose the idempotence benefit too.
Currently I use POST but I don't know if this is the appropriate way.
Rule #1: if you aren't sure, it is okay to use POST.
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”
It seems that using PUT also works fine.
In a sense, any method "works fine" at the origin server. HTTP defines request semantics -- what the messages mean. It doesn't constrain the implementation.
However, general purpose clients are going to assume that your server understands GET/HEAD/POST/PUT etc exactly the same way that every other web server understands them. That's a big part of the power of the REST architectural style - any standards compliant client can talk to any standards compliant server, and it just works. Furthermore, it continues to work exactly the same way if we stick any standards compliant cache/proxy in between them.
But if you respond to a PUT request with 204 No Content, then general purpose components are going to understand that to mean the same thing that any other server would return. Which is to say, your server is responsible if your deviation from the standard results in loss of property.
You can check the answers here for your reference. They are very well explained.
PUT vs. POST in REST
But since both could serve the same purpose and would only depend on your preference or requirements, I usually use post for creating a resource and put for updating one as a practice.
Related
I am sorry for how I have framed the question in the title but I have started programming very recently so once again, I am really sorry.
I am developing a project with React js as my front-end and node js as my backend, I have been successful in doing some basic test api calls to confirm the connection between the two but now, how am I supposed to actually process different actions. For example, while a user is logging in, I need to first check if they are an existing user or not, sign them in if they are not, deleting a user account, changing username, etc.
I tried very hard to look for relevant articles but all I can find are basic "one-time" api calls, what am I supposed to do for an entire batch of operations? From what I have understood, the process of sending a request from React to getting it processed in Node js is like this:
react js ======>
(request for operation) node js ======>
(process the operation) ======>
send a response back to react
Please correct me if there are any mistakes in my question...
Thanks a lot!
This question is really broad, so I'm going to focus in on this part at a high level:
I tried very hard to look for relevant articles but all I can find are basic "one-time" api calls, what am I supposed to do for an entire batch of operations?
I'm guessing when you talk about requests and APIs you're talking about HTTP requests and REST APIs, which are fundamentally "stateless" kinds of things; HTTP requests are self-contained, and the backend doesn't have to keep track of any application state between requests in order to speak HTTP.
But backend applications usually do maintain state, often in the form of databases. For example, many REST APIs expose CRUD (create, read, update, and delete) operations for important business entities — in fact, Stack Overflow probably does exactly this for answers. When I post this answer, my browser will probably send some kind of a "create" request, and when I inevitably notice and fix a typo I will send some kind of "update" request. When you load it in your browser, you will send a "read" request which will get the text of the answer from Stack Overflow's database. Stack Overflow's backend keeps track of my answer between the requests, which makes it possible to send it to many users as part of many different requests.
Your frontend will have to do something similar if your project does things which involve multiple interdependent requests — for example, you would need to keep track of whether the user is authenticated or not in order to show them the login screen, and you would need to hold onto their authentication token to send along with subsequent requests.
Edit: Let's walk through a specific example. As a user, I want to be able to create and read notes. Each note should have a unique ID and a string for its text. On the backend, we'll have a set of CRUD endpoints:
var express = require(“express”);
var router = express.Router();
class Note {
constructor(id, text) {
this.id = id;
this.text = text;
}
}
// This is a quick and dirty database!
notes = {};
router.put("/note/:id", function(req, res) {
notes[req.params.id] = "hello"; // TODO: accept text as well
res.send("");
});
router.get(“/note/:id”, function(req, res) {
res.send(notes[req.params.id].text);
});
module.exports = router;
Then on the client side, one could create a note and then read it like this:
// this request will create the note
fetch("http://localhost:9000/note/42", { method: 'PUT', body: 'hello note!' });
// this request will read the note, but only after it is created!
fetch("http://localhost:9000/note/42")
.then(res => res.text())
.then(res => console.log(res));
I am new to node.js and am acquainting myself with Express. The following code is my source of confusion:
var server = http.createServer(handleRequest);
function handleRequest(req, res) {
var path = req.url;
switch (path) {
case "/n":
return renderPage_1(req, res);
default:
return renderPage_2(req, res);
}
}
I understand that the server needs to accept an HTTP request(req). However, if we are returning a response, why is the response also an argument in the callback function? I keep running into a dead-end thinking that it has to do with the scope of the response object, though I am not sure.
I would greatly appreciate clarification on this matter. I have not been able to find a resource that delineates my confusion.
Best,
Abid
I think the answer to your question is that this is how the authors of express decided to implement the library. At a high level, express is really just a light-ish weight wrapper that makes it easy to build middleware based http services with NodeJS. The reason that both the req & res objects are passed to each express middleware function is that in practice, web services are rarely able to fulfill an entire request in a single step. Often services are built as layer of middleware the build up a response in multiple steps.
For example, you might have a middleware function that looks for identity information in the request and fetches any relevant identity metadata while setting some auth specific headers on the response. The request might then flow to an authorization middleware that uses the fetched metadata to determine if the current user is authorized and if the user is not authorized can end the request early by closing the response stream. If the user is authorized then the request will continue to the next piece of middleware etc. To make this work, each middleware function (step of the stack) needs to be able to access information from the request as well as write information to the response. Express handles this by passing the request and response objects as arguments to the middleware function but this is just one way to do it.
Now the authors could have decided to implement the library differently such that each route handler was supposed to return an object such as { status: 200, content: "Hello, world" } instead of calling methods on the response object but this would be a matter of convention and you could pretty easily write a wrapper around express that let you write your services like this if you wanted.
Hope this helps.
In my express app, I have two routes as follows:
router.post('/:date', (req, res) => {
// if date exists, redirect to PUT
// else add to database
})
router.put('/:date', (req, res) => {
// update date
})
If date already exists on a POST call, I want to redirect to PUT. What is the best way to do this using res.redirect?
In the docs, all redirects are to different URL patterns. I would like to keep the URL same and change the rest verb from POST to PUT.
I had a look at this SO question, and added this line in POST:
res.redirect(303, '/:date');
but it did not redirect me to PUT.
What you're trying to do here will not work for several reasons, but lickily you don't need to do any of that - see below.
First problem
The 303 "See Other" redirect that you're using here, by the spec should always be followed by a GET (or HEAD) request, not PUT or anything else. See RFC 7231, Section 6.4.4:
https://www.rfc-editor.org/rfc/rfc7231#section-6.4.4
The relevant part:
The 303 (See Other) status code indicates that the server is
redirecting the user agent to a different resource, as indicated by a
URI in the Location header field, which is intended to provide an
indirect response to the original request. A user agent can perform a
retrieval request targeting that URI (a GET or HEAD request if using
HTTP), which might also be redirected, and present the eventual result
as an answer to the original request. Note that the new URI in the
Location header field is not considered equivalent to the effective
request URI. [emphasis added]
Second problem
The other popular types of redirects - 301 "Moved Permanently" and 302 "Found" in practice usually work contrary to the spec as if they were 303 "See Other" and so a GET request is made.
See List of HTTP status codes on Wikipedia:
This is an example of industry practice contradicting the standard. The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect (the original describing phrase was "Moved Temporarily"), but popular browsers implemented 302 with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two behaviours. However, some Web applications and frameworks use the 302 status code as if it were the 303. [emphasis added]
Third problem
There is a 307 Temporary Redirect (since HTTP/1.1) but it explicitly disallows changing of the HTTP method, so you can only redirect a POST to POST, a PUT to PUT etc. which can sometimes be useful but not in this case - see Wikipedia:
In this case, the request should be repeated with another URI; however, future requests should still use the original URI. In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. For example, a POST request should be repeated using another POST request.
This 307 redirect is still not what you want and even if it was, it is not universally supported as far as I know so it needs to be used with caution.
See also this answer for more info:
Redirect POST to POST using Express JS routes
Your options
You can abstract away your controllers - which you will usually do anyway, for anything complex:
// controllers - usually 'required' from a different file
const update = (req, res) = {
// update date
};
const add = (req, res) => {
if (date exists) {
return update(req, res);
}
// add to database
};
router.post('/:date', add);
router.put('/:date', update);
Or you can abstract parts of your controllers as functions.
Universal controllers
Also, note that you can write universal controllers called for every HTTP method that might work here:
router.use('/:date', (req, res) => {
});
REST
Note that what you're doing here is not a usual RESTful way of naming your paths and it may make sense to use only PUT in your case for both new and updated dates.
Contrary to what many people think PUT doesn't mean UPDATE. It means to put a resource (new or not) to a certain URL (overwriting the old one if it already exists). It's pretty much like writing this in the shell:
echo abc > /the/path/to/file.txt
which will "update" the file if it exists, but it will also create a new file if it doesn't.
So for example, if you have /users/:id path, then you use:
GET /users to get a list of users
GET /users/:id to get a specific user with that ID
POST /user (not /users/:id) to create a new user without providing ID
PUT /users/:id to overwrite an existing user or to create a new user providing an ID
PATCH /users/:id to update the provided fields of user with that ID
Here, as I understand your :date is like an ID, ie. you want to overwrite the record if it already exists and create if if it doesn't exist. In both cases you are providing the :date path component so you might use PUT for all cases just as well.
In other words, you cannot redirect from one HTTP method to another HTTP method (except for GET) but you don't need to do it in this case.
All meteor methods can be called same way from client and server side.
Let's say user knows or can predict all the method names on server, then he is able to call them and use it's result however he want.
example:
A method which performs cross domain http request and return response can be used to overload server by calling huge amounts of data Meteor.call(httpLoad, "google.com");, or a method which load data from mongo can be used to access database documents if the client know document _id Meteor.call(getUserData, "_jh9d3nd9sn3js");.
So, how to avoid this situations, may be there is a better way to store server-only functions than in Meteor.methods({...})?
Meteor methods are designed to be accessed from the client, if you don't want this, you just need to define a normal javascript function on the server. A really basic example would be:
server/server.js:
someFunction = function(params) {
console.log('hello');
}
As long as it's in the server folder, the function won't be accessible from the client.
For coffeescript users, each file is technically a separate scope, so you would have to define a global variable with #, e.g.
#someFunction = (params) ->
console.log 'hello'
or if you want to scope the function to a package:
share.someFunction = (params) ->
console.log 'hello'
If you have methods that need to be accessible from the client but only for say admin users, you need to add those checks at the start of the meteor method definition:
Meteor.methods({
'someMethod': function(params) {
var user = Meteor.user();
if (user && (user.isAdmin === true)) {
// Do something
} else {
throw new Meteor.Error(403, 'Forbidden');
}
}
});
I'm not going to vouch for the security of this example - it's just that, an example - but hopefully it gives you some idea of how you would secure your methods.
EDIT: Noticed the other answers mention using a if (Meteor.isServer) { ... } conditional. Note that if you are doing this inside methods which are also accessible on the client, the user will be still be able to see your server code, even if they can't run it. This may or may not be a security problem for you - basically be careful if you're hardcoding any 3rd-party API credentials or any kind of sensitive data in methods whose code can be accessed from the client. If you don't need the method on the client, it would be better to just use normal JS functions. If you're wrapping the whole Meteor.methods call with a isServer conditional, the code will be on the server only, but can still be called from the client.
as rightly stated in other answers, your methods will always be accessible from the client (per design). yet, there is a simple workaround to check if the call originates from the client or from the server. if you do a
if ( this.connection == null )
this will return true if the method was called from server. like that you can restrict the method body execution to 'secure' calls.
I think this page explains it: http://meteortips.com/first-meteor-tutorial/methods/
I'm quoting:
"The safer approach is to move these functions to the isServer conditional, which means:
Database code will execute within the trusted environment of the server.
Users won’t be able to use these functions from inside the Console, since users don’t have direct access to the server.
Inside the isServer conditional, write the following:
Meteor.methods({
// methods go here
});
This is the block of code we’ll use to create our methods."
and so on. I hope this helps.
With proper app design, you shouldn't care whether a request was through the web UI or via something typed in a console window.
Basically, don't put generic, abuse worthy functions in Meteor.methods, implement reasonable access controls, and rate-limit and/or log anything that could be a problem.
Any server-side function defined in Meteor.methods will have access to the current user id through this.userid. This userid is supplied by Meteor, not a client API parameter.
Since that Meteor Method server-side code knows the login status and userid, it can then do all the checking and rate limiting you want before deciding to do that thing that the user asked it to do.
How do you rate limit? I've not looked for a module for this lately. In basic Meteor you would add a Mongo collection for user actions accessible server-side only. Insert timestamped, userid specific data on every request that arrives via a Meteor method. Before fulfilling a request in the server method code, do a Mongo find for how many such actions occurred from this userid in a relevant period. This is a little work and will generates some overhead, but the alternative of rate-limiting via a server-wide underscore-style debounce leaves a function open for both abuse and denial-of-service by an attacker.
I am more into front end development and have recently started exploring Backbone.js into my app. I want to persist the model data to the server.
Could you please explain me the various way to save the Model data (using json format). I am using Java on server side. Also I have mainly seen REST being used to save data. As i am more into front end dev, i am not aware of REST and other similar stuff.
It would be great if someone could please explain me the process with some simple example.
Basically Models have a property called attributes which are the various values a certain model may have. Backbone uses JSON objects as a simple way to populate these values using various methods that take JSON objects. Example:
Donuts = Backbone.Model.extend({
defaults: {
flavor: 'Boston Cream', // Some string
price: '0.50' // Dollars
}
});
To populate the model there are a few ways to do so. For example, you can set up your model instance by passing in a JSON OR use method called set() which takes a JSON object of attributes.
myDonut = new Donut({'flavor':'lemon', 'price':'0.75'});
mySecondHelping = new Donut();
mySecondHelping.set({'flavor':'plain', 'price':'0.25'});
console.log(myDonut.toJSON());
// {'flavor':'lemon', 'price':'0.75'}
console.log(mySecondHelping.toJSON());
// {'flavor':'plain', 'price':'0.25'}
So this brings us up to saving models and persisting them either to a server. There is a whole slew of details regarding "What is REST/RESTful?" And it is kind of difficult to explain all this in a short blurb here. Specifically with regard to REST and Backbone saving, the thing to wrap your head around is the semantics of HTTP requests and what you are doing with your data.
You're probably used to two kinds of HTTP requests. GET and POST. In a RESTful environment, these verbs have special meaning for specific uses that Backbone assumes. When you want to get a certain resource from the server, (e.g. donut model I saved last time, a blog entry, an computer specification) and that resource exists, you do a GET request. Conversely, when you want to create a new resource you use POST.
Before I got into Backbone, I've never even touched the following two HTTP request methods. PUT and DELETE. These two verbs also have specific meaning to Backbone. When you want to update a resource, (e.g. Change the flavor of lemon donut to limon donut, etc.) you use a PUT request. When you want to delete that model from the server all together, you use a DELETE request.
These basics are very important because with your RESTful app, you probably will have a URI designation that will do the appropriate task based on the kind of request verb you use. For example:
// The URI pattern
http://localhost:8888/donut/:id
// My URI call
http://localhost:8888/donut/17
If I make a GET to that URI, it would get donut model with an ID of 17. The :id depends on how you are saving it server side. This could just be the ID of your donut resource in your database table.
If I make a PUT to that URI with new data, I'd be updating it, saving over it. And if I DELETE to that URI, then it would purge it from my system.
With POST, since you haven't created a resource yet it won't have an established resource ID. Maybe the URI target I want to create resources is simply this:
http://localhost:8888/donut
No ID fragment in the URI. All of these URI designs are up to you and how you think about your resources. But with regard to RESTful design, my understanding is that you want to keep the verbs of your actions to your HTTP request and the resources as nouns which make URIs easy to read and human friendly.
Are you still with me? :-)
So let's get back to thinking about Backbone. Backbone is wonderful because it does a lot of work for you. To save our donut and secondHelping, we simply do this:
myDonut.save();
mySecondHelping.save();
Backbone is smart. If you just created a donut resource, it won't have an ID from the server. It has something called a cID which is what Backbone uses internally but since it doesn't have an official ID it knows that it should create a new resource and it sends a POST request. If you got your model from the server, it will probably have an ID if all was right. In this case, when you save() Backbone assumes you want to update the server and it will send a PUT. To get a specific resource, you'd use the Backbone method .fetch() and it sends a GET request. When you call .destroy() on a model it will send the DELETE.
In the previous examples, I never explicitly told Backbone where the URI is. Let's do that in the next example.
thirdHelping = Backbone.Model.extend({
url: 'donut'
});
thirdHelping.set({id:15}); // Set the id attribute of model to 15
thirdHelping.fetch(); // Backbone assumes this model exists on server as ID 15
Backbone will GET the thirdHelping at http://localhost:8888/donut/15 It will simply add /donut stem to your site root.
If you're STILL with me, good. I think. Unless you're confused. But we'll trudge on anyway. The second part of this is the SERVER side. We've talked about different verbs of HTTP and the semantic meanings behind those verbs. Meanings that you, Backbone, AND your server must share.
Your server needs to understand the difference between a GET, POST, PUT, and DELETE request. As you saw in the examples above, GET, PUT, and DELETE could all point to the same URI http://localhost:8888/donut/07 Unless your server can differentiate between these HTTP requests, it will be very confused as to what to do with that resource.
This is when you start thinking about your RESTful server end code. Some people like Ruby, some people like .net, I like PHP. Particularly I like SLIM PHP micro-framework. SLIM PHP is a micro-framework that has a very elegant and simple tool set for dealing with RESTful activities. You can define routes (URIs) like in the examples above and depending on whether the call is GET, POST, PUT, or DELETE it will execute the right code. There are other solutions similar to SLIM like Recess, Tonic. I believe bigger frameworks like Cake and CodeIgniter also do similar things although I like minimal. Did I say I like Slim? ;-)
This is what excerpt code on the server might look (i.e. specifically regarding the routes.)
$app->get('/donut/:id', function($id) use ($app) {
// get donut model with id of $id from database.
$donut = ...
// Looks something like this maybe:
// $donut = array('id'=>7, 'flavor'=>'chocolate', 'price'=>'1.00')
$response = $app->response();
$response['Content-Type'] = 'application/json';
$response->body(json_encode($donut));
});
Here it's important to note that Backbone expects a JSON object. Always have your server designate the content-type as 'application/json' and encode it in json format if you can. Then when Backbone receives the JSON object it knows how to populate the model that requested it.
With SLIM PHP, the routes operate pretty similarly to the above.
$app->post('/donut', function() use ($app) {
// Code to create new donut
// Returns a full donut resource with ID
});
$app->put('/donut/:id', function($id) use ($app) {
// Code to update donut with id, $id
$response = $app->response();
$response->status(200); // OK!
// But you can send back other status like 400 which can trigger an error callback.
});
$app->delete('/donut/:id', function($id) use ($app) {
// Code to delete donut with id, $id
// Bye bye resource
});
So you've almost made the full round trip! Go get a soda. I like Diet Mountain Dew. Get one for me too.
Once your server processes a request, does something with the database and resource, prepares a response (whether it be a simple http status number or full JSON resource), then the data comes back to Backbone for final processing.
With your save(), fetch(), etc. methods - you can add optional callbacks on success and error. Here is an example of how I set up this particular cake:
Cake = Backbone.Model.extend({
defaults: {
type: 'plain',
nuts: false
},
url: 'cake'
});
myCake = new Cake();
myCake.toJSON() // Shows us that it is a plain cake without nuts
myCake.save({type:'coconut', nuts:true}, {
wait:true,
success:function(model, response) {
console.log('Successfully saved!');
},
error: function(model, error) {
console.log(model.toJSON());
console.log('error.responseText');
}
});
// ASSUME my server is set up to respond with a status(403)
// ASSUME my server responds with string payload saying 'we don't like nuts'
There are a couple different things about this example that. You'll see that for my cake, instead of set() ing the attributes before save, I simply passed in the new attributes to my save call. Backbone is pretty ninja at taking JSON data all over the place and handling it like a champ. So I want to save my cake with coconuts and nuts. (Is that 2 nuts?) Anyway, I passed in two objects to my save. The attributes JSON object AND some options. The first, {wait:true} means don't update my client side model until the server side trip is successful. The success call back will occur when the server successfully returns a response. However, since this example results in an error (a status other than 200 will indicate to Backbone to use the error callback) we get a representation of the model without the changes. It should still be plain and without nuts. We also have access to the error object that the server sent back. We sent back a string but it could be JSON error object with more properties. This is located in the error.responseText attribute. Yeah, 'we don't like nuts.'
Congratulations. You've made your first pretty full round trip from setting up a model, saving it server side, and back. I hope that this answer epic gives you an IDEA of how this all comes together. There are of course, lots of details that I'm cruising past but the basic ideas of Backbone save, RESTful verbs, Server-side actions, Response are here. Keep going through the Backbone documentation (which is super easy to read compared to other docs) but just keep in mind that this takes time to wrap your head around. The more you keep at it the more fluent you'll be. I learn something new with Backbone every day and it gets really fun as you start making leaps and see your fluency in this framework growing. :-)
EDIT: Resources that may be useful:
Other Similar Answers on SO:
How to generate model IDs with Backbone
On REST:
http://rest.elkstein.org/
http://www.infoq.com/articles/rest-introduction
http://www.recessframework.org/page/towards-restful-php-5-basic-tips