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
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
Flask RestAPI Project - Transimage Rest API For Python

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

OliverKim 1 Jan 12, 2022
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
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 01, 2023
Scaffold django rest apis like a champion 🚀

scaffold django rest apis like a champion 🚀

Abdenasser Elidrissi 133 Jan 05, 2023
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
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
Browsable web APIs for Flask.

Flask API Browsable web APIs for Flask. Status: This project is in maintenance mode. The original author (Tom Christie) has shifted his focus to API S

Flask API 1.3k Dec 27, 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
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
Extensions for Django REST Framework

Extensions for Django REST Framework

aiden 6 Dec 27, 2022
A RESTful way to use your Notion tables as a database.

rest-notion-db A RESTful way to use your Notion tables as a database. Use-cases Form submissions or frontend websites, use one database that

Oorjit Chowdhary 42 Dec 27, 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
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
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
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
Embrace the APIs of the future. Hug aims to make developing APIs as simple as possible, but no simpler.

Read Latest Documentation - Browse GitHub Code Repository hug aims to make developing Python driven APIs as simple as possible, but no simpler. As a r

Hug API Framework 6.7k Dec 27, 2022
Restful API framework wrapped around MongoEngine

Flask-MongoRest A Restful API framework wrapped around MongoEngine. Setup from flask import Flask from flask_mongoengine import MongoEngine from flask

Close 525 Jan 01, 2023
Mlflow-rest-client - Python client for MLflow REST API

Python Client for MLflow Python client for MLflow REST API. Features: Minimal de

MTS 35 Dec 23, 2022