Sending a request from django to itself - python

I have a Django project that contains a second, third-party Django app. In one of my views, I need to query a view from the other app (within the same Django project).
Currently, it works something like this:
import requests
def my_view(request):
data = requests.get('http://localhost/foo/bar').json()
# mangle data
return some_response
Is there a clean way to send the request without going all the way through DNS and the webserver and just go directly to the other app's view (ideally going through the middleware as well of course)

A Django view function accepts a request and returns a response object. There is no reason that a view cannot invoke another view by constructing a request (or cloning or passing its own) and interpreting the response. (c.f. the testing framework).
Of course, if the other view has undesirable side-effects, then the controlling view will have to unwind them. Working within a transaction should allow it to delve in the results of the view it invoked, and then abort the transaction and perform its own.

You can use urllib as shown below
import urllib, urllib3, urllib.request
url = "http://abcd.com" # API URL
postdata = urllib.parse.urlencode(values).encode("utf-8")
req = urllib.request.Request(url)
with urllib.request.urlopen(req, data=postdata) as response:
resp = response.read()
print(resp)

Related

Cookie is not created when calling the endpoint in FastAPI

I have encountered an issue, as I have to create a cookie in the backend, which I will later use to send a request from the frontend. Both apps are on the same domain. This is the general idea behind it: https://levelup.gitconnected.com/secure-frontend-authorization-67ae11953723.
Frontend - Sending GET request to Backend
#app.get('/')
async def homepage(request: Request, response_class=HTMLResponse):
keycloak_code = 'sksdkssdk'
data = {'code': keycloak_code}
url_post = 'http://127.0.0.1:8002/keycloak_code'
post_token=requests.get(url=url_post, json = data )
return 'Sent'
if __name__ == '__main__':
uvicorn.run(app, host='local.me.me', port=7999,debug=True)
Backend
#app.get("/keycloak_code")
def get_tokens(response: Response, data: dict):
code = data['code']
print(code)
....
requests.get(url='http://local.me.me:8002/set')
return True
#app.get("/set")
async def createcookie(response: Response):
r=response.set_cookie(key='tokic3', value='helloworld', httponly=True)
return True
if __name__ == '__main__':
uvicorn.run(app, host='local.me.me', port=8002, log_level="debug")
When I open the browser and access http://local.me.me:8002/set, I can see that the cookie is created.
But when I make a GET request from my frontend to backend to the same URL, the request is received—as I can see in the terminal—but the backend does not create the cookie. Does anyone know what I might be doing wrong?
I have tried different implementations from FastAPI docs, but none has similar use cases.
127.0.0.1 and localhost (or local.me.me in your case) are two different domains (and origins). Hence, when making a request you need to use the same domain you used for creating the cookie. For example, if the cookie was created for local.me.me domain, then you should use that domain when sending the request. See related posts here, as well as here and here.
You also seem to have a second FastAPI app (listenning on a different port) acting as your frontend (as you say). If that's what you are trying to do, you would need to use Session Objects in Python requests module, or preferably, use a Client instance from httpx library, in order to persist cookies across requests. The advantage of httpx is that it offers an asynchronous API as well, using the httpx.AsyncClient(). You can find more details and examples in this answer, as well as here and here.

How to hide GET requests from also being displayed on web

So I'm working on a django project, and one of the objectives is to allow a separate python script to make a HTTP request (using Requests library) to get json data after being authenticated. This works fine, the problem is that if I directly go the url the request.get object uses, I can see all of the data (without any user authentication being involved). This makes my authentication process pointless, as the data is easily visible by simply going to the url. So how would I hide the data on the web side from being viewed, but still allow a GET request to pull the data to my script?
On a side note, I already have a authentication system for the web interface portion of my project (which displays the data). I've tried putting it behind that but to no success.
import json, requests, _mysql
login_attempt = requests.post('http://127.0.0.1:8000/m_app/data_login/',
{'username': 'test', 'password': 'password1234'})
if login_attempt.content.decode('UTF-8') == 'Successful':
print('Logged in.')
else:
print('Not logged in.')
cookies = dict(sessionid=login_attempt.cookies.get('sessionid'))
data = requests.get('http://127.0.0.1:8000/m_app/load/data', #if I type this URL in, I see the data
cookies=cookies)
print(data.content) #prints desired data
By default all your views in django are public, but it's easy to make them protected by checking request.user or using a login_required decorator.

Python Flask - Responding with a redirected website

(unsure of how to phrase this question)
Essentially I'm working with Flask + Soundcloud and what I want to do is to request an http site (which i know will redirect me to a new site) and then i want to return that site (with the same headers and info i originally got). Maybe this explains it better:
#app.route('/play')
def SongURL2():
stream_url="https://api.soundcloud.com/tracks/91941888/stream?client_id=MYCLIENTID"
// newurl = HTTP_REQUEST(stream_url) <- This will redirect me to the actual song streaming link (which only lives for a little bit)
// return newurl;
This is because soundcloud's song's streaming url only live for a short period of time and the device I am using to call my RESTful api will not allow me to do a simple redirect to the newlink. So I need to somehow act like a proxy.
You can achieve this using the Request module:
import requests
#app.route('/play')
def SongURL2():
stream_url="https://api.soundcloud.com/tracks/91941888/stream?client_id=MYCLIENTID"
# Get the redirected url
r = request.get(stream_url)
return r.url
Found an interesting way to proxy through Flask, similar to what #Dauros was aiming at. http://flask.pocoo.org/snippets/118/ In the end bare in mind that this puts extra strain on the server.

Route requests based on the Accept header in Python web frameworks

I have some experience with different web frameworks (Django, web.py, Pyramid and CherryPy), and I'm wondering in which one will it be easier and hopefully cleaner to implement a route dispatcher to a different "view/handler" based on the "Accept" header and the HTTP method e.g.:
Accept: application/json
POST /post/
is handled different than:
Accept: text/html
POST /post/
So the request gets routed to the particular view of the corresponding handler of the MIME "application/json" and the HTTP method "POST".
I do know how to implement something like that in CherryPy, but I lose the use of the CherryPy tools for the internal redirection of the request because I'm calling the specific method directly instead of automagically from the dispatcher. Another option is to implement a full new dispatcher from scratch, but that's the last option.
I'm aware of the alternative to use extensions in the url like /post.json or /post/.json, but I'm looking to keep the same url?
If all you are looking for is one framework that can do this easily, then use pyramid.
Pyramid view definitions are made with predicates, not just routes, and a view only matches if all predicates match. One such predicate is the accept predicate, which does exactly what you want; make view switching depending on the Accept header easy and simple:
from pyramid.view import view_config
#view_config(route_name='some_api_name', request_method='POST', accept='application/json')
def handle_someapi_json(request):
# return JSON
#view_config(route_name='some_api_name', request_method='POST', accept='text/html')
def handle_someapi_html(request):
# return HTML
I needed to do this in Django, and so I wrote a piece of middleware to make it possible: http://baltaks.com/2013/01/route-requests-based-on-the-http-accept-header-in-django
Here is the code:
# A simple middleware component that lets you use a single Django
# instance to serve multiple versions of your app, chosen by the client
# using the HTTP Accept header.
# In your settings.py, map a value you're looking for in the Accept header
# to a urls.py file.
# HTTP_HEADER_ROUTING_MIDDLEWARE_URLCONF_MAP = {
# u'application/vnd.api-name.v1': 'app.urls_v1'
# }
from django.conf import settings
class HTTPHeaderRoutingMiddleware:
def process_request(self, request):
try:
for content_type in settings.HTTP_HEADER_ROUTING_MIDDLEWARE_URLCONF_MAP:
if (request.META['HTTP_ACCEPT'].find(content_type) != -1):
request.urlconf = settings.HTTP_HEADER_ROUTING_MIDDLEWARE_URLCONF_MAP[content_type]
except KeyError:
pass # use default urlconf (settings.ROOT_URLCONF)
def process_response(self, request, response):
return response
I'm not suite sure what you mean by "internal redirection", but if you look at the code you can see that tools.accept is a really thin wrapper around lib.cptools.accept, which you can call from your own code easily. Hand it a list of Content-Types your server can send, and it will tell you which one the client prefers, or raise 406 if the types you emit and the types the client accepts don't overlap.

Redirect and requests in flask microframework

Is there any difference in the way redirects and requests are handled in the flask micro-framework? I have a bunch of functions which are to be run before a request is made but apparently they are not being run whenever there is a redirect to another url.
If you return redirect('someurl') in your view function it will result in a Location header being sent to the client. So unless the client decides to load the target from cache instead the view function of the target URL will be executed just like if the client accessed it directly.

Categories