Skip to main content

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 lists
        • path : str
          Mapped URL path.
          Do not include scheme, authority, query or fragment.
        • handler : Callable
          Object (or function) to call to handle incoming POST requests to path.
          • Parameters
            • data : dict, list, int, float, string, bool or None
              Deserialied JSON request body if any, otherwhise None
          • Returns
            JSON serializable object or None.
            (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)
      • allowEmptyRequestBody : bool (True by default)
        In the case of empty or space request body, if True handler argument will be None, otherwise a BadRequestException will be raised.
        (Note: if True empty or space request body will not be distinguishable from null body)
    • Returns
      WSGI application.

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.
  • Field
    • Constructor
      • Parameters
        • missing : Do or Default
          What to do when this field is missing.
        • error : Do or Default
          What to do when this field is invalid.
    • 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.
      • 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.

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}")

Release files for swjas 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for swjas 0.1.0
File Size Uploaded
swjas-0.1.0.tar.gz 15.8 kB Details

Release files / swjas-0.1.0.tar.gz

Download URL swjas-0.1.0.tar.gz
Size 15.8 kB
Tags Source
SHA-256 checksum
How to use checksums
f3a9ae56fe4d25c2cb0cabe0069e9345916f2a8d21a5e74c175b25340593bb32
BLAKE2b-256 checksum
How to use checksums
7c3db8a19dc55c956e720f953f7fd6877dd6e1b59174959024caef1d61ea03b3
Upload date
Uploaded using Trusted Publishing?
What is 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

Release history Release notifications | RSS feed

This release

0.1.0 This release

1 release file

0.0.9

1 release file

0.0.8

1 release file

0.0.7

1 release file

0.0.6

1 release file

0.0.5

1 release file

0.0.4

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page