Skip to main content

Wonderful REST APIs.

Project description

Layab: Wonderful REST APIs

pypi version Build status Coverage Code style: black Number of tests Number of downloads

Layab stands for Wonderful in Somali and is also a shortcut for Layabout (aren't we all lazy).

This package provides functions and classes that can be used to facilitate the creation of APIs.

If you were using layab 1.* (based on Flask-RestPlus, a project that is now dead and will not be compatible starting with Python 3.9), please refer to the Migration guide as layab now advocate the use of Starlette.

Why didn't you switched from Flask-RestPlus to another Starlette based all-in-one framework (such as FastAPI or Responder)?

Modularity is a key principle in software development. However the use of such framework prevent such development.

An all-in-one framework is more likely to requires hack to fit your usage.

An all-in-one framework is more likely to have a slower development and release pace.

By using layab 2, you can still use an all-in-one framework, but you also can chose what and if you want to:

  • Generate an OpenAPI definition.

  • Embed Swagger-UI.

  • Validate data.

  • Serialize / Deserialize data.

  • ...

Available features

Starlette

Middleware

You can get a bunch of already created Starlette middleware thanks to layab.starlette.middleware function.

from starlette.applications import Starlette
from layab.starlette import middleware

app = Starlette(middleware=middleware())

By default you will have the following middleware:

  • LoggingMiddleware: Log requests upon reception and return (failure or success).
  • CORSMiddleware: Allow cross origin requests.
  • ProxyHeadersMiddleware: Handle requests passing by a reverse proxy.

Responses

Default responses are available to return standard responses.

Location response
from starlette.applications import Starlette
from layab.starlette import LocationResponse

app = Starlette()

@app.route("/resource", methods=["POST", "PUT"])
def handle_resource(request):
    resource_id = create_update_resource()  # Implement this endpoint
    return LocationResponse(request, "/resource/{resource_id}")

@app.route("/resource/{resource_id}", methods=["GET"])
def get_resource(request):
    pass  # Implement this endpoint

Configuration

API and logging configuration should be stored in YAML format.

Configuration is expected to be stored inside a configuration folder located on the parent folder of the provided file path.

API Configuration is expected to follow the "configuration_{env}.yml" naming where env is the value of the SERVER_ENVIRONMENT environment variable.

If not found, environment will be considered as "default".

Logging configuration is loaded using the same logic and the following naming: "logging_{env}.yml".

import layab

# Load logging and service configuration
service_configuration = layab.load('path/to/a/file/in/module/folder')

Note that in case your logging configuration file contains execution of Python code, you will need to provide the yaml.UnsafeLoader loader.

import layab
import yaml

# Load logging and service configuration
service_configuration = layab.load('path/to/a/file/in/module/folder', logging_loader=yaml.UnsafeLoader)

Migration guide

If an information on something that was previously existing is missing, please open an issue.

Create application and OpenAPI definition and Swagger-UI endpoints

Layab 1.*

import layab

app, api = layab.create_api(
    __file__,
    compress_mimetypes=["text/csv", "application/json"],
    title="My API.",
    description="My description.",
)

Layab 2.* using flask-restx

import flask
import layab
from layab.flask_restx import enrich_flask, log_requests, Api

app = flask.Flask(__name__)
enrich_flask(app, compress_mimetypes=["text/csv", "application/json"])
api = Api(
    app, 
    title="My API.",
    description="My description.",
    version="1.0.0",  # You now have to set the version yourself
    info={"x-server-environment": layab.get_environment()}
)
log_requests(skip_paths=["/health"])

Layab 2.* using Starlette

import layab
from layab.starlette import middleware
from starlette.applications import Starlette
import apispec_starlette

app = Starlette(middleware=middleware())
spec = apispec_starlette.add_swagger_json_endpoint(
    app, 
    title="My API.",
    version="1.0.0",  # You now have to set the version yourself
    info={
        "description": "My description.",
        "x-server-environment": layab.get_environment(),
    }
)
# You will however lose the Swagger-ui that was available on / (root endpoint)
# We advise to install it on your Docker image first and then serve the directory as "/" as the last declared route.

Monitoring endpoints

Layab 1.*

import layab

api = None

def health_details():
    pass  # Implement this


layab.add_monitoring_namespace(api, health_details)

Layab 2.* using flask-restx

import os.path

from healthpy.flask_restx import add_consul_health_endpoint
from keepachangelog.flask_restx import add_changelog_endpoint

api = None

async def health_check():
    pass  # Implement this


namespace = api.namespace(
    "Monitoring", path="/", description="Monitoring operations"
)
# You now have to set the release_id yourself
add_consul_health_endpoint(namespace, health_check, release_id="1.0.0")
# You now have to set the path to the changelog yourself
changelog_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "CHANGELOG.md")
add_changelog_endpoint(namespace, changelog_path)

Layab 2.* using Starlette

import os.path

from starlette.applications import Starlette
from healthpy.starlette import add_consul_health_endpoint
from keepachangelog.starlette import add_changelog_endpoint

app = Starlette()

async def health_check():
    pass  # Implement this


add_consul_health_endpoint(app, health_check)
# You now have to set the path to the changelog yourself
changelog_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "CHANGELOG.md")
add_changelog_endpoint(app, changelog_path)

You can now add only one of the two initially provided endpoints (in case you don't have or want to expose your changes).

Refer to healthpy documentation for more information on what is possible to check API health.

Refer to keepachangelog documentation for more information on how changelog is handled.

Created response

Layab 1.*

import layab

api = None

@api.doc(**layab.created_response_doc(api))
def endpoint():
    return layab.created_response("/this_is_the_location")

Layab 2.* using flask-restx

import flask_restx
from layab.flask_restx import location_response

api = None

@api.response(201, "Resource created", flask_restx.fields.String, headers={"location": "Resource location."})
def endpoint():
    return location_response("/this_is_the_location")

Layab 2.* using Starlette

from layab.starlette import LocationResponse

def endpoint(request):
    """
    responses:
        201:
            description: "Resource created"
            headers:
                location:
                    description: "Resource location."
                    type: string
            schema:
                type: string
    """
    return LocationResponse(request, "/this_is_the_location")

Updated response

Layab 1.*

import layab

api = None

@api.doc(**layab.updated_response_doc(api))
def endpoint():
    return layab.updated_response("/this_is_the_location")

Layab 2.* using flask-restx

import flask_restx
from layab.flask_restx import location_response

api = None

@api.response(201, "Resource updated", flask_restx.fields.String, headers={"location": "Resource location."})
def endpoint():
    return location_response("/this_is_the_location")

Layab 2.* using Starlette

from layab.starlette import LocationResponse

def endpoint(request):
    """
    responses:
        201:
            description: "Resource updated"
            headers:
                location:
                    description: "Resource location."
                    type: string
            schema:
                type: string
    """
    return LocationResponse(request, "/this_is_the_location")

Deleted response

Layab 1.*

import layab

api = None

@api.response(*layab.deleted_response_doc)
def endpoint():
    return layab.deleted_response

Layab 2.* using flask-restx

import flask

api = None

@api.response(204, "Resource deleted")
def endpoint():
    return flask.Response(b"", status=204)

Layab 2.* using Starlette

from starlette.responses import Response

def endpoint(request):
    """
    responses:
        204:
            description: "Resource deleted"
    """
    return Response(status_code=204)

How to install

  1. python 3.6+ must be installed
  2. Use pip to install module:
python -m pip install layab

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

layab-2.2.0.tar.gz (12.7 kB view details)

Uploaded Source

Built Distribution

layab-2.2.0-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file layab-2.2.0.tar.gz.

File metadata

  • Download URL: layab-2.2.0.tar.gz
  • Upload date:
  • Size: 12.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.7.1

File hashes

Hashes for layab-2.2.0.tar.gz
Algorithm Hash digest
SHA256 78c4f7e6519bcf754463858b81872b00ef25e484f3ea6dccf6ecd4aa690d3efc
MD5 da49c65312a6d6dc2b2ee7f52bfee8a7
BLAKE2b-256 f575b22a246aba450ab6682be123795b1baa489d6b441b17bdf1da5512ebf054

See more details on using hashes here.

File details

Details for the file layab-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: layab-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.7.1

File hashes

Hashes for layab-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 551320de030327403aafa79a7c2a5f13d3912ebc89daa8e1da559ac8583f7c71
MD5 76befca62008919399f5f5b7a7a1a321
BLAKE2b-256 e314d66f3fcdd6d3ab8447b0ae501449bbb34af536397ddd33d00093afaa5985

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page