Why use URL parameters over request body in API? - django

When making an API endpoint in Django Rest Framework for example, why would I ever use URL parameters to receive data rather than just putting everything in the request data?
I don't get the difference between the two.

Putting some query data in the URL allows the URL to store the "state" of your web application.
For example a state can be "I queried how do I make cheese on stackoverflow", and the URL would be https://stackoverflow.com/search?q=how+do+make+cheese.
This allows the web app to interact as expected with browser tools like Refresh, Go Back, etc. Without the state stored in the URL, refreshing the page might just take you back to the homepage, instead of showing you the same query results (the expected behaviour).
Additionally, you can copy & paste the URL. When someone clicks on it, they will be taken directly to that specific state.
On the other hand, you shouldn't use the URL to store/send sensitive data (as it can easily be seen, use the body instead), and you should make sure reloading an "action" URL won't execute the action again (like paying for a product twice!).

The URL parameters and body parameters server different purpose. The REST API grammar says
GET Method is used when you want to retrieve data back and don't want to update any of the record in system. The GET method will not pass body parameter and hence whatever filter parameters passed to API will be through URL parameters.
POST/PUT Method is used whenever you want to update your database. The value could be single parameter or even no input but you have to use POST/PUT method, if you are trying to update database record(s).

Related

Updating entry of Contentful using postman

As you can check below screenshot I tried to make PUT api call in the Contentful to update the entry.
When I try to hit GET call, everything works fine but don't understand here what is reason of this below error while making PUT call.
Did I missed anything here or anything wrong here?
NOTE: I changed all the variable while making call, spaceId, env, entryId and authorisation(passing access_token)
From what I see in your URL, it looks like you are trying to hit the Contentful Preview API, which is read-only.
API Base URL https://preview.contentful.com
This is a read-only API
source
Therefore, updating an entry via a PUT request cannot be done with the url you are using.
However, I believe your PUT request should work if you update the base url to be https://api.contentful.com/ instead. This is the endpoint for the Content Management API.
Important note:
if you do this, you will need to use a different auth token for the Content Management API.
Using https://api.contentful.com/ hits the writable Content Management API, which has documentation for the PUT request you are making.
Importing the corresponding curl command into your Postman client will confirm this.
So in the end, the url would be this:
https://api.contentful.com/spaces/{space_id}/environments/{environment_id}/entries/{entry_id}
Again, the bearer token will have to come from the writable Content Management API.

Make extra parameters passed in URL as optional

I have this URL path('user/delete/<int:pk>/', views.UserDeleteView.as_view(), name='delete_user'),
to delete a selected user via passing the pk of the user to be accessed by the DeleteView . However, I want to delete multiple users by using a form with checkboxes. For that, I have used a separate view.
my question is that is there any way that I can make this <int:pk> as optional parameter so that I can use the same view for POST as well as GET requests. Just in case I want to use the POST method for the same URL. Can this be done? Someone said it can be done optional in Ruby on Rails. Is there any way to do this here in Django?
You can define two paths, one with the primary key, and another one without the primary key:
path('user/delete/', views.UserDeleteView.as_view(), name='delete_user'),
path('user/delete/<int:pk>/', views.UserDeleteView.as_view(), name='delete_user_id'),
We thus have two views here: 'delete_user' that takes no pk, and 'delete_user_id' that takes a primary key. Both direct to the same UserDeleteView.
You can inject a value for the missing parameter, by using the kwargs= parameter:
path('user/delete/', views.UserDeleteView.as_view(), name='delete_user', kwargs={'pk': None}),
path('user/delete/<int:pk>/', views.UserDeleteView.as_view(), name='delete_user_id'),
That being said, using GET requests are supposed to have no side effects. That is how the HTTP protocol [wiki] is designed:
The GET method requests a representation of the specified resource. Requests using GET should only retrieve data and should have no other effect. (This is also true of some other HTTP methods.) The W3C has published guidance principles on this distinction, saying, "Web application design should be informed by the above principles, but also by the relevant limitations.".
The W3 organization has also guidelines when to use GET or POST:
Use GET if:
The interaction is more like a question (i.e., it is a safe operation such as a query, read operation, or lookup).
Use POST if:
The interaction is more like an order, or
The interaction changes the state of the resource in a way that the user would perceive (e.g., a subscription to a service), or
The user be held accountable for the results of the interaction.
If you want to delete items, you usually make a DELETE or a POST request. Django for example will protect such requests with a CSRF token, to prevent cross-site request forgery [wiki].
I therefore strongly recommend that you only allow POST/DELETE requests for these views, of course with extra checks to see if the user is authorized to make the changes.

Django: Send a Post Request Through Form to Another Server

I have a form on a template on my domain1 and want to send a POST request to domain2. I am using Django as the framework. I only want domain2 to accept requests from domain1 and domain2 (itself). However, I run into csrf problems.
You need a RESTful API. That's a very large topic and would be dumb/impossible to do the work for you here with the info I've been given, so here's a summary.
I suggest Django Rest Framework for making api's.
What the above means, is that when you want to do this sort of stuff (POST requests from other domains), you need a token. This is usually done with a Json Web Token. Also known as JWT's.
The process goes like this:
Get access token from other site to have permission to use the API from that site. Certain http headers, passwords, etc, are often included with this every single time data is exchanged.
Once you get a response giving you permission, you can now perform the type of request you want, with the data you want.
The data format for all this is USUALLY done with JSON. So you will have to import json, then json.dumps(obj) to turn it into valid json, and json.loads(obj) to turn your response into a python dictionary, so you can use it in your template, or wherever you want.
If you want to see an example of this, I recently made a free GoFundMe clone on my guthub. In the donate() view at the bottom, it uses the requests library, and shows how a JWT is obtained and used. You can see it there.

View design for a Django website which has a RESTful API from the get go

I am trying to build a Django powered website. I want the website to be dynamic. For example, I want the profile page for a authenticated user to contain multiple resources (like a friends list, a group list, usage history etc) and these resources should be loaded in the same area on the page by making API calls without reloading the page.
Here is my understanding of the process:
Browser on the client side requests the profile page at www.example.com/user:id
The server returns a HTTP response and sends the html, css and javascript to the browser.
To load variable resources on the webpage, for example, the friend list, the javascript makes API calls using HTTP and sending context in JSON.
The API returns a JSON response which contain the data requested.
Javascript renders the data as html and the client is able to see new content on the same page.
I thought that in order to do this, some of my server side views need to be ordinary Django views which returns an HTTP response, while some others need to be API views which return JSON.
Now here's my confusion. Let's say www.example.com/user:id is processed using an ordinary django view, while www.example.com/user/:id/friendslist is processed using an API view. Now if the user inadvertently points the browser at www.example.com/user/:id/friendslist by typing the entire URL and hits go, what happens?
If I go with the flow of logic that I mentioned above, then the view will simply return a JSON. No html, css or javascript. In this case, how will the browser know what html to display?
I am just a beginner and I am sure I got the flow of logic wrong. Can someone please point out which part I got wrong?
Now if the user inadvertently points the browser at www.example.com/user/:id/friendslist by typing the entire URL and hits go, what happens?
It depends on how you coded your server. In Django you can use is_ajax to check whether the request was AJAX or not. You could return an HTTP error code when the request is not an AJAX one, if you wanted. So a user who inadvertently points the browser to your URL but does not take any further action will get an error.
Note here that a knowledgeable user could circumvent is_ajax by setting the request header field HTTP_X_REQUESTED_WITH to XMLHttpRequest manually.
If I go with the flow of logic that I mentioned above, then the view will simply return a JSON. No html, css or javascript. In this case, how will the browser know what html to display?
Setting your returned data type to application/json already tells the browser what it is dealing with. The least a browser would do this with this is display it as text.
Here's an example of an API call that returns JSON: https://api.zotero.org/users/475425/collections/9KH9TNSJ/items?format=json My browser just shows the JSON.

I dont understand request flows

Having read a bit, I still don't understand. Can you help me see where I am going wrong?
a view function sends out a request and gets a response
a httprequest contains info about a currently requested url.
httprequest objects have 2 attributes containing info submitted by
user. GET and POST
Use post when requesting sensitive information, use get when not.
Post data is generally submitted from an html Form.
OK then. If I want sensitive information from a user such as their name, dob etc, I put the requested info inside a form on the html side. On the server side I gather that info by using an object
request and its attribute POST. I then point it to the html input name I specifically want. Thus we have request.POST['Name'] this will return a string value which I give to a variable of my choosing. Thus name = request.POST['Name']. name on the server side will now hold the users entered name.
Before I continue, is there anything I have gotten wrong?
You're nearly right.
The distinction between GET and POST, however, isn't anything to do with sensitive information. It's true that GET data is visible in the URL (after the ?) and POST data isn't, but that doesn't make POST any more secure - it's trivial to get that data if you want to.
In fact the difference is really one of semantics. GET is used when you're just requesting particular information from the server - for instance, page 2 of a set, or a specific search query. POST is used when you're updating information - submitting a form to change stored data.
Apart from that, you're just about there. One thing that will probably help you is to read up on Django's forms framework, which does a lot of the work in generation and validation of forms for you.
You got one tiny bit of it wrong.
The user sends out a request, which the view function receives, then the view function sends out a response.
And HTTP objects have a lot more information included than just GET and POST variables. See Django's official documentation for more information about this.