Simple WSGI JSON API Server
Project description
swjas
Simple WSGI JSON API Server
Installation
pip install swjas
Core
Usage
Call core.makeApplication
to create your WSGI application.
makeApplication
- Parameters
route
: Iterable
Iterable of(path, handler)
tuples or listspath
:str
Mapped URL path.
Do not include scheme, authority, query or fragment.handler
: Callable
Object (or function) to call to handle incoming POST requests topath
.- Parameters
data
:dict
,list
,int
,float
,string
,bool
orNone
Deserialied JSON request body if any, otherwhiseNone
- Returns
JSON serializable object orNone
.
(Note:datetime.datetime
objects have built-in serialization support)
(Note: Custom objects can be serialized if they provide a_json
property that returns a JSON serializable object)
- Parameters
allowEmptyRequestBody
:bool
(True
by default)
In the case of empty or space request body, ifTrue
handler argument will beNone
, otherwise aBadRequestException
will be raised.
(Note: ifTrue
empty or space request body will not be distinguishable fromnull
body)
- Returns
WSGI application.
- Parameters
Examples
Serve using wsgi_ref
from wsgiref.simple_server import make_server
from swjas.core import makeApplication
# Services
def authentication(data):
authenticated = data["username"] == "Francesco" and data["password"] == "12345"
return {
"authenticated": authenticated
}
def intDivision(data):
if data["b"] == 0:
return {
"error": "Division by zero"
}
return {
"quotient": data["a"] // data["b"],
"remainder": data["a"] % data["b"]
}
# Server
if __name__ == "__main__":
routes = [
('auth', authentication),
('idiv', intDivision)
]
server = make_server("localhost", 8000, makeApplication(routes))
server.serve_forever()
Serve using waitress
import waitress
from swjas.core import makeApplication
import random, string
# Services
def generateRandomID(data):
id = ""
for _ in range(data["length"]):
id += random.choice(string.ascii_letters)
return {
"id": id
}
# Server
if __name__ == "__main__":
routes = [
('genid', generateRandomID)
]
waitress.serve(makeApplication(routes), listen='*:8000')
Define custom JSON serializable objects
class Point:
def __init__(x, y):
self.x = x
self.y = y
@property
def _json(self):
return [self.x, self.y]
Clean
Validate and clean the request body.
Usage
Decorate your handlers with the clean.clean
decorator.
clean
- Parameters
field
:Field
Expected request body scheme.
- Returns
Validated and cleaned request body. - Raises
exceptions.BadRequestException
If the request body does not match the provided scheme.
- Parameters
Field
- Constructor
- Parameters
missing
:Do
orDefault
What to do when this field is missing.error
:Do
orDefault
What to do when this field is invalid.
- Parameters
- Methods
clean
(abstract)
Validate and clean the field.
Derived fields must implement it.- Parameters
value
Deserialized request body value to clean.
- Returns
Cleaned value. - Raises
FieldException
If the value is invalid.
- Parameters
cleanAndAdd
Validate and clean the field.- Parameters
present
:bool
Whether the field is present or not.value
Deserialized request body value to clean.add
: Callable
Object (or function) to call if the field is cleaned.- Parameters
value
Cleaned value.
- Parameters
- Parameters
- Constructor
Examples
Simple cleaning
from swjas.clean import clean, Default, IntField, StringField, FloatField, DictField, ListField
@clean(DictField({
"a": IntField(min=1),
"b": IntField(min=1)
}))
def sumPositiveIntegers(data):
return {
"sum": data["a"] + data["b"]
}
@clean(ListField(minLength=1, fields=FloatField()))
def floatAverage(data):
return sum(data) / len(data)
@clean(DictField({
"username": StringField(minLength=5, maxLength=20, regex=r"[A-Za-z0-9]+"),
"password": StringField(minLength=8, maxLength=16, regex=r"[A-Za-z0-9]+"),
"age": IntField(min=18, max=150, missing=Default(None)),
"fullName": StringField(minLength=1, maxLength=128, missing=Default(None))
}))
def printMe(data):
print(data)
return {
"success": True
}
Custom field
from swjas.clean import TypeField, FieldException, Do
class EvenNumberField(TypeField):
def __init__(self, missing=Do.RAISE, error=Do.RAISE):
super().__init__(int, missing=missing, error=error)
def clean(self, value):
value = super().clean(value)
if value % 2 != 0:
raise FieldException("Odd number")
return value
Exceptions
Usage
Any uncatched exceptions.HttpException
will be serialized and added to the response body and will set the corresponding Http response status.
Any exception.PrintableException
cause set with the raise ... from
syntax will be added to the response body too.
Examples
Raise an HttpException
from swjas.exceptions import AuthorizationException, NotFoundException
if not authenticated:
raise AuthorizationException(message="Requested object requires authentication")
elif not exists:
raise NotFoundException(message="Requested object does not exist")
Raise an HttpException
with cause
try:
validateRequest(data)
except Exception as e:
from swjas.exceptions import BadRequestException
raise BadRequestException(message="Error while validating the request") from e
Create an HttpException
on the fly
from swjas.exceptions import HttpException
raise HttpException.build(410)
Define an HttpException
from swjas.exceptions import HttpException
class GoneException(HttpException):
statusCode = 410
Client
Send requests.
Usage
Run python -m swjas.client -h
from command line or call client.request
or client.service
functions.
Examples
Send a request providing JSON body via command line and save result to JSON file
>>> python -m swjas.client //localhost:8080/signup --outputstatus --indent 4 > response.json
{
"username": "Francesco",
"password": "12345"
}
^Z
Send a request providing JSON body via file and print result to console
>>> python -m swjas.client //localhost:8080/signup --if request.json
{
"result": "success"
}
Send a request via script
from swjas.client import HttpException, RequestException, request
data = {
"username": "Francesco",
"password": "12345"
}
try:
res = request("//localhost:8080/signup", data)
except HttpException as e:
print(f"{e.statusCode}: {e.statusMessage}\n{e.responseBody}")
except RequestException as e:
print(f"Request failed: {e}")
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file swjas-0.1.0.tar.gz
.
File metadata
- Download URL: swjas-0.1.0.tar.gz
- Upload date:
- Size: 15.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f3a9ae56fe4d25c2cb0cabe0069e9345916f2a8d21a5e74c175b25340593bb32 |
|
MD5 | 5d9dc5bd4e28d356bba556705ae5466e |
|
BLAKE2b-256 | 7c3db8a19dc55c956e720f953f7fd6877dd6e1b59174959024caef1d61ea03b3 |