UnRest - Simple sqlalchemy rest api generation.
from unrest import UnRest
# First, initialize UnRest with your web application
rest = UnRest(app)
# Then declare your endpoint
rest(Person)
This should provide you a /api/person and a /api/person/<login> route accessible in GET only.
To activate data modification, set the methods array like this:
rest(Person, only=['name', 'sex', 'age'], methods=['GET', 'PUT', 'POST', 'DELETE', 'PATCH']) # or simply methods=rest.all
You will get both routes (collection and member) on the five methods. Please see the wikipedia page for their signification.
You can also override the default methods like this:
person = rest(Person)
@person.declare('GET')
def get(payload, login=None):
# Pre get hook
if login:
login = login.upper()
rv = person.get(payload, login=login)
# Post get hook
return {
'occurences': rv['occurences'],
'objects': [
{'login': person['login'].lower()} for person in rv['objects']
]
}
Documentation
Full documentation can be found at kozea.github.io/unrest
Example
Consider this simple web application:
from datetime import timedelta
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import relationship
from sqlalchemy.sql.schema import Column, ForeignKey
from sqlalchemy.types import Integer, Interval, Numeric, String
from unrest import UnRest
# Flask application
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/unrest.db'
# Model definition
db = SQLAlchemy(app)
class Tree(db.Model):
id = Column(Integer, primary_key=True)
name = Column(String)
@property
def fruit_colors(self):
return ', '.join([fruit.color for fruit in self.fruits])
class Fruit(db.Model):
fruit_id = Column(Integer, primary_key=True)
color = Column(String(50))
size = Column(Numeric)
age = Column(Interval)
tree_id = Column(Integer, ForeignKey('tree.id'))
tree = relationship(Tree, backref='fruits')
# Drop everything just in case
db.drop_all()
# Create model
db.create_all()
# Data insertion
pine = Tree(name='pine')
maple = Tree(name='maple')
oak = Tree(name='oak')
db.session.add(pine)
db.session.add(maple)
db.session.add(oak)
db.session.add(Fruit(color='grey', size=12, age=timedelta(days=12, hours=1, minutes=15), tree=pine))
db.session.add(Fruit(color='darkgrey', size=23, age=timedelta(days=49, seconds=230, milliseconds=213), tree=pine))
db.session.add(Fruit(color='brown', size=2.12, age=timedelta(0), tree=pine))
db.session.add(Fruit(color='red', size=.5, age=timedelta(minutes=40), tree=maple))
db.session.add(Fruit(color='orangered', size=100, age=timedelta(hours=2, microseconds=12), tree=maple))
db.session.commit()
db.session.remove()
# Declare rest endpoints
rest = UnRest(app, db.session)
# Authorize every methods
rest(Tree, methods=rest.all, allow_batch=True)
# Don't authorize batch for fruits
rest(Fruit, methods=rest.all)
# Run the app
app.run(debug=True)
You will now have:
GET
With primary keys arguments
$ curl -s http://localhost:5000/api/tree/1
200 OK
{
"occurences": 1,
"objects": [
{
"id": 1,
"name": "pine"
}
]
}
$ curl -s http://localhost:5000/api/fruit/1
200 OK
{
"occurences": 1,
"objects": [
{
"fruit_id": 1,
"color": "grey",
"size": 12.0,
"age": 1041300.0,
"tree_id": 1
}
]
}
Without argument
$ curl -s http://localhost:5000/api/tree
200 OK
{
"occurences": 3,
"objects": [
{
"id": 1,
"name": "pine"
},
{
"id": 2,
"name": "maple"
},
{
"id": 3,
"name": "oak"
}
]
}
$ curl -s http://localhost:5000/api/fruit
200 OK
{
"occurences": 5,
"objects": [
{
"fruit_id": 1,
"color": "grey",
"size": 12.0,
"age": 1041300.0,
"tree_id": 1
},
{
"fruit_id": 2,
"color": "darkgrey",
"size": 23.0,
"age": 4233830.213,
"tree_id": 1
},
{
"fruit_id": 3,
"color": "brown",
"size": 2.12,
"age": 0.0,
"tree_id": 1
},
{
"fruit_id": 4,
"color": "red",
"size": 0.5,
"age": 2400.0,
"tree_id": 2
},
{
"fruit_id": 5,
"color": "orangered",
"size": 100.0,
"age": 7200.000012,
"tree_id": 2
}
]
}
PUT
With primary keys arguments
$ curl -s http://localhost:5000/api/tree/1 -X PUT -H "Content-Type: application/json" -d '{
"name": "cedar"
}'
200 OK
{
"occurences": 1,
"objects": [
{
"id": 1,
"name": "cedar"
}
]
}
Get it again to be sure:
$ curl -s http://localhost:5000/api/tree/1
200 OK
{
"occurences": 1,
"objects": [
{
"id": 1,
"name": "cedar"
}
]
}
Without argument
$ curl -s http://localhost:5000/api/tree -X PUT -H "Content-Type: application/json" -d '{
"objects": [{"id": 2, "name": "cedar"}, {"id": 22, "name": "mango"}]
}'
200 OK
{
"occurences": 2,
"objects": [
{
"id": 2,
"name": "cedar"
},
{
"id": 22,
"name": "mango"
}
]
}
Get it again to be sure:
$ curl -s http://localhost:5000/api/tree
200 OK
{
"occurences": 2,
"objects": [
{
"id": 2,
"name": "cedar"
},
{
"id": 22,
"name": "mango"
}
]
}
Check that when allow_batch is not set we can't put all:
$ curl -s http://localhost:5000/api/fruit -X PUT -H "Content-Type: application/json" -d '{
"objects": [
{"fruit_id": 2, "color": "red"},
{"fruit_id": 22, "color": "blue"}
]
}'
406 Not Acceptable
{
"message": "You must set allow_batch to True if you want to use batch methods."
}
POST
With primary keys arguments
$ curl -s http://localhost:5000/api/tree/1 -X POST -H "Content-Type: application/json"
501 Not Implemented
{
"message": "POST on id corresponds to collection creation. It's not implemented by default. If you want to update an item use the PUT method instead"
}
Without argument
$ curl -s http://localhost:5000/api/fruit -X POST -H "Content-Type: application/json" -d '{
"color": "forestgreen", "size": 3.14, "age": 1.5926, "tree_id": 3
}'
200 OK
{
"occurences": 1,
"objects": [
{
"fruit_id": 6,
"color": "forestgreen",
"size": 3.14,
"age": 1.5926,
"tree_id": 3
}
]
}
Now we should have a total of 6 fruits:
$ curl -s http://localhost:5000/api/fruit
200 OK
{
"occurences": 6,
"objects": [
{
"fruit_id": 1,
"color": "grey",
"size": 12.0,
"age": 1041300.0,
"tree_id": 1
},
{
"fruit_id": 2,
"color": "darkgrey",
"size": 23.0,
"age": 4233830.213,
"tree_id": 1
},
{
"fruit_id": 3,
"color": "brown",
"size": 2.12,
"age": 0.0,
"tree_id": 1
},
{
"fruit_id": 4,
"color": "red",
"size": 0.5,
"age": 2400.0,
"tree_id": 2
},
{
"fruit_id": 5,
"color": "orangered",
"size": 100.0,
"age": 7200.000012,
"tree_id": 2
},
{
"fruit_id": 6,
"color": "forestgreen",
"size": 3.14,
"age": 1.5926,
"tree_id": 3
}
]
}
DELETE
With primary keys arguments
$ curl -s http://localhost:5000/api/fruit/3 -X DELETE
200 OK
{
"occurences": 1,
"objects": [
{
"fruit_id": 3,
"color": "brown",
"size": 2.12,
"age": 0.0,
"tree_id": 1
}
]
}
Now we should have only 5 fruits remaining:
$ curl -s http://localhost:5000/api/fruit
200 OK
{
"occurences": 5,
"objects": [
{
"fruit_id": 1,
"color": "grey",
"size": 12.0,
"age": 1041300.0,
"tree_id": 1
},
{
"fruit_id": 2,
"color": "darkgrey",
"size": 23.0,
"age": 4233830.213,
"tree_id": 1
},
{
"fruit_id": 4,
"color": "red",
"size": 0.5,
"age": 2400.0,
"tree_id": 2
},
{
"fruit_id": 5,
"color": "orangered",
"size": 100.0,
"age": 7200.000012,
"tree_id": 2
},
{
"fruit_id": 6,
"color": "forestgreen",
"size": 3.14,
"age": 1.5926,
"tree_id": 3
}
]
}
Without argument
Batch delete is not allowed on fruit:
$ curl -s http://localhost:5000/api/fruit -X DELETE
501 Not Implemented
{
"message": "You must set allow_batch to True if you want to use batch methods."
}
But is on tree:
$ curl -s http://localhost:5000/api/tree -X DELETE
200 OK
{
"occurences": 3,
"objects": [
{
"id": 1,
"name": "pine"
},
{
"id": 2,
"name": "maple"
},
{
"id": 3,
"name": "oak"
}
]
}
$ curl -s http://localhost:5000/api/tree
200 OK
{
"occurences": 0,
"objects": []
}
PATCH
With primary keys arguments
$ curl -s http://localhost:5000/api/fruit/1 -X PATCH -H "Content-Type: application/json" -d '{
"color": "blue"
}'
200 OK
{
"occurences": 1,
"objects": [
{
"fruit_id": 1,
"color": "blue",
"size": 12.0,
"age": 1041300.0,
"tree_id": 1
}
]
}
Without argument
$ curl -s http://localhost:5000/api/tree -X PATCH -H "Content-Type: application/json" -d '{
"objects": [{"id": 2, "name": "cedar"}, {"id": 3, "name": "mango"}]
}'
200 OK
{
"occurences": 2,
"objects": [
{
"id": 2,
"name": "cedar"
},
{
"id": 3,
"name": "mango"
}
]
}
Check that when allow_batch is not set we can't put all:
$ curl -s http://localhost:5000/api/fruit -X PATCH -H "Content-Type: application/json" -d '{
"objects": [
{"fruit_id": 1, "color": "blue"},
{"fruit_id": 3, "age": 1038540.0},
{"fruit_id": 4, "color": "rainbow", "size": 8},
{"fruit_id": 5, "size": 10, "tree_id": 1}
]
}'
406 Not Acceptable
{
"message": "You must set allow_batch to True if you want to use batch methods."
}
otherwise all the specified attributes would have been patched.
Metadata
Release files for unrest 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| unrest-1.1.0.tar.gz | 43.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| unrest-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 101.5 kB
Release files / unrest-1.1.0.tar.gz
| Download URL | unrest-1.1.0.tar.gz |
|---|---|
| Size | 43.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
be0417c08b0675698641258ab5f1e921c71ba8d6c3b54283566ebec7a7762164
|
|
BLAKE2b-256 checksum How to use checksums |
d9fc0b9ce1c8018752824c2d72f3988f190cf07d1d53527e9c6811ce7e7e9374
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.25.1
|
Release files / unrest-1.1.0-py3-none-any.whl
| Download URL | unrest-1.1.0-py3-none-any.whl |
|---|---|
| Size | 57.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0c2ee6294f4f3d7c94c01aa3f56c51ad70e8a8e5f68b6efdcc37d185360efbf6
|
|
BLAKE2b-256 checksum How to use checksums |
824c66f47280d043b8700541de96d4c170eb147eeb9c5cd59e0c46a9839ae0c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.25.1
|
Security for unrest 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.