I have a Django custom URL which works fine in POSTMAN but not working properly in a browser the details are given as below.
In postman, I am using the following URL and it s working fine
127.0.0.1:8000/v0/call_letter_status/
and I am getting a 200 response and output as well
But when I am trying in browser I am getting an error like this
ValueError at /v0/call_letter_status/
The view project.views.User.call_letter_track didn't return an HttpResponse object.
Request Method: GET
Request URL: http://127.0.0.1:8000/v0/call_letter_status/
Django Version: 1.5
Exception Type: ValueError
My Code is as given below:
def call_letter_track(request):
if request.META["CONTENT_TYPE"] == 'application/json':
if request.method == 'GET':
sqlQuery = """ SELECT jc.company_name,jc.job_position,jc.venue,jc.email_body,jc.interview_date,aj.job_id,aj.logo_image_url FROM jr_call_letter jc
JOIN api_job aj ON aj.job_id=jc.job_id ORDER BY "jc.job_id" DESC LIMIT 2 """
cursor.execute(sqlQuery)
result=dictfetchall(cursor)
final_response_map = []
key=0
for result_new in result:
print key
response_map = {}
response_map['company_name']=result[key]['company_name']
response_map['job_id']=result[key]['job_id']
response_map['job_position']=result[key]['job_position']
response_map['interview_date']=datetime.fromtimestamp(result[key]['interview_date']).strftime('%d-%m-%Y')
response_map['email_body']=result[key]['email_body']
response_map['venue']=result[key]['venue']
response_map['logo_image_url']=result[key]['logo_image_url']
key=key+1
final_response_map.append(response_map)
response = {'data':final_response_map}
data = json.dumps(response, encoding="ISO-8859-1")
return HttpResponse(data,content_type="application/json", status=200)
Please help me in getting a solution for this problem.
Your return statement is inside the if condition. If that condition is invalid it will go outside of the condition and expect a Response, but there is no return outside your condition, hence the error.
try providing this for checking:
def call_letter_track(request):
if request.META["CONTENT_TYPE"] == 'application/json':
'''
.
.
your code
.
.
'''
return HttpResponse(data,content_type="application/json", status=200)
return HttpResponse('Hello World')
The browser by default has the Content-Type header of application/xml and hence it is not entering your if condition.
Browser will not send CONTENT_TYPE header with application/json; causes the outer if block is never executed; The view function will not return.
How about Remove the outermost if so that request without Content-type: application/json also get HttpResponse?
def call_letter_track(request):
if request.META["CONTENT_TYPE"] == 'application/json': # <---
if request.method == 'GET':
....
Related
This question already has answers here:
Flask view return error "View function did not return a response"
(3 answers)
Closed 1 year ago.
I am trying to send a webhook with a json to my flask app- it then takes the key values and inputs it to my search engine and should reply back with the results and 200 (code that it was successful) my code looks like this:
from flask import Flask, request, abort
from Webhooks.TGSearchEngine import TGSearch
app = Flask(__name__)
#app.route('/', methods=['POST'])
def webhook():
sys.stdout.flush()
if request.method == 'POST':
reply = request.json['reply']
query = request.json['query']
channel = request.json['channel']
messageid = request.json['id']
return TGSearch.main(reply, query, channel, messageid), 200
else:
abort(400)
But I get TypeError( TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
My TGSearch.main() module takes the vars and returns a dictionary with the results. I don't understand why it would throw this error. Any ideas?
If you are sure that TGSearch.main(reply, query, channel, messageid), 200 doesn't return None value, you had to convert the result of the response to a valid response object.
Try one of these options:
You can pass the result in a variable to a template rendering:
response = TGSearch.main(reply, query, channel, messageid), 200
return render_template("example.html", response)
You can convert the response into a JSON:
from flask.json import jsonify
result = TGSearch.main(reply, query, channel, messageid), 200
response = jsonify(result)
Or in the case you are getting a tuple, you can access separate values and make them a string.
result = TGSearch.main(reply, query, channel, messageid), 200 // "Message", 200
return str(result[0]) + str(result[1])
Flask must always return something. In your else statement you should add a return.
Note: you specified methods=['POST'] in your route, so the only method allowed will be POST, I don't think it's necessary to check if request.method == 'POST'
I've been trying to build an API for more than 4 hours now and I searched and asked everywhere I could but I can't find help. The problem is at the level of handling POST requests. I tried with NodeJS (testify and express (as well as middlewares)) and Python (Flask, bottle) and I still can't get why I get an empty object with express or None in python. I have the following code with bottle
1 from bottle import run, Bottle, post, request, redirect
2 import json
3
4 pika = Bottle()
5
6 #post("/shorturl")
7 def shorten():
8 data = request.json
9 #data = json.dumps(rdata)
10 print(data)
11 return f"You posted {data}"
12
13 run(host="localhost", port=3000, debug=True)
And I had the following code at the beginning (I deleted and restarted from scratch) - you can find tweet here.
I can't get None with flask and bottle when using request.get_json() and request.json() respectively which I've found are the way to do it from the docs.
Any help appreciated.
Thanks
Your python code seems to be correct, because I tried and it worked.
For troubleshooting you can insert:
print(request.headers['Content-Type']) #output should be: application/json'
print(request.body.read()) #output should be like: b'{"key":"value"}'
I used Postman and when I tried the first time, I made the mistake to select body form instead of raw. In Postman you have to write Content-Type:appliction/json in the header manually and insert the json as raw.
I assume in Restler it's similar (I never used Restler).
So if you have to configure it manually, make sure that your header contains 'Content-Type':'application/json'
And your body is set to raw and look like this.
If for example form-data was selected, the manually set header would not be used by postman and print(request.header['Content-Type']) would output something like this: multipart/form-data; boundary=--------------------------742283902180513961059188
Could imagine Restler has the same snare.
Here is a way to handle a dynamic routing of the api. Now you just have to add methods to the API class and they are automatically picked up by the bottle app. I am merging POST and GET into one method string to merge query parameters and forms into one payload which you can access via self.payload
import ujson as json
from login import User
def check(data):
try:
if isinstance(data, (str,bytes)):
return json.loads(data)
except:
return data
return data
def merge_dicts(*args):
result = {}
for dictionary in args:
result.update(dictionary or {})
return result
class API:
def __init__(self, payload, user):
self.payload = payload
self.option = ''
self.request = None
#classmethod
def bot(cls, request, option, user):
payload = merge_dicts(dict(request.forms), dict(request.query.decode())) # merge query and form inputs
slf = cls(payload, user)
slf.request = request
slf.option = str(option)
return slf
def test(self): # localhost/api/test
return self.payload
#get('/api/<command>')
#post('/api/<command>')
#get('/api/<command>/<option>')
#post('/api/<command>/<option>')
def routeapi(command='', option=''):
user = User()
wapi = API.bot(request, option, user)
func = getattr(wapi, f"{command}", None)
if callable(func):
result = func()
if result:
if request.method == 'GET':
response.headers['Content-Type'] = 'application/json'
response.headers['Cache-Control'] = 'no-cache'
return {command:json.check(result)}
else:
return {command:None}
I am trying to parse "#" symbol as a direct url in Flask project. The issue is everytime the url is requested, it breaks any value that has # init as it's a special character in url encoding.
localhost:9999/match/keys?source=#123&destination=#123
In flask, I am trying to get these arguments like this
app.route(f'/match/keys/source=<string:start>/destination=<string:end>', methods=['GET'])
The url response that i see on console is this:
"GET /match/keys/source=' HTTP/1.0" 404 -] happens
I believe you might not fully understand how 'query strings' work in flask. This url:
app.route(f'/match/keys/source=<string:start>/destination=<string:end>', methods=['GET'])
won't work as you expect as it won't match the request:
localhost:9999/match/keys?source=#123&destination=#123
rather it aught to be:
#app.route('/match/keys', methods=['GET'])
and this would match:
localhost:9999/match/keys?source=%23123&destination=%23123
Then to catch those 'query strings' you do:
source = request.args.get('source') # <- name the variable what you may
destination = request.args.get('destination') # <- same as the naming format above
So when you call localhost:9999/match/keys?source=%23123&destination=%23123 you test for those 'query strings' in the request url and if they are they that route function would execute.
I wrote this test:
def test_query_string(self):
with app.test_client() as c:
rc = c.get('/match/keys?source=%23123') # <- Note use of the '%23' to represent '#'
print('Status code: {}'.format(rc.status_code))
print(rc.data)
assert rc.status_code == 200
assert 'source' in request.args
assert rc.data.decode('utf-8') == "#123"
and it passes using this route function:
#app.route('/match/keys', methods=['GET'])
def some_route():
s = request.args.get('source')
return s
So you see I was able to catch the query string source value in my unit test.
I found another trick to work around with it. Instead of using GET method, I switched to POST
localhost:9999/match/keys
and in the app.routes, i sent the argument to get_json.
app.route('/match/keys/',method=['POST'])
def my_func():
arg = request.get_json
In postman, I send the POST request and send the body to be like this:
Postman Post request
Hellos firends,
I have REST service in Python Django application. I am trying to store some values in the request session post successful login service call.
like the following
request.session['valid']=True
and the I am able to check that the values set properly.
The in the next request when I am trying to retrieve the value I am not able to find any of the keys I had stored.
following is the code to retrieve the keys
if 'valid' not in request.session:
print('Invalid request. . .')
return False
elif request.session['valid']==True:
username=request.session['username']
print('Request validated. . .')
return True
I have the frontend app running on React and Backend REST is on DRF. After the login is done on the following code,
#csrf_exempt
#api_view(['POST'])
def login_details(request):
if request.method == 'POST':
headers = {
'Content-type': 'application/json',
}
# Assuming at this point login is successful, so I am setting the session
request.session['username']=TF_VAR_user_name
request=initSession(request)
data = txt
response = requests.post('https://hooks.slack.com/services/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', headers=headers, data=data)
print(response)
return Response(data_json)
except cx_Oracle.DatabaseError as exc:
error, = exc.args
m = error.message
err="Oracle-Error-Message: "+ str(error.code) + " Oracle-Error-Message: "+error.message
dic2={"Oracle-Error-Code":str(error.code),"Oracle-Error-Message":error.message}
print(dic2)
m=json.dumps(dic2)
n=json.loads(m)
txt="{'text':'User "+atp_userid+" Oracle-Error-Message: "+error.message+"'}"
data = txt
response = requests.post('https://hooks.slack.com/services/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', headers=headers, data=data)
return Response(n)
else:
return Response({ "message":"Unauthoried, please login."},status=status.HTTP_401_UNAUTHORIZED)
The I am trying to read Stored values in the following code,
#csrf_exempt
#api_view(['POST'])
def dashboard(request):
if 'valid' not in request.session:
print('Invalid request. . .')
elif request.session['valid']==True:
username=request.session['username']
print('Request validated. . .')
Please help me how can store values in session and retrieve in the subsequent request. I am sorry for the trouble as I am completely new to Python and Django
I have a Flask application that returns both HTML pages and JSON responses to API requests. I want to change what an error handler returns based on the content type of the request. If the client requests application/json, I want to return a jsonify response, otherwise I want to return a render_template response. How can I detect what was requested and change the response appropriately?
The current error handlers I have only return an HTML response.
def register_errorhandlers(app):
"""Register error handlers."""
def render_error(error):
"""Render error template."""
# If a HTTPException, pull the `code` attribute; default to 500
error_code = getattr(error, 'code', 500)
return render_template('{0}.html'.format(error_code)), error_code
for errcode in [401, 404, 500]:
app.errorhandler(errcode)(render_error)
Use request.content_type to get the content type the client sent with the request. Use request.accept_mimetypes the get the mimetypes the client indicated it can accept in a response. Use these to determine what to return.
from flask import request, jsonify, render_template
if request.accept_mimetypes.accept_json:
return jsonify(...)
else:
return render_template(...)
I used the after_request decorator to do this and checked the content type:
#app.after_request
def after_request_helper(resp):
if resp.content_type == "text/html":
# If a HTTPException, pull the `code` attribute; default to 500
error_code = getattr(error, 'code', 500)
return render_template('{0}.html'.format(error_code)), error_code
else:
return app.errorhandler(errcode)(render_error)
A more detailed answer:
def wants_json_response():
return request.accept_mimetypes['application/json'] >= \
request.accept_mimetypes['text/html']
The wants_json_response() helper function compares the preference for JSON or HTML selected by the client in their list of preferred formats. If JSON rates higher than HTML, then it is necessary to return a JSON response.
Otherwise, return the original HTML responses based on templates.
For the JSON responses would slightly supplement the function with one condition:
if wants_json_response(): which is what you need. So the answer is in that.
If the condition is true we could write a function that would generate a response:
def api_error_response(status_code, message=None):
payload = {'error': HTTP_STATUS_CODES.get(status_code, 'Unknown error')}
if message:
payload['message'] = message
response = jsonify(payload)
response.status_code = status_code
return response
This function uses the handy HTTP_STATUS_CODES dictionary from Werkzeug (a core dependency of Flask) that provides a short descriptive name for each HTTP status code.
For easier and faster understanding, 'error' is used to represent errors, so you only need to worry about the numeric status code and the optional long description.
The jsonify() function returns a Flask Response object with a default status code of 200, so after the response is created, it is necessary to set the status code to the correct one for the error.
So if we put it all together now it would look like this:
# app/__init__.py
import requests
def register_errorhandlers(app):
from .errors import render_error
for e in [
requests.codes.INTERNAL_SERVER_ERROR,
requests.codes.NOT_FOUND,
requests.codes.UNAUTHORIZED,
]:
app.errorhandler(e)(render_error)
and
# app/errors.py
import requests
from flask import render_template, request, jsonify
from werkzeug.http import HTTP_STATUS_CODES
from .extensions import db
def api_error_response(status_code, message=None):
payload = {'error': HTTP_STATUS_CODES.get(status_code, 'Unknown error')}
if message:
payload['message'] = message
response = jsonify(payload)
response.status_code = status_code
return response
def wants_json_response():
return request.accept_mimetypes['application/json'] >= \
request.accept_mimetypes['text/html']
def render_error(e):
if requests.codes.INTERNAL_SERVER_ERROR == e.code:
db.session.rollback()
if wants_json_response():
return api_error_response(e.code)
else:
return render_template(f'{e.code}.html'), e.code
Additionally
Then they could use the response generation for other cases as well.
The most common error that the API is going to return is going to be
the code 400, which is the error for “bad request”. This is the error
that is used when the client sends a request that has invalid data in it.
In order to generate messages to the function below even easier in these cases, we forward only the required description - message.
def bad_request(message):
return api_error_response(400, message)
I hope this will help in approaching with errors :)