Using Flask API instead of render_template - python

last year i developed a big website using Flask.
I used render_template method to send data from back-end to front-end and request.form to get data from front-end to back-end
Now, my product owner wants me to use "API" instead of above solutions.
And i'm fully confused how to use API.
Should i remove any render_template or request.form?
Should i change my back-end and view functions completely?
Am i able to just change render_template and request.form and make no change in the remaining code ?
Can i use Jinja template after using API? or i should use javascript?
my previous solution was like this:
apps = apps_model.query.all ()
render_template ('index.html' , apps=apps)
and:
user_name = request.form ['username']

my product owner wants me to use "API" instead of above solutions
My understanding of this means that your product manager wants you to seperate the backend from the frontend. Simply put, you should create an [RESTful] API. In essence, you don't have to use render_template to process and parse the HTML templates and display it to the end user.
Your new API should return JSON objects and then, from the client side (i.e. the website), the API gets called to create, update, retrieve and delete data from the database and then return the information to the client.
from flask import Flask, jsonify
app = Flask(__name__)
app.route("/", methods=["GET"])
def index():
api_response = {
"status": "success",
"message": "Welcome to our API"
}
return jsonify(api_response)
Should i remove any render_template or request.form?
You will not be needing render_template anymore as you won't be displaying or returning HTML pages. However, request.form can still be used to collect data from the client side. Totally, depends on how you want the client to communicate with your API
Should i change my back-end and view functions completely?
Only change/create the view functions to return specific data.
Sample cases:
Get all users: create route /api/users
Get user A: create route /api/users/user_a
Am i able to just change render_template and request.form and make no change in the remaining code ?
No.
Can i use Jinja template after using API? or i should use javascript?
Very unlikely. You won't be rendering template anymore. Should I use Javascript? Certainly, for your client side.
See https://www.restapitutorial.com

Related

Flask: How to render a template AND save request.headers info?

I am trying to save objects made available by the request.headers in my Flask app.
I want to render my index.html upon page load, but I also want to grab the visiting user's email so I can use it for other functions / processes.
# routes
#app.route('/')
def index():
return render_template('index.html')
def find_aad():
aad_email = request.headers.get('X-MS-CLIENT-PRINCIPAL-NAME') # aad email
return aad_email
If I try to run find_aad() on its own,
user_email = find_aad() # cant run
I will get the typical error: Working outside of request context.
How can I on an initial load of the website secure these headers and save them to an object without having these errors?
You could get at it this way, perhaps:
On that first call to index, you can create a UUID for the "session" and use that as an identifier for the user, then you pass that code back inside the rendered UI elements for stashing on the client-side. Then, on every subsequent call to the backend, you send that UUID with the rest of the request.
On those subsequent requests, you can access the email value via that UUID as the key to the data structure you're using to store client information on the backend.
This concept is the idea of a "session" with a "session id" that is common in client/server communications. Using sockets or possibly even built in or supplemental libraries for Flask would probably be a good idea instead of "rolling your own". Sorry if I'm being unhelpful or stupid - it's late where I'm at.
EDIT:
By request here's some simple pseudocode for this:
from flask import Flask
import uuid
...
uuid_to_email = {}
...
#app.route('/')
def index():
user_id = str(uuid.uuid4())
uuid_to_email[user_id] = request.headers.get('X-MS-CLIENT-PRINCIPAL-NAME')
return render_template('index.html', uuid=user_id) # where it is implied that you would then use the uuid in the client-side code to story it and pass it back to the endpoints you want to do that with

Django/Django REST Framework - Internal API displaying results fetched from external API with filtering

So hey guys currently I'm trying to create an API endpoint that calls an external API via url with some filtering by comma separated strings. I'm used to creating internal APIs with models and views that call from it's own local sqlite database. But I'm less familiar with this.
For instance I'm trying to have it so when I open my django devserver for this endpoint say called 'api/data?tags=beef,chicken' it gets the JSON response from say 'www.example.com/api/data?tags=beef,chicken' and displays it.
I was thinking about something like the code but wasn't sure how to apply filtering to it without accessing the queryset.
import requests
from rest_framework import status
from rest_framework.response import Response
def external_api_view(request):
if request.method == "GET":
r = requests.get("https://example.com/api/data/")
If you need to send the parameters directly from your local API to the external API you can use this
def external_api_view(request):
if request.method == "GET":
r = requests.get("https://example.com/api/data/", params=requests.GET)

flask Function to create route

i'm building an app similar to myPhpAdmain
i need to allow users in session to create route (aka: #app.route) for the page they require
#app.route('/<x>')
def <x>():
return render_template (<x>+'.html')
where x is a variable that has been given by a user through the front-end
x = request.form.get('x')
how can I allow users to create Pages route like that by a function without allowing them to write it themselves in my flask app ?
Use variable routing:
#app.route('/<x>')
def user_route(x):
return render_template(f"{x}.html")

Django REST API with multiple representations/formats

I'm new in web dev and I'm trying for a project to develop a Restful web api and a website. I'm using Django framework and following tutos, I always see html files as static and the different views rendering an html template. This way of doing seems to me as backend and frontend are not much separated. Is it possible to have backend only developed in Django ?
edit:
I have actually a problem more specific. I having this app (records) with a view having "patient_list" using Response class from REST framework that renders some data and an html template like this:
def patient_list(request):
"""
List all records, or create a new .
"""
if request.method == 'GET':
#data = Patient.objects.all()
data= Patient.objects.all()
#serializer = PatientSerializer(data, many=True)
#return JSONResponse(serializer.data)
return Response({'patients': data}, template_name='records.html')
in my urls.py I have:
url(r'^records/$', views.patient_list),
and here I'm a little confused. Suppose one called this /records, so patient_list is called and will response with an html page. From what I understood (maybe wrong), a restful API should renders data in a standard view so that it can be used from any "frontend" (html pages or mobile app). Is this statement correct ? am I doing it wrong using Response with an html template ?
With Vanilla Django
Of course it's possible, and without any additional libraries to Django.
E.g. You can define a Django view that returns JSON data instead of rendering it into a HTML template server-side. Effectively making an API instead of a "website".
Here's an example with a class-based view that accepts GET requests and returns some JSON data with JsonResponse
from django.views.generic import View
from django.http import JsonResponse
class MyView(View):
def get(self, request):
my_data = {'something': 'some value'}
return JsonResponse(my_data, mimetype='application/json')
As you can see, you don't have to use the HTML rendering facilities in Django, they're there only if you want to use them.
With REST libraries
And of course there is a host of libraries to build RESTful APIs with Django, like Django REST Framework and Tastypie
Multiple representations and content negotiation
Content negotiation is the process of selecting one of multiple possible representations to return to a client, based on client or server preferences.
You can support more than one format in your REST API. E.g. you can support both HTML and JSON formats. There are various ways to do this:
You may use a GET param ?format=JSON (and have it default to HTML e.g.)
You may use Accept headers
You may have two URLs /records.html and /records.json (the format suffix method)
More on this topic in DRF's documentation
E.g. if you were to implement the first method with the GET params you could modify your code this way:
if request.method == 'GET':
data = Patient.objects.all()
format = request.GET.get('format', None)
if format == 'JSON':
serializer = PatientSerializer(data, many=True)
return JSONResponse(serializer.data)
else:
# Return HTML format by default
return Response({'patients': data}, template_name='records.html')

What is an 'endpoint' in Flask?

The Flask documentation shows:
add_url_rule(*args, **kwargs)
Connects a URL rule. Works exactly like the route() decorator.
If a view_func is provided it will be registered with the endpoint.
endpoint – the endpoint for the registered URL rule. Flask itself assumes the name of the view function as endpoint
What exactly is meant by an "endpoint"?
How Flask Routing Works
The entire idea of Flask (and the underlying Werkzeug library) is to map URL paths to some logic that you will run (typically, the "view function"). Your basic view is defined like this:
#app.route('/greeting/<name>')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
Note that the function you referred to (add_url_rule) achieves the same goal, just without using the decorator notation. Therefore, the following is the same:
# No "route" decorator here. We will add routing using a different method below.
def give_greeting(name):
return 'Hello, {0}!'.format(name)
app.add_url_rule('/greeting/<name>', 'give_greeting', give_greeting)
Let's say your website is located at 'www.example.org' and uses the above view. The user enters the following URL into their browser:
http://www.example.org/greeting/Mark
The job of Flask is to take this URL, figure out what the user wants to do, and pass it on to one of your many python functions for handling. It takes the path:
/greeting/Mark
...and matches it to the list of routes. In our case, we defined this path to go to the give_greeting function.
However, while this is the typical way that you might go about creating a view, it actually abstracts some extra info from you. Behind the scenes, Flask did not make the leap directly from URL to the view function that should handle this request. It does not simply say...
URL (http://www.example.org/greeting/Mark) should be handled by View Function (the function "give_greeting")
Actually, it there is another step, where it maps the URL to an endpoint:
URL (http://www.example.org/greeting/Mark) should be handled by Endpoint "give_greeting".
Requests to Endpoint "give_greeting" should be handled by View Function "give_greeting"
Basically, the "endpoint" is an identifier that is used in determining what logical unit of your code should handle the request. Normally, an endpoint is just the name of a view function. However, you can actually change the endpoint, as is done in the following example.
#app.route('/greeting/<name>', endpoint='say_hello')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
Now, when Flask routes the request, the logic looks like this:
URL (http://www.example.org/greeting/Mark) should be handled by Endpoint "say_hello".
Endpoint "say_hello" should be handled by View Function "give_greeting"
How You Use the Endpoint
The endpoint is commonly used for the "reverse lookup". For example, in one view of your Flask application, you want to reference another view (perhaps when you are linking from one area of the site to another). Rather than hard-code the URL, you can use url_for(). Assume the following
#app.route('/')
def index():
print url_for('give_greeting', name='Mark') # This will print '/greeting/Mark'
#app.route('/greeting/<name>')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
This is advantageous, as now we can change the URLs of our application without needing to change the line where we reference that resource.
Why not just always use the name of the view function?
One question that might come up is the following: "Why do we need this extra layer?" Why map a path to an endpoint, then an endpoint to a view function? Why not just skip that middle step?
The reason is because it is more powerful this way. For example, Flask Blueprints allow you to split your application into various parts. I might have all of my admin-side resources in a blueprint called "admin", and all of my user-level resources in an endpoint called "user".
Blueprints allow you to separate these into namespaces. For example...
main.py:
from flask import Flask, Blueprint
from admin import admin
from user import user
app = Flask(__name__)
app.register_blueprint(admin, url_prefix='admin')
app.register_blueprint(user, url_prefix='user')
admin.py:
admin = Blueprint('admin', __name__)
#admin.route('/greeting')
def greeting():
return 'Hello, administrative user!'
user.py:
user = Blueprint('user', __name__)
#user.route('/greeting')
def greeting():
return 'Hello, lowly normal user!'
Note that in both blueprints, the '/greeting' route is a function called "greeting". If I wanted to refer to the admin "greeting" function, I couldn't just say "greeting" because there is also a user "greeting" function. Endpoints allow for a sort of namespacing by having you specify the name of the blueprint as part of the endpoint. So, I could do the following...
print url_for('admin.greeting') # Prints '/admin/greeting'
print url_for('user.greeting') # Prints '/user/greeting'
Endpoint is the name used to reverse-lookup the url rules with url_for and it defaults to the name of the view function.
Small example:
from flask import Flask, url_for
app = Flask(__name__)
# We can use url_for('foo_view') for reverse-lookups in templates or view functions
#app.route('/foo')
def foo_view():
pass
# We now specify the custom endpoint named 'bufar'. url_for('bar_view') will fail!
#app.route('/bar', endpoint='bufar')
def bar_view():
pass
with app.test_request_context('/'):
print url_for('foo_view')
print url_for('bufar')
# url_for('bar_view') will raise werkzeug.routing.BuildError
print url_for('bar_view')
If you have same class name and want to map with multiple routes, then specify the endpoint, so that framework will differentiate between two:
class ClassName(Resource):
def get(self):
if request.endpoint!='hello':
return {"data": "Hello"}
elif:
return {"data" : "World"}
api.add_resource(ClassName, '/rout1', endpoint = "world")
api.add_resource(ClassName, '/rout2', endpoint="hello")
#app.route('/') #Endpoint
def a_function(): #View function
return 'view'
Inside Flask, every endpoint with its request methods mapped to a view function. When you use app.route decorator you are actually adding a URL rule.

Categories