Sergio E. Diaz Sergio E. Diaz - 5 months ago 22
Javascript Question

Is there a better way to check if the values of an AJAX request are valid?

I'm in the process of building an AJAX backend for a Django application, and I don't know if I'm building it right. Currently to accept integer values, I need to typecast them into integers using int(), which raises exceptions and ends up in a 500 all the time if I don't apply much boilerplate. This causes my code to look slightly messier than I would like, and I don't know if I'm doing it correctly. This is an example AJAX view from the app:

@ajax_required
def poll(request):
try:
last_id = int(request.POST.get('last_id'))
feed_type = request.POST['feed_type']
except (KeyError, TypeError):
return HttpResponseBadRequest()

if feed_type == 'following' and request.user.is_authenticated():
posts = Post.get_posts(user=request.user, after_id=last_id)
return JsonResponse({
'html': render_to_string('posts/raw_posts.html', {'posts': posts}),
'count': posts.count()
})

return HttpResponseForbidden()


As you see, I have to do a lot of boilerplate and silence some exceptions of the language itself, which concerns me, coming from a PHP background. Is there a better way to do this or am I doing things correctly?

Answer

If you're not opposed to using a framework Marshmallow will handle serialization and deserialization for you, it is super easy to define custom validation beyond simple type checking, and it's gorgeous. Tom Christie has even wrapped it up for use with Django.

Edit: If you choose to use it your code would look more like this:

from rest_marshmallow import Schema, fields

class FeedSchema(Schema):
    last_id = fields.Integer()
    feed_type = fields.String()

@ajax_required
def poll(request):
    try:
        # Validate request
        serializer = FeedSchema(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.validated_data
        # Return posts
        if data['feed_type'] == 'following' and request.user.is_authenticated():
            posts = Post.get_posts(user=request.user, after_id=data['last_id'])
            return JsonResponse({
                'html': render_to_string('posts/raw_posts.html', {'posts': posts}),
                'count': posts.count()
            })
        # The user isn't authenticated or they requested a feed type they don't have access to.
        return HttpResponseForbidden()
    except ValidationError as err:
        return HttpResponseBadRequest(err.messages)