Django: Send a Post Request Through Form to Another Server - django

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.

Related

In the backend, can you access data from previous requests?

This is more of a theory question, so I'm not going to post any code.
On the frontend, the user types in a search command. On the backend (Django in my case), it hits an API, the results of the search are saved into a Django View in views.py. On the frontend, the user interacts with this returned data and sends another request. On the backend, is the data from the first Django View still available for use? How do you access it?
(The data is also in the frontend and I can send it with the second request. But if it's still stored on the backend then I wouldn't need to.)
HTTP by it's own nature is a stateless protocol. It does mean that protocol doesn't know what or when should happen any request. Request comes and your API just reacts to this request by your implemented logic.
If you want to persist/save any state/data on your API side, you can do it by persisting them to database or saving to any local/global variable. Then you can access this saved state/data while recieving other requests to your back-end and implement the logic to use of previous state with the new incoming data.

How to build a json REST API in django (without Django REST framework)

Preface
I have a django project. I've wired it up so it serves a bunch of views for a bunch of models. Now I want to add an endpoint which just dumps a good fraction of the database out as json.
The way I would assume you do this is add a URL to a view class / method which returns a HTTPResponseObject full of json. Unfortunately, after quite a bit of googling, all I can find are references to Django REST framework. This is the sort of thing you would think Django would provide internally not as part of an external plugin library. But searching the django docs doesn't yield an immediate answer -- I don't think there are any docs about how to build an endpoint which just serves a bunch of json.
Questions:
Do I really need "Django REST framework" to serve json in django?
Did I overlook docs in Django for serving json?
What is the canonical way to serve json in a django project?
After more googling, I found what I was looking for in the Django docs:
JsonResponse
from django.http import JsonResponse
return JsonResponse({'foo':'bar'})
I think googling using the word "REST" was kind of a red herring which made the search space always direct my queries towards "Django REST framework" which is not what I wanted, though I do want to add a RESTful API.
You can write GET API using this method, but for POST method this will not work.
For Post method we need to use some REST Library.
POST Method will check for CSRF token in the cookies and where it fails to execute the request, as your django server will treat this request as forged.
You should go with Django Rest Framework but if you want to do it yourself then:
For POST request, if the client is sending you data as JSON, then you can use the json module to read the data from the request body.
import json
def add_new_user(self, request):
data = request.body.decode('utf8')
data = json.loads(data)
If plain name/value pair is sent, then use request.POST or request.GET
Use JsonResponse to send the response
After authentication, the server usually send a token to the client. The client then sends that token when sending a request to 'protected' api end-point. A custom header (like auth_token) is used to send the token.
In the server code, you need to do something like
request.META['HTTP_AUTH_TOKEN'] to get the token (see Custom HTTP Header in Django)
There are more things to consider like CSRF token or JWT.
See this site for a complete example https://jee-appy.blogspot.com/2018/02/make-rest-api-django.html. Be warned, it use old version of django.

Authentication with Flask/Django and a javascript front end

I'm struggling to understand how flask_login or django knows when a user logs in that they retain access?
If I were to use ReactJs or Angular with flask-restful or django/tastypie, what is being added to the header/body of future json requests to ensure that my user stays logged in?
This is done via sessions, which is based on cookies. From the Flask documentation:
In addition to the request object there is also a second object called session which allows you to store information specific to a user from one request to the next. This is implemented on top of cookies for you and signs the cookies cryptographically.
and the Django docs:
Django provides full support for anonymous sessions. The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies. Cookies contain a session ID – not the data itself (unless you’re using the cookie based backend).
So, the requests to the server automatically include a cookie that indicates some ID that the server then uses to figure out what the session data should be for the given user. In general, when Ajax requests are made from client-side applications to the server, this cookie is included and so ensures that the user is considered to be logged in for those requests.
In some cases, you can also (optionally) manually add a special header to HTTP requests to indicate which user is logged in.
See also Securing RESTapi in flask for some more information.
If you use REST service then you should take a look at oAuth. In other words it uses token which you attach to every request from client to server and the last can determine which user sent this request by this token.
On the other hand, you can use cookie or session to determine a user status. And in this case you don't need to add any headers to your request.
Also I recommend you this package for Django - Django Rest Framework (there you can read more about token and auth via REST) and this extension for Flask.

RESTful API for users' data

I would like to develop a website, with reusable API - and REST-sty;e one should suite quite well.
Lets say that each user can store information about books they like. So I have many users, and each of them can have many books.
As I suppose, I would get list of books by some kind of request as below:
GET /book
But.
User should list only his books, not all of them, that are stored on the server. So how to do this properly?
As I read through many SO Q&A, it seems to be not RESTful to leverage standard authentication with cookies and session id (like it is common with PHP or others), because it preserves state on the server.
Then, first request (GET /book) would not return any results (user not logged in), and after logging, it would return list of this user's books.
Another solution I came across, is to append credentials to every request, like:
GET /book?user=john&pass=1234
Despite of TLS (HTTPS) requirement of that (because of plaintext data), it just seems wrong. Seems like redundancy, bandwith waste, each-request validation etc.
My question is:
If I am not wrong, how to do this good way? Both from the good programming point of view, and performance/network usage prespective?
And maybe REST is not suitable for user owned data?
EDIT:
And OAuth and similar solutions seem way too complicated (and they add overhead too, I think?).
You can add a first mandatory REST method to get an authentication token, so you can require this token in all other REST requests and use it to filter the results.
Use the Authorization header to pass credential information. If OAuth is too complex, use Basic auth over SSL... like so:
GET /user HTTP/1.1
Authorization: Basic ZmlkZGxlcnBpYW5pc3Q6aGVsbG93b3JsZA==
Accept: application/json
(other headers here)
Though I'd definitely recommend a URL that's unique to your user, such as this one:
GET /users/fiddlerpianist/books HTTP/1.1
Note that, in a stateless RESTful service, there is no concept of login or logout. The Authorization header would be passed from the client with every request.

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.