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
A simple API example in Python (Flask framework)

API-Example A simple API in Python(Flask) ✨ Features An API i guess? 💁‍♀️ How to use first download the main.py install python then install flask fra

Portgas D Ace 2 Jan 06, 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

Robert Wikman 0 Jan 07, 2022
A Django api to display items and their current up-to-date prices from different online retailers in one platform.

A Django api to display items and their current up-to-date prices from different online retailers in one platform. Utilizing scrapy to periodically scrape the latest prices from different online reta

Kennedy Ngugi Mwaura 1 Nov 05, 2021
RESTful Todolist API

RESTful Todolist API GET todolist/ POST todolist/ {"desc" : "Description of task to do"} DELETE todolist/int:id PUT todolist/int:id Requirements D

Gabriel Tavares 5 Dec 20, 2021
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
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
REST API with Flask. No data persistence.

Flask REST API Python 3.9.7 The Flask experience, without data persistence :D First, to install all dependencies: python -m pip install -r requirement

Luis Quiñones Requelme 1 Dec 15, 2021
Country-specific Django helpers, to use in Django Rest Framework

django-rest-localflavor Country-specific serializers fields, to Django Rest Framework Documentation (soon) The full documentation is at https://django

Gilson Filho 19 Aug 30, 2022
Django queries

Djaq Djaq - pronounced “Jack” - provides an instant remote API to your Django models data with a powerful query language. No server-side code beyond t

Paul Wolf 53 Dec 12, 2022
A minimalistic manga reader for desktop built with React and Django

smanga A minimalistic manga reader/server for serving local manga images on desktop browser. Provides a two-page view layout just as reading a physica

Padam Upreti 13 Sep 24, 2022
Dropdown population implementation for Django REST Framework

drf-dropdown Dropdown population implementation for Django REST Framework Usage Add DropdownView to API URL # urls.py import dropdown urlpatterns = [

Preeti Yuankrathok 4 Dec 06, 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
BreakFastApi 🍣 🍔 🍕 The most delicious API on the web

BreakFastApi 🍣 🍔 🍕 The most delicious API on the web. Just send a request and you'll receive the most mouth watering dish recipe with estimated coo

Mariia Sizova 156 Nov 19, 2022
Generate Views, Serializers, and Urls for your Django Rest Framework application

DRF Generators Writing APIs can be boring and repetitive work. Don't write another CRUDdy view in Django Rest Framework. With DRF Generators, one simp

Tobin Brown 332 Dec 17, 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
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
Key-Value база данных на Tarantool и REST API к ней.

KVmail Key-Value база данных на Tarantool и REST API к ней. Документация к API доступна здесь. Requiremrnts ubuntu 16.04+ python3.6+ supervisord nginx

1 Jun 16, 2021
Eazytraining - Simple application to show how to query API from webapp

student-list Eazytraining - Simple application to show how to query API from webapp This repo is a simple application to list student with a webserver

⚡Christophe FREIJANES 2 Nov 15, 2021
Recursive Serialization for Django REST framework

djangorestframework-recursive Overview Recursive Serialization for Django REST framework This package provides a RecursiveField that enables you to se

336 Dec 28, 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