Skip to main content

Set of semi-adapters for Sanic framework to autodiscovery routes defined by adapters @route decorator instead of defining multiple resources or registering each route, resource, and blueprint in separate calls.

Project description

sanic-adapters-200

Sanic Adapters

Set of semi-adapters for Sanic framework. The main idea was to autodiscovery routes defined by adapters @route decorator instead of defining multiple resources or registering each route, resource, and blueprint in separate calls. Currently

Why?

The idea of Adapters is to:

  • Simplify the naming convention to be more understandable by each other
  • Simplify things like registering blueprints and adding routes to blueprints
  • Aggregate each Sanic Classed Based View in one Resource class which is similar to Controller from MVC
  • Implement structures and frames as same as the framework helps to implement RESTfish or RESTFull routes in the current framework

Current version

  • Currently, the idea of RESTfish or RESTfull was implemented as a Sanic blueprint (called by this repo as RoutePart) which is composed of resources called by Sanic as Classed Based Views (HTTPMethodView) but for adapters, it is renamed to RESTResource. All binding is realized by the RESTFramework resource using the autodiscovery method which imports all routes from a defined package and build the structure required for the Sanic app.

Installation

by pip

pip install sanic-adapters

by poetry

poetry add sanic-adapters

Getting started

Example Directories Structure

/project
├── /src
│   ├── /application
│   ├── /domain
│   ├── /infrastructure
│   │   └── /repositories
│   │       └── transactions.py
│   └── /interface
│       └── /sanic
│           ├── /routes
│           │   └── transaction.py
│           ├── server.py
│           └── services.yaml
├── .gitignore
├── requirements.txt
├── pyproject.toml
├── README.md
└── ...

Example routes/transaction.py:

# ../src/interface/sanic/routes/transaction.py
from sanic.response import text
from sanic_adapters.resources import RESTResource
from sanic_adapters.decorators import route
from project.src.infrastructure.repositories.transactions import TransactionsRepository


# [ Optional ] can be used class decorator (ResourceOverride) to change default mapping from Transaction -> /transaction
class Transactions(RESTResource):
    @route(name="list_of_transactions", path="/")
    async def get(self, name: str, transactions: TransactionsRepository):
        return text(f"Hello World my dear {name.title()} {transactions=}")

Example repositiries/transactions.py:

# ../src/infrastructure/repositories/transactions.py
from dataclasses import dataclass


@dataclass
class TransactionsRepository:
    ...

Example server.py

# ../src/interface/sanic/server.py
from sanic import Sanic
from sanic_adapters.adapters import RESTFramework
from sanic_adapters.adapters import IoC

app = Sanic("project")

ioc = IoC(app, "services.yaml")
app.blueprint(RESTFramework.autodiscover("project.src.interface.sanic.routes"))  # argument is package path as string

OR

# ../src/interface/sanic/server.py
from sanic import Sanic
from sanic_adapters.adapters import RESTFramework
from sanic_adapters.adapters import IoC

app = Sanic("project")

@app.before_server_start
async def before_start(*_):
    IoC(app, "services.yaml")
    app.blueprint(RESTFramework.autodiscover("project.src.interface.sanic.routes"))  # argument is package path as string

Alternative server.py - not tested yet

# ../src/interface/sanic/server.py
from sanic import Sanic
from sanic_adapters.adapters import RESTFramework
from sanic_adapters.adapters import IoC

app = Sanic("project")

ioc = IoC(app, "services.yaml")
rest = RESTFramework(app, "project.src.interface.sanic.routes")  # argument is package path as string

or

# ../src/interface/sanic/server.py
from sanic import Sanic
from sanic_adapters.adapters import RESTFramework
from sanic_adapters.adapters import IoC

app = Sanic("project")

@app.before_server_start
async def before_start(*_):
    IoC(app, "services.yaml")
    RESTFramework(app, "project.src.interface.sanic.routes")  # argument is package path as string

Example services.yaml

transactions:
  class: "project.src.infrastructure.repositories.transactions.TransactionsRepository"
  provided_by: "Factory"

Example usage out of sanic dependency scope:

from sanic_adapters.adapters import IoC

transaction_repository = IoC.services.transactions()

Documentation

To Be Continued...
For current release you can use Two important decorators:

1. @ResourceOverride(path=...)

This is responsible for change default path from register route class name to your custom path

  • Each Resource class in routes package is register as Sanic Blueprint with default name convention of class:
    --> CamelCase == will be mapped to route path ==> /camel-case - for automatically standard convention
    --> Classname == will be mapped to route path ==> /classname - for automatically standard convention
  • Each Route registered by @route decorator is annonymous Class Based View with single method

2. @route(name="...", path="...", method="...")

This register in static fields each route as single Class Based View in sanic app with single method. Reason of this forcing the user of the framework to use separate request handler as a separate method of class and design better code with best practicies. The name of endpoint in sanic is kind of unique primary key, and that means each method of Resource class is a single REST(fish/full) Resource.

🔻 Important 🔻🔻🔻

  • Name of method starting of HTTP method (i.e HTTP METHOD GET for function def get(...) or def get_something(...)) is automatically mapped to route with HTTP Method "GET"
  • When you use kwargs method="POST" in @route decorator you can override HTTP method for this resource

In future

  • Add other adapters to be less RESTfish or RESTFull
  • Add HATEOAS semi-framework (sub-framework)
  • Add decorator to wrap @inject for IoC for Dependency Injector to use injection only by class type hint
    (maybe this will be new one project for that solution)
from dataclasses import dataclass
from pytheons.dependency_injector.decorators import service
from project.src.infrastructure.repositories.transactions import TransactionsRepository

@service
@dataclass
class MyService:
  transaction: TransactionsRepository
  • Add support for Class Based Websockets
  • Add support for Class Based Middlewares
  • More Refactors and Simplifications with optimization
  • Add support for sanic-motor and move to Data Mapper Pattern based on @dataclass decorator and Domain Driven Design Mapping

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

sanic_adapters-0.2.1.tar.gz (7.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sanic_adapters-0.2.1-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file sanic_adapters-0.2.1.tar.gz.

File metadata

  • Download URL: sanic_adapters-0.2.1.tar.gz
  • Upload date:
  • Size: 7.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.5 CPython/3.12.7 Linux/5.15.173-1-MANJARO

File hashes

Hashes for sanic_adapters-0.2.1.tar.gz
Algorithm Hash digest
SHA256 8744e32d5a3c387e2ef6ec52bf58faee4683393cb65a41ef77ed0f9c7c4b729c
MD5 9972bab1754167e89e5ebf8dc125ccd6
BLAKE2b-256 1453923eb593dc13bedb606d6d5196fa7bbf11e8f6a7af8b7ba663617f3acf57

See more details on using hashes here.

File details

Details for the file sanic_adapters-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: sanic_adapters-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 8.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.5 CPython/3.12.7 Linux/5.15.173-1-MANJARO

File hashes

Hashes for sanic_adapters-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 64126cb83a42d09be2b9e809c3266b7efeb0bd4aaf525b045fbf5ac4a46da8dc
MD5 72565dcf347aae9e8b25ff2cb4da1bf7
BLAKE2b-256 bf833bb8871101ddfdd9ef1d58255d1ef2c0f96f7c266eeabab62dce9192060e

See more details on using hashes here.

Supported by

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