A lightweight REST miniframework for Python.

Related tags

RESTful API restless
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 4, 2023
Django-rest-auth provides a set of REST API endpoints for Authentication and Registration

This app makes it extremely easy to build Django powered SPA's (Single Page App) or Mobile apps exposing all registration and authentication related functionality as CBV's (Class Base View) and REST (JSON)

Tivix 2.4k Dec 29, 2022
The no-nonsense, minimalist REST and app backend framework for Python developers, with a focus on reliability, correctness, and performance at scale.

The Falcon Web Framework Falcon is a reliable, high-performance Python web framework for building large-scale app backends and microservices. It encou

Falconry 9k Jan 3, 2023
A small repository of projects built in my course, REST APIs with Flask and Python.

A small repository of projects built in my course, REST APIs with Flask and Python.

Teclado 1k Jan 5, 2023
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
Allows simplified Python interaction with Rapid7's InsightIDR REST API.

InsightIDR4Py Allows simplified Python interaction with Rapid7's InsightIDR REST API. InsightIDR4Py allows analysts to query log data from Rapid7 Insi

Micah Babinski 8 Sep 12, 2022
A small project in Python + Flask to demonstrate how to create a REST API

SmartBed-RESTApi-Example This application is an example of how to build a REST API. The application os a mock IoT device, simulating a Smart Bed. Impl

Rares Cristea 6 Jan 28, 2022
Flask RestAPI Project - Transimage Rest API For Python

[ 이미지 변환 플라스크 Rest API ver01 ] 0. Flask Rest API - in SunnyWeb : 이미지 변환 웹의 Flask

OliverKim 1 Jan 12, 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 4, 2023
Authentication for Django Rest Framework

Dj-Rest-Auth Drop-in API endpoints for handling authentication securely in Django Rest Framework. Works especially well with SPAs (e.g React, Vue, Ang

Michael 1.1k Dec 28, 2022
Authentication Module for django rest auth

django-rest-knox Authentication Module for django rest auth Knox provides easy to use authentication for Django REST Framework The aim is to allow for

James McMahon 873 Dec 30, 2022
REST implementation of Django authentication system.

djoser REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such

Sunscrapers 2.2k Jan 1, 2023
A JSON Web Token authentication plugin for the Django REST Framework.

Simple JWT Abstract Simple JWT is a JSON Web Token authentication plugin for the Django REST Framework. For full documentation, visit django-rest-fram

Jazzband 3.3k Jan 4, 2023
Automated generation of real Swagger/OpenAPI 2.0 schemas from Django REST Framework code.

drf-yasg - Yet another Swagger generator Generate real Swagger/OpenAPI 2.0 specifications from a Django Rest Framework API. Compatible with Django Res

Cristi Vîjdea 3k Jan 6, 2023
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
Estudo e desenvolvimento de uma API REST

Estudo e desenvolvimento de uma API REST ??‍?? Tecnologias Esse projeto utilizará as seguintes tecnologias: Git Python Flask DBeaver Vscode SQLite ??

Deusimar 7 May 30, 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
Example Starlette REST API application

The idea of this project is to show how Starlette, Marshmallow, and SQLAlchemy can be combined to create a RESTful HTTP API application that is modular, lightweight, and capable of dealing with many simultaneous requests.

Robert Wikman 0 Jan 7, 2022