Skip to content
This repository has been archived by the owner on Dec 15, 2023. It is now read-only.

miraculixx/tastypie-async

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tastypie-async

State-of-the art async REST APIs for django tastypie.

tastypie-async follows the recommended practice for async REST APIs, which is to return 202 CREATED on task submission, and issue a 303 SEE OTHER on status requests when the result is available.

Hello world

In good tastypie tradition, API implementation is straight forward:

from tpasync.resources import AsyncResourceMixin
import myapp.tasks as tasks

# resources.py
# -- define the resource
class DoubleResource(AsyncResourceMixin, Resource):
    def async_get_list(self, request, **kwargs):
        number = request.GET['foo']
        return tasks.double.delay(foo)
    
    class Meta:
        resource_name = 'double'

Adding the API to your Django app is the same as with any tastypie API:

# -- register
api = Api(api_name='v1')
api.register(DoubleResouce())

# urls.py
urlpatterns += [
    r('^api/', include(api.urls),
]

The above example provides the /api/v1/double/ URL supporting async GET requests:

# submits the celery task and returns a state location
GET /api/v1/foo/?foo=1
Status: 202 ACCEPTED
Location:/api/v1/double/state/30049f59-b619-4890-a1eb-d53b245797d1/

Getting results

  1. query the state to get updates

    GET /api/v1/double/state/30049f59-b619-4890-a1eb-d53b245797d1/
    Status: 200 OK
    {  
       "id":"7fbd961a-75d8-4aae-bd41-64296de661fa",
       "resource_uri":"/api/v1/double/state/7fbd961a-75d8-4aae-bd41-64296de661fa/",
       "state":"PENDING"
    }
    
  2. when the result is ready it will be notified in the state response

    GET /api/v1/double/state/30049f59-b619-4890-a1eb-d53b245797d1/
    Status: 200 OK
    {  
       "id":"394daac4-3daa-4a0f-87b8-f9e2c8c73749",
       "resource_uri":"/api/v1/double/state/394daac4-3daa-4a0f-87b8-f9e2c8c73749/",
       "result_uri":"/api/v1/double/result/394daac4-3daa-4a0f-87b8-f9e2c8c73749/",
       "state":"SUCCESS"
    }
    
  3. get results. this returns whatever result was provided by the celery task, serialized by tastypie as usual:

    GET http://localhost:8001/api/v1/double/result/394daac4-3daa-4a0f-87b8-f9e2c8c73749/
    Status: 200 OK
    {
     "result": 2
    }
    
  4. cancel tasks. you may also choose to cancel a task

    DELETE http://localhost:8001/api/v1/double/state/7fbd961a-75d8-4aae-bd41-64296de661fa/
    Status: 410 Gone
    

Implementing operations

tastypie-async supports the usual tastypie operations, GET/PUT/POST/DELETE for list and detail. To implement override the respective async_<method> operation:

  • GET / => async_get_list
  • GET /<pk>/ => async_get_detail
  • POST / => async_post_list
  • POST /<pk>/ => async_post_detail
  • PUT / => async_put_list
  • PUT /<pk>/ => async_put_detail
  • DELETE / => async_delete_list
  • DELETE /<pk>/ => async_delete_detail
  • PATCH / => async_patch_list
  • PATCH /<pk>/ => async_patch_detail

Implementation of any of these methods is straight forward, just return the AsyncResult returned by the celery task:

def async_get_list(request, **kwargs):
    return myapp.tasks.double.delay(requests.GET.get('foo'))

Task implementation is the same as with any other Celery task:

# tasks.py
def double(number):
   return number * 2

Note that it is the responsibility of the task to execute actions that correspond to the API method called, tastypie-async is only the broker between the API call and Celery.

Installation

Just add tpasync to INSTALLED_APPS:

# settings.py

INSTALLED_APPS = (
    ...
    'tastypie',
    'tpasync',
    ...
)

Why not use the Celery REST API?

tastypie-async uses Celery as the execution engine. Any AsyncResource submits tasks to Celery the same way any Celery task is executed. While Celery provides a REST API itself, Celery webhooks, it is less flexible than tastypie-async and has a few other drawbacks. For example, the tasks submitted via Celery need to be aware of their use as a REST API, which means they are hard to be reused outside of celery webhooks. In contrast, tasks used in a AsyncResource remain unaware of their use as a REST API, seperation of concerns is thus maintained.

Also adding authentication, authorization and throttling to an AsyncResource is straight forward -- it works the same as with any tastypie Resource because the method dispatcher is the same.

License

see the LICENSE file