0

My webservice should receive calls in these two formats: application/x-www-form-urlencoded and content-type application/json.

The code below works correctly for the forms. However, it doesn't work for the json ones. Apparently I need to use request.args.get for it.

Is there a way to modify the code so that the same method can receive calls in these two formats?

@app.route("/api/<projectTitle>/<path:urlSuffix>", methods=['POST'])
def projectTitlePage(projectTitle, urlSuffix):

    apiKey = request.form.get('apikey')
    userId = databaseFunctions.getApiKeyUserId(apiKey)
    userInfo = databaseFunctions.getUserInfo(userId)
    projectId = databaseFunctions.getTitleProjectId(projectTitle)
    projectInfo = databaseFunctions.getProjectInfo(projectId)
    databaseFunctions.addUserHit(userId, projectId)
    databaseFunctions.addProjectHit(userId)

    print request.form.to_dict(flat=False)
    try:
        r = requests.post(projectInfo['secretUrl'], data=request.form.to_dict(flat=False))
    except Exception, e:
        return '/error=Error'

    return r.text
3
  • can you add your includes and how your request object is assigned? Commented Apr 20, 2015 at 16:15
  • 1
    Have you tried branching the request processing based on the HTTP CONTENT-TYPE header? Commented Apr 20, 2015 at 16:15
  • Hi @RPhillipCastagna. Can you please expand your comment in an answer? I think that might work! Commented Apr 20, 2015 at 16:16

3 Answers 3

4

Try to get the JSON using Request.get_json(); an exception is raised if that fails, after which you can fall back to using request.form:

from flask import request
from werkzeug.exceptions import BadRequest

try:
    data = request.get_json()
    apiKey = data['apikey']
except (TypeError, BadRequest, KeyError):
    apiKey = request.form['apikey']

If the mimetype is not application/json, request.get_json() returns None; trying to use data['apikey'] then results in a TypeError. The mimetype being correct but the JSON data being invalid gives you a BadRequest, and all other invalid return values either result in a KeyError (no such key) or a TypeError (object doesn't support indexing by name).

The other option would be to test the request.mimetype attribute:

if request.mimetype == 'application/json':
    data = request.get_json()
    apiKey = data['apiKey']
else:
    apiKey = request.form['apikey']

Either way, if there is no valid JSON data or form data was posted but there is no apikey entry or an unrelated mimetype was posted, a BadRequest exception will be raised and a 400 response is returned to the client.

Sign up to request clarification or add additional context in comments.

Comments

0

I'm not incredibly familiar with Flask in particular, but based on their documentation you should be able to do something like

content = request.headers['CONTENT-TYPE']

if content[:16] == 'application/json':
   # Process json
else:
   # Process as form-encoded

3 Comments

This won't work if a parameter was added to the request; Content-Type: application/json; charset=utf-8 is a perfectly valid header to send.
Instead, use the Werkzeug Request object API; the mimetype attribute contains the Content-Type contents without any MIME parameters.
Well there ya go! Like I said, not terribly familiar with Flask in particular
-1

My approach to fetch the json and form-data regardless of the header was like

data = request.get_json() or request.form
key = data.get('key')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.