How to identify that requests are coming from my own django website? - django

I'm trying to use the django rest framework to identify when an API Request is coming from my own website (in order to send an error to these requests).
views.py
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.request import Request as RESTRequest
def is_rest_request(request):
return isinstance(request, RESTRequest)
def payment(request, *args, **kwargs):
if is_rest_request(request):
return JsonResponse({"result": 502})
else:
return JsonResponse({"result": 209})
However, when I make the following request from an online python compiler:
import requests
x = requests.get('https://url.com/api/payment')
print(x.text)
I get this output: {"result": 209}, when I should be getting {"result": 502}
Any reasons why?

Related

How to integrate webargs + marshmallow?

I am only beginner in flask. Trying to integrate marshmallow and webargs. It perfectly works in flask-restful Resource class. But when I use a simple flask route it does not work
routes.py
class UserAPI(Resource):
#use_args(UserSchema())
def post(self, *args):
print(args)
return 'success', 201
def get(self):
return '<h1>Hello</h1>'
#bp.route('/test/', methods=['POST'])
#use_kwargs(UserSchema())
def test2(*args, **kwargs):
print(args)
print(kwargs)
return 'success', 201
api.add_resource(UserAPI, '/', endpoint='user')
I've added error handler which is necessary when using use_args
from webargs.flaskparser import parser, abort
from webargs import core
#parser.error_handler
def webargs_validation_handler(error, req, schema, *, error_status_code, error_headers):
status_code = error_status_code or core.DEFAULT_VALIDATION_STATUS
abort(
400,
exc=error,
messages=error.messages,
)
That's what I'm getting when I make request to Resource endpoint what is normal
And that's what I'm getting when I make request to a simple flask route what is not normal
I want to be able to use both ways
Found answer in webargs docs :)
https://webargs.readthedocs.io/en/latest/framework_support.html#error-handling
from flask import jsonify
# Return validation errors as JSON
#app.errorhandler(422)
#app.errorhandler(400)
def handle_error(err):
headers = err.data.get("headers", None)
messages = err.data.get("messages", ["Invalid request."])
if headers:
return jsonify({"errors": messages}), err.code, headers
else:
return jsonify({"errors": messages}), err.code

How to Integrate the https://jsonplaceholder.typicode.com/ into the django application?

Get posts from JSON placeholder. https://jsonplaceholder.typicode.com/posts
Get posts details from JSON Placeholder. https://jsonplaceholder.typicode.com/posts/1
Get Comments from JSON Placeholder. https://jsonplaceholder.typicode.com/posts/1/comments
Try to use request to call the api
https://www.w3schools.com/python/module_requests.asp
You can use serialize to integrate
You need to call jsonplaceholder API from your DRF views. The example is below. It is using the requests package.
# views.py
import requests
from rest_framework.views import APIView
class GetPostsList(APIView):
def get(self, request, format=None):
r = requests.get("https://jsonplaceholder.typicode.com/posts")
return Response(r.json())
class GetPostDetails(APIView):
def get(self, request, post_id, format=None):
r = requests.get(f"https://jsonplaceholder.typicode.com/posts/{post_id}")
return Response(r.json())
# urls.py
from django.conf.urls import url, include
from .views import GetPostsList, GetPostDetails
posts_urlpatterns = [
url(r"^posts/$", GetPostsList.as_view()),
url(r"^posts/(?P<post_id>\w+)/$", GetPostDetails.as_view())
]
You need to add URLs to your main URLs. Below are screenshots from a working example:

Best way to do simple API calls between Django server and android application?

I'm building a system where I store a Member model on a Django server, one of the attributes of Member is score which is what I want to change using API calls. My question is what would be the best way to do this? I looked into the Django REST framework but it seems a bit overkill for what I'm trying to do. I've been trying to pass the necessary information through the url using regular expressions but I'm unsure if it will work. Outline of what I need is below
iOS/Android app makes request sending pk and score to add to total
server updates appropriate model instance and returns True/False to app depending if save was successful
You can achieve this by this quite dirty solution:
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('<int:member_id>/<int:score_to_add>/', views.update_score, name='update_score'),
]
views.py
from django.http import HttpResponse
from .models import Member
def update_score(request, member_id, score_to_add):
member = Member.objects.get(pk=member_id)
member.score += score_to_add
try:
member.save
return HttpResponse("True")
except:
return HttpResponse("False")
Also you can respond with Json. Here is alternative views:
Alternative views.py
from django.http import JsonResponse
from .models import Member
def update_score(request, member_id, score_to_add):
member = Member.objects.get(pk=member_id)
member.score += score_to_add
try:
member.save
return JsonResponse({'status': True})
except:
return JsonResponse({'status': False})
But i think Django Rest Framework is a better way to do this.
You can create a view to return JsonResponse. Take example of polls app in django and convert a post view to return a JSON response.
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.http import JsonResponse
from .models import Choice, Question
# Need to disable csrf here
#csrf_exempt
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
# If you want Json requests Or you can use
# received_json_data=request.POST if you are using normal form data request.
received_json_data=json.loads(request.body)
try:
selected_choice = question.choice_set.get(pk=received_json_data['choice'])
except (KeyError, Choice.DoesNotExist):
# If failed
return JsonResponse({'result': False})
else:
selected_choice.votes += 1
selected_choice.save()
return JsonResponse({'result': True})
Although It works but I would still recommend using DRF because what you are doing needs proper REST API and DRF eases a lot of pain points.

how can I pass curent_user from flask-security to a pluggable view function?

I have a flask app that uses flask security for authentication. I want to use graphql with graphene to fetch data but I'm having trouble accessing the current_user proxy which is I've always used to resolve requests. graphene only provides a customized pluggable view which is understandable but it can't access the current_user within the context of the app and therefore current_user reverts back to AnonymousUser.
here is some sample code
from flask import Flask, render_template, redirect, request
from flask_security import Security, SQLAlchemySessionUserDatastore, login_required, current_user, login_user
from flask_graphql import GraphQLView
import graphene
from graphene_sqlalchemy import SQLAlchemyConnectionField
from .models import UserModel, RoleModel, Todo, TodoModel
from .pipeline import session
app = Flask(__name__, template_folder="../templates", static_folder="../static")
app.config.from_object('core.pipeline.configs.DevConfig')
user_datastore = SQLAlchemySessionUserDatastore(session, UserModel, RoleModel)
security = Security(app, user_datastore)
#app.route('/')
#login_required
def index(path):
user = current_user
return render_template('index.html')
Main issue in your code is
app.add_url_rule('/graphql', view_func=graphql_view())
Where graphql_view() run during code load without any flask request context.
Please, try this code
class GraphQLViewCurrentUser(GraphQLView):
def get_context(self, request):
context = super().get_context(request)
context.update({'current_user': current_user})
return context
app.add_url_rule(
'/graphql', view_func=GraphQLViewCurrentUser.as_view(
'graphql', schema=schema, context={}, graphiql=True))

Flask unittesting API requests

I am trying to write unit test cases for flas api server.
Can someeone please suggest ow to get rid of auth.login_required.
Tried mocking auth, but of no use.
with test_client its not hitting code block too.
api.py
from flask import Flask
from flask.ext.httpauth import HTTPBasicAuth
app = Flask(__name__)
auth = HTTPBasicAuth()
#app.route('/')
#auth.login_required
def index():
print "In index"
response.status_code = 200
return response
Tried following http://flask.pocoo.org/docs/0.12/testing/
from src.api import app
from unittest import TestCase
class TestIntegrations(TestCase):
def setUp(self):
self.app = app.test_client()
def test_thing(self):
response = self.app.get('/')
Can someone please help ??
There are two ways to do so - first is to disable authorization in tests:
// in your test module
from api import app, auth
import unittest
#auth.verify_password
def verify_password(user, password):
"""Overwrite password check to always pass.
This works even if we send no auth data."""
return True
Another approach is to actually send the auth headers from tests (this way you can also test your authorization system):
from api import app
from base64 import b64encode
import unittest
class ApiClient:
"""Performs API requests."""
def __init__(self, app):
self.client = app.test_client()
def get(self, url, **kwargs):
"""Sends GET request and returns the response."""
return self.client.get(url, headers=self.request_headers(), **kwargs)
def request_headers(self):
"""Returns API request headers."""
auth = '{0}:{1}'.format('user', 'secret')
return {
'Accept': 'application/json',
'Authorization': 'Basic {encoded_login}'.format(
encoded_login=b64encode(auth.encode('utf-8')).decode('utf-8')
)
}
class TestIntegrations(unittest.TestCase):
def setUp(self):
self.app = ApiClient(app)
def test_thing(self):
response = self.app.get('/')
print(response.data)
The ApiClient helper can also define post, delete methods which will be similar to get.
The full source code with examples is here.