Visualizzazione post con etichetta django. Mostra tutti i post
Visualizzazione post con etichetta django. Mostra tutti i post

mercoledì 20 gennaio 2016

Which framework should I use to develop a REST application in Python?

Recently, I started looking into REST solutions in Python. Although the possibilities are many, it was hard to find many satisfactory products to be used to develop REST applications in a simple, clean way.
To feet my needs, the final product had to satisfy the following criteria:

  • it has to support Python 3 cleanly;
  • it should enforce as little design constraints as possible on the resulting application;
  • as a consequence of the previous point, it should make it easy to swap the chosen solution with another at will;
  • optional, but good to have: it should make it possible and not too awkward to use a DI library on top of it.

Here is a list of the frameworks I checked out.

Django REST framework

This one seems to be one of the most adopted, probably because of the popularity of Django. Django REST Framework is a Django plugin that adds some functionality to handle REST more easily. It's very well documented and it's not too hard to customize the logic of specific endpoints, or plug in additional code on the resources. 
Like with anything in Django, most of the basics work out of the box, and everything is easy and cool as long as you follow the Django (in this case, Django REST framework) way to do things. The design of your applications must follow the rules strictly, and obviously you need to use the entirety of the Django framework, or write some very awkward code.
This makes it almost impossible not only to change the REST layer, but everything else in your application will be entangled in Django. 

Flask RESTful

Flask RESTful is more lightweight than Django REST framework, and seems to be well documented and supported. I like the OO approach and the extendibility. The problem with it is Flask: in the documentation, they basically suggest against using Python 3. This makes me very uncomfortable using the framework in general, let alone an extension on top of it.
Another thing I don't like is the fact that you need to extend Resource to create a resource, and you need to pass the class arguments as dictionaries using resource_class_kwargs and resource_class_args: it makes it awkward to inject services and to use a DI library.

Werkzeug

Werkzeug is the WSGI library Flask is based upon. It's a very thin layer, so it doesn't force your design too much. The only complain may be that the layer is almost too thin: it doesn't do much to hide WSGI. Another big point against it is that, according to their website, support for python 3 is still highly experimental.

Falcon

Falcon ended up being my framework of choice. I love its minimalistic approach, and the fact that it uses duck typing when creating resources, and that it takes initialized classes when configuring the resulting application: it makes it very easy to use DI with it, encouraging the developers to follow the single responsibility principle. It's also advertised as being extremely fast compared to other frameworks, although I'm not really concerned with performance at this level when coding with Python. And it supports Python 3! 
I'll publish a post with my approach to REST development with Falcon in the near future.

Conclusion

Obviously, this post is not an evaluation on the quality of these frameworks per se, but more a collection of thoughts on which library fits my needs the most. I'd like to get your feedback and feel free to suggest more frameworks.


giovedì 28 aprile 2011

The very basics of Facebook apps on Django

Working on a facebook app i discovered that:

  • Pyfacebook doesn't work anymore.
  • Other projects are far too complicated (or maybe i'm just lazy) to suit to my app.
  • The majority of the tutorials i could find on the internet were largely out of date.

So, here's all you need to simply retrieve the user data you desire from facebook using django.

All you need is facebook python sdk.

Thanks to Sulil Arora for sharing this snippet, it helped a lot.

Just create a django app, create a view using the following code and set it as your facebook app's canvas page.

You can find a project using this piece of code here




import base64
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt
from django.utils import simplejson
import facebook

APP_ID = 'my_app_id'

### CHECK SIGNED REQUEST
import hmac
import hashlib
APP_SECRET = "my_app_secret"

@csrf_exempt #or post requests will be blocked
def canvas(request):
#Facebook sends base64 encoded data via POST

sr = request.POST['signed_request']
#We check the signature and retrieve basic user data
data = parse_signed_request(sr,APP_SECRET)
if data is None:
# Algorithm is unknown or the signed request
#doesn't come from Facebook. You should handle this.
return HttpResponse('ERROR')

user_id = data.get('user_id',False)
oauth_token = data.get('oauth_token',False)
# If we're to retrieve his/her data
# we'll find user_id and oauth_token in data.
# If we're not we need to redirect the user to facebook
# auth dialog

if not user_id or not oauth_token:
# Need authorization for more data
# redirect to Facebook oauth dialog
# using a script (see Facebook docs)
redirect_url = "https://www.facebook.com/dialog/oauth?"+\
"client_id=%s&redirect_uri=%s"\
% (APP_ID,'http.//www.example.com/canvas/')

return HttpResponse(
"<script> top.location.href='%s' </script>"\
% redirect_url
)

f = facebook.GraphAPI(oauth_token)
user_data = f.get_object(user_id)

### Use user's data as needed

return HttpResponse('OK')

def base64_url_decode(inp):
"""
Cleans a base64 encoded string and returns
it decoded
"""
padding_factor = (4 - len(inp) % 4) % 4
inp += "="*padding_factor
return base64.b64decode(
unicode(inp).translate(
dict(zip(
map(ord, u'-_'),
u'+/'
))
)
)

def parse_signed_request(signed_request, secret):
"""
Check if the received signed_request is really coming
from Facebook using your app secret key.
Returns a dict containing facebook data or None if it fails.
"""
l = signed_request.split('.', 2)
encoded_sig = l[0]
payload = l[1]

sig = base64_url_decode(encoded_sig)
data = simplejson.loads(base64_url_decode(payload))

if data.get('algorithm').upper() != 'HMAC-SHA256':
return None

else:
expected_sig = hmac.new(secret,
msg=payload,
digestmod=hashlib.sha256).digest()

if sig != expected_sig:
return None
else:
return data