Package: python-squall
Squall, API framework which looks aheadNavigationAboutMotivationPerformanceASAP and batchingUsageInstallQuick startOpenAPIRoutingCompressionHEAD parametersPathQueryHeaderCookieParameters configurationParameters validationBody processingResponse serializationResponse deserialization serializationOpentelemetry usageAcknowledgmentsRoadmapDependenciesVersioningLicenseAboutMotivationInitially, it was a library for ASGI frameworks for publishing RBAC routing information to the MTAG API-Gateway.
After some research, we have decided that this is the most expensive way and made a decision to create a framework
which will deliver the best experience in the development of applications behind the API-Gateway.Eventually, Squall is a part of the e2e solution for modern high-performance stacks.Performance1Kb no schema30Kb no schema1Kb schema30Kb schemaMore results and benchmark methodologyhereASAP and batchingSquall following own MTAG/Squall ASAP pattern. The idea of the ASAP pattern is pretty simple to understand.
If you have all necessaries to do something you can do in the next steps, you should do it now.Be careful. This pattern is mind-changing.The batch operation is always better than a lot of small ones.UsageInstallpip3installpython-squallYou also need some ASGI server. Let's install Uvicorn, the most popular one.pip3installuvicornQuick startCreateexample.pywith the following contentfromtypingimportList,OptionalfromdataclassesimportdataclassfromsquallimportSquallapp=Squall()@dataclassclassItem:name:strvalue:Optional[int]=None@app.get("/get",response_model=List[Item])asyncdefhandle_get()->List[Item]:return[Item(name="null_value"),Item(name="int_value",value=8)]@app.post("/post",response_model=Item)asyncdefhandle_post(data:Item)->Item:returndataAnd run ituvicornexample:appNow, we are able to surf our GET endpoint on:http://127.0.0.1:8000/getAnd let's play withcurlon POST endpoint# curl -X 'POST' 'http://127.0.0.1:8000/post' -H 'Content-Type: application/json' -d '{"name": "string", "value": 234}'{"name":"string","value":234}Type checking and validation is done byapischemafor both, Request and Response.# curl -X 'POST' 'http://127.0.0.1:8000/post' -H 'Content-Type: application/json' -d '{"name": "string", "value": "not_an_int"}'{"details":[{"loc":["value"],"msg":"expected type integer, found string"},{"loc":["value"],"msg":"expected type null, found string"}]}OpenAPI generationOpenAPI for your app generates automatically based on route parameters and schema you have defined.There are support for ReDoc and Swagger out of the box. You can reach it locally once your application started:Swagger:http://127.0.0.1:8000/docReDoc:http://127.0.0.1:8000/redocRoutingSquall provides familiar decorators for any method route registration on both, application itself and on nested routers.Methodapprouter *GET@app.get@router.getPUT@app.put@router.putPOST@app.post@router.postDELETE@app.delete@router.deleteOPTIONS@app.options@router.optionsHEAD@app.head@router.headPATCH@app.patch@router.patchTRACE@app.trace@router.trace*router = squall.Router()Nested routers supports prefixes and further nesting.fromsquallimportRouter,Squallanimals_router=Router(prefix="/animals")@animals_router.get("/")asyncdefget_animals():return[]@animals_router.get("/cat")asyncdefget_cat():return[]dogs_router=Router(prefix="/dogs")@dogs_router.get("/list")asyncdefget_all_dogs():return[]animals_router.include_router(dogs_router)app=Squall()app.include_router(animals_router)Will give usNested routing is usually used for splitting applications into files and achieving better project structure.CompressionSquall provides built-in blazing-fast compression based on Intel® Intelligent Storage Acceleration Library (Intel® ISA-L) using awesome Python'sisallibrary as binding.Compared to Python's builtins ISA-L can deliver up to 20 times faster compression. Such in-app performance does game-changing opportunities for the entire system set up,In order to enable compression you have to path compression config to Squall appfromsquallimportSquallfromsquall.compressionimportCompressionapp=Squall(compression=Compression())For more details checkcompression settingsAccept-Encodingheader also required. Squall supports gzip, deflate options for it.HEAD parametersThere are four kinds of parameters that developers can get from HTTP headers. Squall offers an interface for their conversion and validation.Path"Path" is a dynamic value specified by developers in the route URL.fromsquallimportSquall,Pathapp=Squall()@app.get("/company/{company_id}/employee/{employee_id}")asyncdefget_company_employee(company_id:int,employee_id=Path()):return{"company_id":company_id,"employee_id":employee_id,}Squall determinate affiliation of the variable with path by any of following ways:Default parameter value isPathinstanceParameter default name equal to route patternSpecifics:Allows only the following annotations:str,bytes,int,floatUnion,Optional, not allowed. Because a path can't have an undefined value. Also, parameters must have a strong conversion contract.If an annotation isn't set parameter will arrive asstrShares common configuration contract for head entities. Please, read morehere.Query"Query" is a way get query string parameters value(s).fromtypingimportListfromsquallimportSquall,Queryapp=Squall()@app.get("/")asyncdefget_company_employee(company_id:int=Query(),employee_ids:List[int]=Query()):return{"company_id":company_id,"employee_ids":employee_ids,}Specifics:Allowed annotations:str,bytes,int,float,Optional,ListIf it is a getting of multiple values for the same key, at the moment,value validationcannot be applied.Header"Header" is a way to get header value(s). Shares common behavior with QueryfromtypingimportListfromsquallimportSquall,Headerapp=Squall()@app.get("/")asyncdefget_company_employee(company_id:int=Header(),employee_ids:List[int]=Header()):return{"company_id":company_id,"employee_ids":employee_ids,}Specifics:Allowed annotations:str,bytes,int,float,Optional,ListIf it is a getting of multiple values for the same key, at the moment,value validationcannot be applied.Cookie"Cookie" is a way get cookie value.fromtypingimportListfromsquallimportSquall,Cookieapp=Squall()@app.get("/")asyncdefget_company_employee(user_id:int=Cookie()):return{"user_id":user_id,}Specifics:Allowed annotations:str,bytes,int,float,OptionalParameters configurationAll head fields share common configuration pattern which include the following list of parameters:default, default value to assignalias, replaces source key where to get the value fromtitle, title for schema specificationdescription, description for schema specificationvalid, instance of validator,squall.Numorsquall.Strexample, example for schema specificationexamples, multiple examples for schema specificationdeprecated, mark parameter as deprecated, will appear in specificationParameters validationAt the moment, Squall provides following validators that developer can apply to HEAD parameters values:squall.Num-int,floatvalidator. Following conditions are supported:gt,ge,lt,lesquall.Str-str,bytesvalidator. Following conditions are supported:min_len,max_lenPlease, take a look at therelated test suiteBody processingSchema defined using dataclasses behind the scene validated by awesomeapischema.
Please follow their documentation for build validation.There are things strictly important to remember:Response serializationIf response_model is equal to the handler return annotation Squall expects exactly these types and will not perform mutations to dataclasses, etc.
Type checking will be done during serialization.Handy to save some resources working with ORM. For instanceSQL Alchemy dataclass mappingfromtypingimportList,OptionalfromdataclassesimportdataclassfromsquallimportSquallapp=Squall()@dataclassclassItem:name:strvalue:Optional[int]=None@app.get("/get",response_model=List[Item])asyncdefhandle_get()->List[Item]:return[Item(name="null_value"),Item(name="int_value",value=8)]Response deserialization-serializationThe following example demonstrates a different scenario. Where response expects to receive from handler Python primitives and Sequences/Maps only.
With this scenario, all response data will be processed through the filling of the relevant model.fromtypingimportList,OptionalfromdataclassesimportdataclassfromsquallimportSquallapp=Squall()@dataclassclassItem:name:strvalue:Optional[int]=None@app.get("/get",response_model=List[Item])asyncdefhandle_get():return[{"name":"null_value"},{"name":"int_value","value":8}]OpenTelemetry usageTo trace internal actions next packages must be installed:pip install opentelemetry-api opentelemetry-sdkHaving installed libs initial application and OpenTelemetry configuration should be performed as shown bellow:fromopentelemetryimporttracefromopentelemetry.sdk.traceimportTracerProviderfromopentelemetry.sdk.trace.exportimport(BatchSpanProcessor,ConsoleSpanExporter,)fromsquallimportSqualltrace.set_tracer_provider(TracerProvider())trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))app=Squall(trace_internals=True)@app.get("/get")asyncdefhandle_get()->dict:return{"Hello":"World"}For detailed config have a look atOpentelemetry docsAcknowledgmentsMany thanks to@tiangoloand the entireFastAPI community. Squall development started from hard-forking this superior developers-friendly framework.Roadmap0.1.x- Initial project publication0.2.x- Intel®ISA-Lbased compression0.3.x- Observability based onOpenTelemetrywith switchable Squall internals tracing.0.4.x-Dependency Injectorintegration0.5.x-YARLandaio-MultiDictintegration0.6.x- Fine-tuning for__slots__, LEGB, attribute access.0.7.x- MTAG integration0.8.x- Starts new SGI initiativeDependenciesisalLicense: MITFaster zlib and gzip compatible compression and decompression by providing python bindings for the ISA-L library.apischemaLicense: MITJSON (de)serialization, GraphQL and JSON schema generation using Python typing.apischema makes your life easier when dealing with API data.orjsonLicense: MIT or Apache 2.0orjson is a fast, correct JSON library for Python. It benchmarks as the fastest Python library for JSON and is more correct than the standard json library or other third-party libraries. It serializes dataclass, datetime, numpy, and UUID instances natively.StarletteLicense: BSD 3Starlette is a lightweight ASGI framework/toolkit, which is ideal for building high performance async services.VersioningSquall follows the next versioning contract:AA.BB.CCAA- Major changes, backward compatibility breaksBB- Minor changes, new featuresCC- Patch, bug fixesLicenseMIT