Visit the home of sandman
on the web:
sandman.io
Looking for a place to ask questions about sandman? Check out the sandman-discuss and sandman-users forums!
sandman
"makes things REST". Have an existing database you'd like to
expose via a REST API? Normally, you'd have to write a ton of
boilerplate code for the ORM you're using, then integrate that into some
web framework.
I don't want to write boilerplate.
Here's what's required to create a RESTful API service from an existing
database using sandman
:
$ sandmanctl sqlite:////tmp/my_database.db
That's it. sandman
will then do the following:
- connect to your database and introspect its contents
- create and launch a REST API service
- create an HTML admin interface
- open your browser to the admin interface
That's right. Given a legacy database, sandman
not only gives you a
REST API, it gives you a beautiful admin page and opens your browser to
the admin page. It truly does everything for you.
sandman
, by default, supports connections to the same set of
databases as SQLAlchemy. As of this
writing, that includes:
- MySQL (MariaDB)
- PostgreSQL
- SQLite
- Oracle
- Microsoft SQL Server
- Firebird
- Drizzle
- Sybase
- IBM DB2
- SAP Sybase SQL Anywhere
- MonetDB
As of version 0.9.3, sandman
fully supports HTTP Basic
Authentication! See the documentation for more details.
sandmanctl
is really just a simple wrapper around the following:
from sandman import app
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///chinook'
from sandman.model import activate
activate()
app.run()
You don't even need to tell ``sandman`` what tables your database
contains. Just point sandman
at your database and let it do all
the heavy lifting
Let's start our new service and make a request. While we're at it, lets
make use of sandman
's awesome filtering capability by specifying a
filter term:
> python runserver.py &
* Running on http://127.0.0.1:5000/
> curl GET "http://localhost:5000/artists?Name=AC/DC"
...
{
"resources": [
{
"ArtistId": 1,
"Name": "AC/DC",
"links": [
{
"rel": "self",
"uri": "/artists/1"
}
]
}
]
}
All of that, including filtering/searching, is automagically available from those five measly lines of code.
Oh, that's not enough? You also want a Django-style admin interface
built automatically? Fine. You may have noticed that when you ran
runserver.py
that a browser window popped up. Now's the time to go
check that out. You'll find it's that Django-style admin interface
you've been bugging me about, looking something like this:
(If you want to disable the browser from opening automatically each time
sandman
starts, call activate
with browser=False
)
If you wanted to specify specific tables that sandman
should make
available, how do you do that? With this little ditty:
from sandman.model import register, Model
class Artist(Model):
__tablename__ = 'Artist'
class Album(Model):
__tablename__ = 'Album'
class Playlist(Model):
__tablename__ = 'Playlist'
register((Artist, Album, Playlist))
And if you wanted to add custom logic for an endpoint? Or change the endpoint name? Or add validation? All supported. Here's a "fancy" class definition:
class Style(Model):
"""Model mapped to the "Genre" table
Has a custom endpoint ("styles" rather than the default, "genres").
Only supports HTTP methods specified.
Has a custom validator for the GET method.
"""
__tablename__ = 'Genre'
__endpoint__ = 'styles'
__methods__ = ('GET', 'DELETE')
@staticmethod
def validate_GET(resource=None):
"""Return False if the request should not be processed.
:param resource: resource related to current request
:type resource: :class:`sandman.model.Model` or None
"""
if isinstance(resource, list):
return True
elif resource and resource.GenreId == 1:
return False
return True
With sandman
, zero boilerplate code is required. In fact, using
sandmanctl
, no code is required at all. Your existing database
structure and schema is introspected and your database tables magically
get a RESTful API and admin interface. For each table, sandman
creates:
- proper endpoints
- support for a configurable set of HTTP verbs
- GET
- POST
- PATCH
- PUT
- DELETE
- responses with appropriate
rel
links automatically - foreign keys in your tables are represented by link
- custom validation by simply defining
validate_<METHOD>
methods on your Model - explicitly list supported methods for a Model by setting the
__methods__
attribute - customize a Models endpoint by setting the
__endpoint__
method - essentially a HATEOAS-based service sitting in front of your database
sandman
is under active development but should be usable in any
environment due to one simple fact:
``sandman`` never alters your database unless you add or change a record yourself. It adds no extra tables to your existing database and requires no changes to any of your existing tables. If you start ``sandman``, use it to browse your database via cURL, then stop ``sandman``, your database will be in exactly the same state as it was before you began.
pip install sandman
Take a look in the sandman/test
directory. The application found
there makes use of the Chinook
sample SQL database.
Questions or comments about sandman
? Hit me up at
jeff@jeffknupp.com.
- Support for using existing declarative models alongside
sandman
generated models- If you have an existing app and want to include sandman in it,
simply pass your existing models in to the
register()
function along with anysanmdman
generated classes.sandman
will detect the existing models and augment them.
- If you have an existing app and want to include sandman in it,
simply pass your existing models in to the
- Fixes a critical bug where code used by the new
etag
decorators was accidentally not included. Thanks to @mietek for the PR. - Fixes an issue when showing the HTML representation of an empty collection.
- Thanks to @mietek for reporting the issue.
- Fixes a critical bug in the requirements portion of
setup.py
, addingFlask-HTTPAuth
- Authentication supported!
- Entire API and admin can be protected by HTTP Basic Auth. See the docs for more details.
- ETAGs
- Resources return the proper ETAG header and should reply with a 304 after the first request. This greatly improves the throughput and performance of the API.
- The
meta
endpoint- All resources now have a
/<resource>/meta
endpoint that describes the types of each of their fields (both in HTML and JSON)
- All resources now have a
- The root endpoint
- A "root" endpoint (
/
) has been created. It lists all resources registered in the application and includes URLs to their various endpoints. This allows a "dumb" client to navigate the API without knowing URLs beforehand.
- A "root" endpoint (
- Python 3 support!
sandman
tests now pass for both 2.7 and 3.4! Python 3.4 is officially supported.
Link
header now set to a resource's links- Links to related objects now user a proper
rel
value:related
- The link to the current resource still uses the
self
rel
value - Links are specified both in the header (as per RFC5988) and in the resource itself
- Links to related objects now user a proper
- Pagination added for JSON (and number of results per page being returned is fixed)
- Nested JSON models no longer the default; hitting a URL with the
argument "expand" will show one level of nested resources
- This conforms more closely to REST principles while not sacrificing the functionality.
- Fix multiple references to same table error (fixes #59)