{"id":13463604,"url":"https://github.com/jeffknupp/sandman","last_synced_at":"2025-05-14T20:07:10.787Z","repository":{"id":9624210,"uuid":"11552213","full_name":"jeffknupp/sandman","owner":"jeffknupp","description":"Sandman \"makes things REST\".","archived":false,"fork":false,"pushed_at":"2021-12-25T11:42:58.000Z","size":11880,"stargazers_count":2301,"open_issues_count":37,"forks_count":170,"subscribers_count":100,"default_branch":"develop","last_synced_at":"2025-04-13T15:59:38.487Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeffknupp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-20T19:52:21.000Z","updated_at":"2025-03-30T22:59:27.000Z","dependencies_parsed_at":"2022-09-05T05:41:38.336Z","dependency_job_id":null,"html_url":"https://github.com/jeffknupp/sandman","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffknupp%2Fsandman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffknupp%2Fsandman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffknupp%2Fsandman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffknupp%2Fsandman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeffknupp","download_url":"https://codeload.github.com/jeffknupp/sandman/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248741200,"owners_count":21154252,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T14:00:24.101Z","updated_at":"2025-04-13T15:59:45.651Z","avatar_url":"https://github.com/jeffknupp.png","language":"Python","readme":"This version is obsolete, please consider using https://github.com/jeffknupp/sandman2\n======================================================================================\n\n[![Build Status](https://travis-ci.org/jeffknupp/sandman.png?branch=develop)](https://travis-ci.org/jeffknupp/sandman)\n\n[![Coverage Status](https://coveralls.io/repos/jeffknupp/sandman/badge.png?branch=develop)](https://coveralls.io/r/jeffknupp/sandman?branch=develop)\n\n[![Gitter chat](https://badges.gitter.im/jeffknupp/sandman.png)](https://gitter.im/jeffknupp/sandman)\n\n[![Analytics](https://ga-beacon.appspot.com/UA-12615441-7/sandman/home)](https://github.com/jeffknupp/sandman)\n\n[![PyPI](http://img.shields.io/pypi/dm/sandman.svg)](http://img.shields.io/pypi/dm/sandman.svg)\n\n\nDiscuss\n-------\n\nLooking for a place to ask questions about sandman? Check out the \u003ca href=\"https://groups.google.com/forum/#!forum/sandman-discuss\"\u003esandman-discuss\u003c/a\u003e and \u003ca href=\"https://groups.google.com/forum/#!forum/sandman-users\"\u003esandman-users\u003c/a\u003e forums!\n \nDocumentation\n-------------\n\n[Sandman documentation](https://sandman.readthedocs.org/en/latest/)\n\n`sandman` \"makes things REST\". Have an existing database you'd like to expose via\na REST API? Normally, you'd have to write a ton of boilerplate code for\nthe ORM you're using, then integrate that into some web framework. \n\nI don't want to write boilerplate.\n\nHere's what's required to create a RESTful API service from an existing database using\n`sandman`:\n\n```bash\n$ sandmanctl sqlite:////tmp/my_database.db\n```\n\n*That's it.* `sandman` will then do the following:\n\n* connect to your database and introspect its contents\n* create and launch a REST API service\n* create an HTML admin interface\n* *open your browser to the admin interface*\n\nThat's right. Given a legacy database, `sandman` not only gives you a REST API,\nit gives you a beautiful admin page and *opens your browser to the admin page*.\nIt truly does everything for you.\n\nSupported Databases\n------------------\n\n`sandman`, by default, supports connections to the same set of databases as\n[SQLAlchemy](http://www.sqlalchemy.org). As of this writing, that includes:\n\n* MySQL (MariaDB)\n* PostgreSQL\n* SQLite\n* Oracle\n* Microsoft SQL Server\n* Firebird\n* Drizzle\n* Sybase\n* IBM DB2\n* SAP Sybase SQL Anywhere\n* MonetDB\n\nAuthentication\n--------------\n\nAs of version 0.9.3, `sandman` fully supports HTTP Basic Authentication! See the\ndocumentation for more details.\n\nBehind the Scenes\n-----------------\n\n`sandmanctl` is really just a simple wrapper around the following:\n\n```python\nfrom sandman import app\n\napp.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///chinook'\n\nfrom sandman.model import activate\n\nactivate()\n\napp.run()\n```\n\n**You don't even need to tell `sandman` what tables your database contains.** \nJust point `sandman` at your database and let it do all the heavy lifting\n\nLet's start our new service and make a request. While we're at it, lets make use\nof `sandman`'s awesome filtering capability by specifying a filter term:\n\n```zsh\n\u003e python runserver.py \u0026\n* Running on http://127.0.0.1:5000/\n\n\u003e curl GET \"http://localhost:5000/artists?Name=AC/DC\"\n```\n\n```json\n...\n{\n    \"resources\": [\n        {\n            \"ArtistId\": 1,\n            \"Name\": \"AC/DC\",\n            \"links\": [\n                {\n                    \"rel\": \"self\",\n                    \"uri\": \"/artists/1\"\n                }\n            ]\n        }\n    ]\n}\n```\n\nAll of that, including filtering/searching, is automagically available from\nthose *five* measly lines of code.\n\nOh, that's not enough? You also want a Django-style admin interface built\nautomatically? Fine. You may have noticed that when you ran `runserver.py` that\na browser window popped up. Now's the time to go check that out. You'll find\nit's that Django-style admin interface you've been bugging me about, looking\nsomething like this:\n\n![admin interface awesomesauce screenshot](http://sandman.io/static/img/admin_small.jpg)\n\n----\n\n(If you want to disable the browser from opening automatically each time `sandman`\nstarts, call `activate` with `browser=False`)\n\nIf you wanted to specify specific tables that `sandman` should make available,\nhow do you do that? With this little ditty:\n\n```python\nfrom sandman.model import register, Model\n\nclass Artist(Model):\n    __tablename__ = 'Artist'\n\nclass Album(Model):\n    __tablename__ = 'Album'\n\nclass Playlist(Model):\n    __tablename__ = 'Playlist'\n\nregister((Artist, Album, Playlist))\n```\n\nAnd if you wanted to add custom logic for an endpoint? Or change the endpoint\nname? Or change your top level json object name? Or add validation? All supported.\nHere's a \"fancy\" class definition:\n\n```python\nclass Style(Model):\n    \"\"\"Model mapped to the \"Genre\" table\n\n    Has a custom endpoint (\"styles\" rather than the default, \"genres\").\n    Only supports HTTP methods specified.\n    Has a custom validator for the GET method.\n\n    \"\"\"\n\n    __tablename__ = 'Genre'\n    __endpoint__ = 'styles'\n    __methods__ = ('GET', 'DELETE')\n    __top_level_json_name__ = 'Genres'\n\n    @staticmethod\n    def validate_GET(resource=None):\n        \"\"\"Return False if the request should not be processed.\n\n        :param resource: resource related to current request\n        :type resource: :class:`sandman.model.Model` or None\n\n        \"\"\"\n\n        if isinstance(resource, list):\n            return True\n        elif resource and resource.GenreId == 1:\n            return False\n        return True\n```\n\nWith `sandman`, zero boilerplate code is required. In fact, using `sandmanctl`,\n**no code is required at all**. Your existing database\nstructure and schema is introspected and your database tables magically get a\nRESTful API and admin interface. For each table, `sandman` creates:\n\n* proper endpoints \n* support for a configurable set of HTTP verbs \n    * GET\n    * POST\n    * PATCH\n    * PUT\n    * DELETE\n* responses with appropriate `rel` links automatically\n  * foreign keys in your tables are represented by link\n* custom validation by simply defining `validate_\u003cMETHOD\u003e` methods on your Model\n* explicitly list supported methods for a Model by setting the `__methods__` attribute\n* customize a Models endpoint by setting the `__endpoint__` method\n* essentially a HATEOAS-based service sitting in front of your database\n\n`sandman` is under active development but should be usable in any environment due\nto one simple fact:\n\n**`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.** \n\n### Installation\n\n`pip install sandman`\n\n### Example Application\n\nTake a look in the `sandman/test` directory. The application found there makes\nuse of the [Chinook](http://chinookdatabase.codeplex.com) sample SQL database.\n\n## Contact Me\n\nQuestions or comments about `sandman`? Hit me up at [jeff@jeffknupp.com](mailto:jeff@jeffknupp.com).\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/jeffknupp/sandman/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n\n# Changelog\n\n## Version 0.9.8\n\n* Support for the `wheel` distribution format\n\n## Version 0.9.7\n\n* Slightly better test coverage and documentation\n\n## Version 0.9.6\n\n* Support for using existing declarative models alongside `sandman` generated models\n    * If you have an existing app and want to include sandman in it, simply pass\n      your existing models in to the `register()` function along with any\n      `sanmdman` generated classes. `sandman` will detect the existing models\n      and augment them.\n\n## Version 0.9.5\n\n* Fixes a critical bug where code used by the new `etag` decorators was\n  accidentally not included. Thanks to @mietek for the PR.\n* Fixes an issue when showing the HTML representation of an empty collection.\n* Thanks to @mietek for reporting the issue.\n\n## Version 0.9.4\n\n* Fixes a critical bug in the requirements portion of `setup.py`, adding `Flask-HTTPAuth`\n\n## Version 0.9.3\n\n* Authentication supported!\n    * Entire API and admin can be protected by HTTP Basic Auth. See the docs for\n      more details.\n* ETAGs\n    * Resources return the proper ETAG header and should reply with a 304 after\n      the first request. This greatly improves the throughput and performance of\n      the API.\n\n## Version 0.9.2\n\n* The `meta` endpoint\n    * All resources now have a `/\u003cresource\u003e/meta` endpoint that describes the\n      types of each of their fields (both in HTML and JSON) \n* The root endpoint\n    * A \"root\" endpoint (`/`) has been created. It lists all resources\n      registered in the application and includes URLs to their various\n      endpoints. This allows a \"dumb\" client to navigate the API without knowing\n      URLs beforehand.\n\n## Version 0.9.1\n\n* Python 3 support!\n    * `sandman` tests now pass for both 2.7 and 3.4! Python 3.4 is officially supported.\n\n## Version 0.8.1\n\n### New Feature\n\n* `Link` header now set to a resource's links\n    * Links to related objects now user a proper `rel` value: `related`\n    * The link to the current resource still uses the `self` `rel` value\n    * Links are specified both in the header (as per RFC5988) and in the\n      resource itself\n* Pagination added for JSON (and number of results per page being returned is fixed)\n* Nested JSON models no longer the default; hitting a URL with the argument \"expand\"\n  will show one level of nested resources\n    * This conforms more closely to REST principles while not sacrificing the\n      functionality. \n\n\n## Version 0.7.8\n\n### Bug Fixes\n\n* Fix multiple references to same table error (fixes #59)\n","funding_links":[],"categories":["Python","RESTful API","Web Development","资源列表","Servers","others","Awesome Python"],"sub_categories":["General","RESTful API","Python"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffknupp%2Fsandman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeffknupp%2Fsandman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffknupp%2Fsandman/lists"}