I get a 400 Bad Request error while using django-piston
Asked Answered
J

7

11

I am trying to use Piston to provide REST support to Django. I have implemented my handlers as per the documentation provided . The problem is that i can "read" and "delete" my resource but i cannot "create" or "update". Each time i hit the relevant api i get a 400 Bad request Error.

I have extended the Resource class for csrf by using this commonly available code snippet:

class CsrfExemptResource(Resource):
    """A Custom Resource that is csrf exempt"""
    def __init__(self, handler, authentication=None):
        super(CsrfExemptResource, self).__init__(handler, authentication)
        self.csrf_exempt = getattr(self.handler, 'csrf_exempt', True)

My class (code snippet) looks like this:

user_resource = CsrfExemptResource(User)

class User(BaseHandler):
    allowed_methods = ('GET', 'POST', 'PUT', 'DELETE')

    @require_extended
    def create(self, request):
        email = request.GET['email']
        password = request.GET['password']
        phoneNumber = request.GET['phoneNumber']
        firstName = request.GET['firstName']
        lastName = request.GET['lastName']
        self.createNewUser(self, email,password,phoneNumber,firstName,lastName)
        return rc.CREATED

Please let me know how can i get the create method to work using the POST operation?

Junta answered 27/12, 2010 at 7:50 Comment(3)
Okay, i commented out "django.middleware.csrf.CsrfViewMiddleware" from the settings file instead of using the extension of Resource Class. I still see the issue thoughJunta
How are you attempting the "PUT" or "POST" HTTP operation that corresponds to "create" or "update"? How do you know this client-side code is creating a correct and valid HTTP request?Natala
For the POST, i use a restclient WizTools.org from which i can explicitly create a POST request.So atleast i am sure of the request going through and that is enough i guess.Junta
S
10

This is happening because Piston doesn't like the fact that ExtJS is putting "charset=UTF-8" in the content-type of the header.

Easily fixed by adding some middleware to make the content-type a bit more Piston friendly, create a file called middleware.py in your application base directory:

class ContentTypeMiddleware(object):

    def process_request(self, request):
        if request.META['CONTENT_TYPE'] == 'application/x-www-form-urlencoded; charset=UTF-8':
            request.META['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
        return None

Then simply include this middleware in your settings.py:

MIDDLEWARE_CLASSES = (
    'appname.middleware.ContentTypeMiddleware',
)
Stonework answered 25/3, 2011 at 0:58 Comment(0)
A
7

Proposed solutions still did not work for me (django 1.2.3/piston 0.2.2) so I've tweaked joekrell solution and this finally works (I'm only using POST and PUT, but presumably you can add other verbs to the list):

class ContentTypeMiddleware(object):

def process_request(self, request):

    if request.method in ('POST', 'PUT'):
        # dont break the multi-part headers !
        if not 'boundary=' in request.META['CONTENT_TYPE']:
            del request.META['CONTENT_TYPE']

with:

MIDDLEWARE_CLASSES = (
'appname.middleware.ContentTypeMiddleware',
)

I haven't noticed any side-effect, but I can't promise it's bullet-proof.

Aubyn answered 9/4, 2011 at 9:40 Comment(1)
Yes, your solution worked for me as well (Django 1.3, Piston 0.2.2). In general it looks like Piston became an abandon-ware --- it was not updated in a long time.Splashy
S
4

I have combined some of what other people have said, and added support for any content type, json for instance...

class ContentTypeMiddleware(object):
    def process_request(self, request):
        if request.method in ('POST', 'PUT') and request.META['CONTENT_TYPE'].count(";") > 0:
            request.META['CONTENT_TYPE'] = [c.strip() for c in request.META['CONTENT_TYPE'].split(";") ][0]
        return None
Shamekashameless answered 24/8, 2011 at 14:32 Comment(1)
using this for POST broke other stuff but it fixed my problems when using just for PUTGobbet
K
4

I thought Eric's solution worked the best but then ran into problems when saving things in admin. This tweak seems to fix it if anyone else comes across it:

class ContentTypeMiddleware(object):

    def process_request(self, request):
        if request.method in ('POST') and not 'boundary=' in request.META['CONTENT_TYPE']:
            request.META['CONTENT_TYPE'] = [c.strip() for c in request.META['CONTENT_TYPE'].split(";") ][0]
        return None
Knotted answered 5/10, 2011 at 16:13 Comment(0)
R
1

In utils.py, change this.

def content_type(self):
    """
    Returns the content type of the request in all cases where it is
    different than a submitted form - application/x-www-form-urlencoded
    """
    type_formencoded = "application/x-www-form-urlencoded"

    ctype = self.request.META.get('CONTENT_TYPE', type_formencoded)

    if ctype.strip().lower().find(type_formencoded) >= 0:
        return None

    return ctype

https://bitbucket.org/jespern/django-piston/issue/87/split-charset-encoding-form-content-type

Recommend answered 21/1, 2011 at 19:4 Comment(0)
A
1

This is solution which worked for me, after a tweak:

class ContentTypeMiddleware(object):

    def process_request(self, request):
        if 'charset=UTF-8' in request.META['CONTENT_TYPE']:
            request.META['CONTENT_TYPE'] = request.META['CONTENT_TYPE'].replace('; charset=UTF-8','')
        return None
Adalie answered 23/10, 2013 at 12:58 Comment(0)
E
0

We had a resource that was simply updating a timestamp based on the request credentials and PUT. It turns out that Piston does not like PUT without a payload. Adding an empty string payload '' fixed it.

A quick Google search indicates that other systems like Apache may not like PUT without a payload, as well.

Ezana answered 25/10, 2014 at 0:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.