A lightweight REST miniframework for Python.

Related tags

RESTful APIrestless
Overview

restless

https://travis-ci.org/toastdriven/restless.svg?branch=master https://coveralls.io/repos/github/toastdriven/restless/badge.svg?branch=master

A lightweight REST miniframework for Python.

Documentation is at https://restless.readthedocs.io/.

Works great with Django, Flask, Pyramid, Tornado & Itty, but should be useful for many other Python web frameworks. Based on the lessons learned from Tastypie & other REST libraries.

Features

  • Small, fast codebase
  • JSON output by default, but overridable
  • RESTful
  • Python 3.6+
  • Django 2.2+
  • Flexible

Anti-Features

(Things that will never be added...)

  • Automatic ORM integration
  • Authorization (per-object or not)
  • Extensive filtering options
  • XML output (though you can implement your own)
  • Metaclasses
  • Mixins
  • HATEOAS

Why?

Quite simply, I care about creating flexible & RESTFul APIs. In building Tastypie, I tried to create something extremely complete & comprehensive. The result was writing a lot of hook methods (for easy extensibility) & a lot of (perceived) bloat, as I tried to accommodate for everything people might want/need in a flexible/overridable manner.

But in reality, all I really ever personally want are the RESTful verbs, JSON serialization & the ability of override behavior.

This one is written for me, but maybe it's useful to you.

Manifesto

Rather than try to build something that automatically does the typically correct thing within each of the views, it's up to you to implement the bodies of various HTTP methods.

Example code:

# posts/api.py
from django.contrib.auth.models import User

from restless.dj import DjangoResource
from restless.preparers import FieldsPreparer

from posts.models import Post


class PostResource(DjangoResource):
    # Controls what data is included in the serialized output.
    preparer = FieldsPreparer(fields={
        'id': 'id',
        'title': 'title',
        'author': 'user.username',
        'body': 'content',
        'posted_on': 'posted_on',
    })

    # GET /
    def list(self):
        return Post.objects.all()

    # GET /pk/
    def detail(self, pk):
        return Post.objects.get(id=pk)

    # POST /
    def create(self):
        return Post.objects.create(
            title=self.data['title'],
            user=User.objects.get(username=self.data['author']),
            content=self.data['body']
        )

    # PUT /pk/
    def update(self, pk):
        try:
            post = Post.objects.get(id=pk)
        except Post.DoesNotExist:
            post = Post()

        post.title = self.data['title']
        post.user = User.objects.get(username=self.data['author'])
        post.content = self.data['body']
        post.save()
        return post

    # DELETE /pk/
    def delete(self, pk):
        Post.objects.get(id=pk).delete()

Hooking it up:

# api/urls.py
from django.conf.urls.default import url, include

from posts.api import PostResource

urlpatterns = [
    # The usual suspects, then...

    url(r'^api/posts/', include(PostResource.urls())),
]

Licence

BSD

Running the Tests

The test suite uses tox for simultaneous support of multiple versions of both Python and Django. The current versions of Python supported are:

  • CPython 3.6
  • CPython 3.7
  • CPython 3.8
  • CPython 3.9
  • PyPy

You just need to install the Python interpreters above and the tox package (available via pip), then run the tox command.

Comments
  • Moving to more composition

    Moving to more composition

    I've been displeased with the way serialization & data preparation have been working. This splits them off into their own classes & makes them a bit pluggable. If I merge it, it'll be a major version bump (v2.0.0, though not much work to port), since fields is no longer special.

    Thoughts? @jphalip @binarydud

    opened by toastdriven 11
  • Better handling for failed authentication?

    Better handling for failed authentication?

    This might be more of a question than a feature request or a bug report. I'm not sure :)

    Currently, if the authentication fails then an Unauthorized exception is raised: https://github.com/toastdriven/restless/blob/1.0.0/restless/resources.py#L238-L239

    When raised, this exception isn't handled, causing Django to return a 500 response. Wouldn't it be more appropriate for restless to directly return a 401 HTTP response instead? To do this I've overridden the handle() method to catch the exception. I'm not sure if that would be the recommended way.

    Any thoughts? Thanks a lot for this great app by the way!

    opened by jphalip 10
  • added support for custom response status

    added support for custom response status

    This allows passing a custom status to an endpoint HTTP response by using a tuple:

    def update(self, pk):
        try:
            Post = Post.objects.get(id=pk)
            status = 200
        except Post.DoesNotExist:
            post = Post()
            status = 201
        
        post.title = self.data['title']
        post.user = User.objects.get(username=self.data['author'])
        post.content = self.data['body']
        post.save()
        return post, status   # status can be passed here
    

    Fixes #118

    opened by yuriescl 7
  • unclear request object being used in example about alternative serializations

    unclear request object being used in example about alternative serializations

    I was going through the restless docs about extending restless. In the section about handling multiple forms of serialization around line 470 in the MultiSerializer example,

    class MultiSerializer(Serializer):
            def deserialize(self, body):
                # This is Django-specific, but all frameworks can handle GET
                # parameters...
                ct = request.GET.get('format', 'json')
                if ct == 'yaml':
                    return yaml.safe_load(body)
                else:
                    return json.load(body)
    
            def serialize(self, data):
                # Again, Django-specific.
                ct = request.GET.get('format', 'json')
                if ct == 'yaml':
                    return yaml.dump(body)
                else:
                    return json.dumps(body, cls=MoreTypesJSONEncoder)
    

    in line ct = request.GET.get.... Its not clear where the request variable being used is coming from. I experimented a little and realized that neither the serializer instance nor the supplied arguments contain the request instance.

    Can you please clarify if I am missing something here - in which case we can just improve the docs around the same.

    Also if the request instance is not really present, my ideas around making it available would be as follows

    • make the resource instance available as Serializer.resource - so that it can be used as self.resource (I dont recommend this one since it makes too much of the details available to the serializer)
    • make the request instance available as Serializer.request - so that it can be used as self.request - but this one can raise thread safety issues.

    I would be happy to make the changes and raise PR for you if you would like that

    opened by rkssisodiya 6
  • self.data should populate from querystring on GET requests

    self.data should populate from querystring on GET requests

    I notice that request.data is not populated on GET requests because almost no HTTP clients send a request body with GET requests, even though some client libraries allow it. On the contrary, when clients want to pass data via GET, they (almost always) use querystring arguments. Wouldn't it make sense for restless to conditionally populate request.data from wherever the data is?

    opened by donspaulding 6
  • Does it support nested data on the `fields` declaration?

    Does it support nested data on the `fields` declaration?

    As a django-piston user, it is common to have nested data on the fields declaration:

    fields = (
        'id', 'username',
        ('group', ('id', 'name'))
    )
    

    On django-tastypie, this is similar to use full = True on ForeignKey fields.

    Is there a way to work with nested data?

    Data Preparation Feature 
    opened by marcio0 6
  • Drop support for Python < 3.4

    Drop support for Python < 3.4

    What are your opinions about dropping support for Python < 3.4?

    Python 2.7 is reaching end-of-life soon. And Python 3.0 to 3.3 are not supported anymore.

    Maybe we could give an step foward and drop support for 3.4 too, because it's end of life will be in two months.

    This will help us to support new versions of some frameworks while keeping the code clear.

    opened by Marcelo-Theodoro 5
  • Compatibility issue with newer Django (1.8/1.10)

    Compatibility issue with newer Django (1.8/1.10)

    django.conf.urls.patterns() is deprecated since Django 1.8 and removed in 1.10. It is imported however in dj.py. See https://docs.djangoproject.com/en/dev/releases/1.8/#django-conf-urls-patterns

    opened by ghost 5
  • Default to False in TornadoResource.is_debug

    Default to False in TornadoResource.is_debug

    Description

    TornadoResource error handling is broken if tornado.web.Application is not run in debug mode.

    During the handling of any error Resource.build_error() is called, which in turn calls TornadoResource.is_debug(). This will throw a KeyError if debug was not passed to the Application constructor. This is an optional parameter and should not be relied upon.

    Example

    A simple example displaying this error can be seen below

    from tornado import web, ioloop
    from restless.exceptions import BadRequest
    from restless.tnd import TornadoResource
    
    class TestTornadoResource(TornadoResource):
        def list(self):
            raise BadRequest()
    
    # Fails to handle the `BadRequest` properly
    # This will only work if debug=True/False is passed. 
    app = web.Application([
        (r'/', TestTornadoResource.as_list())
    ])
    
    if __name__ == '__main__':
        app.listen(8080)
        ioloop.IOLoop.instance().start()
    
    opened by matt-snider 5
  • Support for UUIDs

    Support for UUIDs

    Currently UUIDs fail both in that they can't be serialized and can't be used as a pk

    I fould this pull request: https://github.com/toastdriven/restless/pull/49/files and notice that Django it self will support this in 1.8.4: https://docs.djangoproject.com/en/1.8/releases/1.8.4/

    I've manually updated my urls to this:

        @classmethod
        def urls(cls, name_prefix=None):
            return patterns('',
                            url(r'^$', cls.as_list(), name=cls.build_url_name('list', name_prefix)),
                            url(r'^(?P<pk>[-\w]+)/$', cls.as_detail(), name=cls.build_url_name('detail', name_prefix)),
                            )
    

    I'm not a regex wiz, so there might be a better one. Would love this to be build in.

    opened by justmobilize 4
  • Added a way to change the status header

    Added a way to change the status header

    I added a way to change the status code of a request. Currently you have the following options:

    • Add a decorator to a function: @status(201)
    • Create a data.Data object ```return data.Data('yourdata', status=201)
    opened by schmitch 4
  • Updated dj.py for supporting latest Django

    Updated dj.py for supporting latest Django

    Change One: restless/restless/dj.py from django.conf.urls import url ❌ from django.urls import re_path ✔️

    url(r'^$', cls.as_list(), name=cls.build_url_name('list', name_prefix)), ❌ re_path (r'^$', cls.as_list(), name=cls.build_url_name('list', name_prefix)), ✔️

    url(r'^(?P<pk>[\w-]+)/$', cls.as_detail(), name=cls.build_url_name('detail', name_prefix)), ❌ re_path (r'^(?P<pk>[\w-]+)/$', cls.as_detail(), name=cls.build_url_name('detail', name_prefix)), ✔️

    Change Two: Refactor codes

    opened by nhridoy 0
  • docs: Fix a few typos

    docs: Fix a few typos

    There are small typos in:

    • docs/cookbook.rst
    • docs/extending.rst
    • docs/releasenotes/v2.0.0.rst
    • docs/tutorial.rst
    • restless/resources.py

    Fixes:

    • Should read overriding rather than overridding.
    • Should read output rather than ouput.
    • Should read grained rather than graned.
    • Should read business rather than busines.

    Semi-automated pull request generated by https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md

    opened by timgates42 0
  • Django: Use path funcion instead of url funcion

    Django: Use path funcion instead of url funcion

    The django.conf.urls.url function has been deprecated since version 3.1 and wil be removed on version 4. I replaced it with the easier to read path function.

    Edit: I also added the support for Django 4.0 on tox and on Travis. I think this PR is important to make sure that people can update to later versions of Django without break anything.

    opened by r-lelis 2
  • Django: fixes pagination parameter

    Django: fixes pagination parameter

    When a user pass the p parameter in query, Django returns a string. The string needs to be casted to integer in order to be used in the paginator. Otherwise, the response returns BadRequest.

    opened by cawal 3
  • HttpError class constructor bug. Cannot override error msg with argument

    HttpError class constructor bug. Cannot override error msg with argument

    https://github.com/toastdriven/restless/blob/661593b7b43c42d1bc508dec795356297991255e/restless/exceptions.py#L36

    Should be something like that:

    self.msg = msg if msg else self.__class__.msg

    opened by soneiko 0
  • Late binding of Preparers

    Late binding of Preparers

    Currently, you could be left with a circular import problem if your preparer references another preparer that hasn't been defined yet and you can't change the order of the preparers to fix it.

    This is a bit like when Django references another model in a ForeignKey. The Django syntax lets you put the Model directly into the ForeignKey definition or a string that references the model.

    I propose supporting this syntax 'choices': CollectionSubPreparer('choice_set.all', 'survey.api.choice_preparer'),

    Notice the preparer is referenced as a string instead of including it directly. The change to CollectionSubPreparer is quite simple. Something like this:

    from pydoc import locate
    
    class MyCollectionSubPreparer(CollectionSubPreparer):
        """ Override this to allow for the preparer to be a dot notation string (i.e. survey.api.question_preparer).
        """
    
        def prepare(self, data):
            """
            Handles passing each item in the collection data to the configured
            subpreparer.
            Uses a loop and the ``get_inner_data`` method to provide the correct
            item of the data.
            Returns a list of data as the response.
            """
            result = []
    
            if isinstance(self.preparer, str):
                self.preparer = locate(self.preparer)
    
            for item in self.get_inner_data(data):
                result.append(self.preparer.prepare(item))
    
            return result
    

    I can prepare a PR that changes CollectionSubPreparer if there's interest in this change.

    opened by edmenendez 0
Releases(2.2.0)
  • 2.2.0(Aug 4, 2021)

  • 2.1.1(Jun 1, 2017)

  • 2.1.0(Jun 1, 2017)

    Features

    • Added SubPreparer and CollectionSubPreparer classes to make easier to nest responses
    • Hability of using callables in preparers (as soon as they don't have args)

    Changes

    • Dropped Itty support :(
    • Proper HTTP status messages
    • Added support to Django 1.9 to 1.11 (dropped support to Django <= 1.7)
    • Proper wrapping for decorators
    Source code(tar.gz)
    Source code(zip)
  • 2.0.4(May 22, 2017)

  • 2.0.3(Nov 21, 2016)

    This release adds a change which was in restkiss v2.0.2 but got lost in the backporting process - sorry, everybody!

    Features

    • Changed all Resource subclasses so that a 204 No Content response sends text/plain on Content-Type. (SHA: 116da9f & SHA: b10be61)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Nov 14, 2016)

    This release makes some long-needed changes on error handling for Resource and its subclasses, plus support for both Django >= 1.9 and Tornado >= 4.0 and allowing alphanumeric PKs on all supported frameworks.

    Features

    • Allowed PKs with dashes and alphanumeric digits. (SHA: e52333b)
    • Reworked test suite so that it uses tox for simultaneously testing on CPython and PyPy, both 2.x and 3.x (SHA: 2035e21, SHA: 9ca0e8c, SHA: 3915980 & SHA: a1d2d96)
    • Reworked Resource so that it throws a NotImplementedError instead of returning an HttpResponse from Django. (SHA: 27859c8)
    • Added several HttpError subclasses. (SHA: e2aff93)
    • Changed Resource so that it allows any serializable object on the response body. (SHA: 1e3522b & SHA: b70a492)

    Bugfixes

    • Changed JSONSerializer to throw a BadRequest upon a serialization error. (SHA: 8471463)
    • Updated DjangoResource to use lists instead of the deprecated django.conf.urls.patterns object. (SHA: f166e4d & SHA: f94c500)
    • Fixed FieldsPreparer behavior when parsing objects with a custom __getattr__. (SHA: 665ef31)
    • Applied Debian's fix to Tornado tests for version 4.0.0 onwards. (SHA: 372e00a)
    • Skips tests for all unavailable frameworks. (SHA: 8b81b17)
    Source code(tar.gz)
    Source code(zip)
Owner
Daniel Lindsley
I program computers, make music, play games, curate animated gifs. Allergic to seriousness. He/Him
Daniel Lindsley
RESTler is the first stateful REST API fuzzing tool for automatically testing cloud services through their REST APIs and finding security and reliability bugs in these services.

RESTler is the first stateful REST API fuzzing tool for automatically testing cloud services through their REST APIs and finding security and reliability bugs in these services.

Microsoft 1.8k Jan 04, 2023
Document Web APIs made with Django Rest Framework

DRF Docs Document Web APIs made with Django Rest Framework. View Demo Contributors Wanted: Do you like this project? Using it? Let's make it better! S

Manos Konstantinidis 626 Nov 20, 2022
Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.7k Dec 28, 2022
Kong API Manager with Prometheus And Splunk

API Manager Stack Run Kong Server + Konga + Prometheus + Grafana + API & DDBB + Splunk Clone the proyect and run docker-compose up

Santiago Fernandez 82 Nov 26, 2022
BloodDonors: Built using Django REST Framework for the API backend and React for the frontend

BloodDonors By Daniel Yuan, Alex Tian, Aaron Pan, Jennifer Yuan As the pandemic raged, one of the side effects was an urgent shortage of blood donatio

Daniel Yuan 1 Oct 24, 2021
Django Ninja is a web framework for building APIs with Django and Python 3.6+ type hints.

💨 Fast, Async-ready, Openapi, type hints based framework for building APIs

Vitaliy Kucheryaviy 3.8k Jan 04, 2023
The Web API toolkit. 🛠

🛠 The Web API toolkit. 🛠 Community: https://discuss.apistar.org 🤔 💭 🤓 💬 😎 Documentation: https://docs.apistar.com 📘 Requirements: Python 3.6+

Encode 5.6k Dec 27, 2022
Simple Crud Api With Django Rest Framework

SIMPLE CRUD API WITH DJANGO REST FRAMEWORK Django REST framework is a powerful and flexible toolkit for building Web APIs. Requirements Python 3.6 Dja

kibet hillary 1 May 03, 2022
Transparently use webpack with django

Looking for maintainers This repository is unmaintained as I don't have any free time to dedicate to this effort. If you or your organisation are heav

2.4k Dec 24, 2022
Build a Backend REST API with Python & Django

Build a Backend REST API with Python & Django Skills Python Django djangorestframework Aws Git Use the below Git commands in the Windows Command Promp

JeonSoohyun a.k.a Edoc.. 1 Jan 25, 2022
Introduction to Django Rest Framework

Introduction to Django Rest Framework This is the repository of the video series Introduction to Django Rest Framework published on YouTube. It is a s

Simple is Better Than Complex 20 Jul 14, 2022
DRF-extensions is a collection of custom extensions for Django REST Framework

Django REST Framework extensions DRF-extensions is a collection of custom extensions for Django REST Framework Full documentation for project is avail

Gennady Chibisov 1.3k Dec 28, 2022
Django REST API with React BoilerPlate

This is a setup of Authentication and Registration Integrated with React.js inside the Django Templates for web apps

Faisal Nazik 91 Dec 30, 2022
simple api build with django rest framework

Django Rest API django-rest-framework Employees management simple API in this project wrote test suites for endpoints wrote simple doc string for clas

OMAR.A 1 Mar 31, 2022
JSON:API support for Django REST framework

JSON:API and Django REST framework Overview JSON:API support for Django REST framework Documentation: https://django-rest-framework-json-api.readthedo

1k Dec 27, 2022
Django app for handling the server headers required for Cross-Origin Resource Sharing (CORS)

django-cors-headers A Django App that adds Cross-Origin Resource Sharing (CORS) headers to responses. This allows in-browser requests to your Django a

Adam Johnson 4.8k Jan 05, 2023
Eureka is a Rest-API framework scraper based on FastAPI for cleaning and organizing data, designed for the Eureka by Turing project of the National University of Colombia

Eureka is a Rest-API framework scraper based on FastAPI for cleaning and organizing data, designed for the Eureka by Turing project of the National University of Colombia

Julian Camilo Velandia 3 May 04, 2022
REST API framework designed for human beings

Eve Eve is an open source Python REST API framework designed for human beings. It allows to effortlessly build and deploy highly customizable, fully f

eve 6.6k Jan 04, 2023
A Django-powered API with various utility apps / endpoints.

A Django-powered API Includes various utility apps / endpoints. Demos These web apps provide a frontend to the APIs in this project. Issue API Explore

Shemar Lindie 0 Sep 13, 2021