SIO-AsyncAPI
SIO-AsyncAPI is a Python library built on the top of Flask-SocketIO and driven by AsyncAPI. It allows you to generate an AsyncAPI specification from your SocketIO server and validate messages against it.
Similar to FastAPI, SIO-AsyncAPI allows you to define your SocketIO server using Python type annotations and Pydantic models. It also provides a way to generate an AsyncAPI specification from your SocketIO server.
SIO-AsyncAPI now supports both Pydantic 1.10+ and 2.x, emits AsyncAPI 3.1, and keeps Socket.IO ACKs in the custom x-ack extension.
Installation
pip install sio_asyncapi
Basic Example
# examples/simple.py
from flask import Flask
from sio_asyncapi import AsyncAPISocketIO, ResponseValidationError, RequestValidationError
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
import logging
logger = logging.getLogger(__name__)
app = Flask(__name__)
socketio = AsyncAPISocketIO(
app,
validate=True,
generate_docs=True,
version="1.0.0",
title="Demo",
description="Demo Server",
server_url="http://localhost:5000",
server_name="DEMO_SIO",
)
class UserSignUpRequest(BaseModel):
"""Request model for user sign up"""
email: EmailStr = Field(..., description="User email", example="bob@gmail.com")
password: str = Field(..., description="User password", example="123456")
class UserSignUpResponse(BaseModel):
"""Response model for user sign up"""
success: bool = Field(True, description="Success status")
error: Optional[str] = Field( None, description="Error message if any",
example="Invalid request")
@socketio.on("user_sign_up", get_from_typehint=True)
def user_sign_up(request: UserSignUpRequest) -> UserSignUpResponse:
"""User sign up"""
_ = request
return UserSignUpResponse(success=True, error=None)
@socketio.on_error_default
def default_error_handler(e: Exception):
"""
Default error handler. It called if no other error handler defined.
Handles RequestValidationError and ResponseValidationError errors.
"""
if isinstance(e, RequestValidationError):
logger.error(f"Request validation error: {e}")
return {"success": False, "error": str(e)}
elif isinstance(e, ResponseValidationError):
logger.critical(f"Response validation error: {e}")
raise e
else:
logger.critical(f"Unknown error: {e}")
raise e
if __name__ == '__main__':
socketio.run(app, debug=True)
# import pathlib
# if __name__ == "__main__":
# path = pathlib.Path(__file__).parent / "simple.yml"
# doc_str = socketio.asyncapi_doc.get_yaml()
# with open(path, "w") as f:
# f.write(doc_str)
# print(doc_str)
Here is how validation error looks like in FireCamp:
In order to get the AsyncAPI specification from your SocketIO server instead of running the server, you can do the following:
You can also get a compact agent-friendly event catalog with socketio.get_agent_schema() or socketio.get_agent_schema_json().
See examples/agentic_doc_example.py for a complete example that writes both exports to disk.
import pathlib
if __name__ == "__main__":
path = pathlib.Path(__file__).parent / "simple.yml"
doc_str = socketio.asyncapi_doc.get_yaml()
with open(path, "w") as f:
f.write(doc_str)
print(doc_str)
Example of the AsyncAPI specification generated from the above example:
# examples/simple.yml
asyncapi: 3.1.0
info:
title: Demo
version: 1.0.0
description: 'Demo Server
<br/> This specification targets AsyncAPI 3.1 and keeps Socket.IO ACK values in
the custom `x-ack` message extension.
Socket.IO-specific transport details may still require application-level interpretation.
'
servers:
DEMO_SIO:
host: localhost:5000
protocol: socketio
channels:
root:
address: /
messages:
User_Sign_Up:
$ref: '#/components/messages/User_Sign_Up'
operations:
receive_user_sign_up:
action: receive
channel:
$ref: '#/channels/root'
messages:
- $ref: '#/channels/root/messages/User_Sign_Up'
description: User sign up
components:
messages:
User_Sign_Up:
name: user_sign_up
description: User sign up
payload:
$ref: '#/components/schemas/UserSignUpRequest'
x-ack:
$ref: '#/components/schemas/UserSignUpResponse'
schemas:
NoSpec:
description: Specification is not provided
UserSignUpRequest:
title: UserSignUpRequest
description: Request model for user sign up
type: object
properties:
email:
title: Email
description: User email
example: bob@gmail.com
type: string
format: email
password:
title: Password
description: User password
example: '123456'
type: string
required:
- email
- password
UserSignUpResponse:
title: UserSignUpResponse
description: Response model for user sign up
type: object
properties:
success:
title: Success
description: Success status
default: true
type: boolean
error:
title: Error
description: Error message if any
example: Invalid request
type: string
Rendered version of the above AsyncAPI specification:
Converting from Flask-SocketIO to SIO-AsyncAPI
SIO-AsyncAPI is built on top of Flask-SocketIO and all unit tests of Flask-SocketIO are tested against SIO-AsyncAPI. If you converting your SocketIO server from Flask-SocketIO to SIO-AsyncAPI, you can be sure that your SocketIO server will work as expected. When converting your SocketIO server from Flask-SocketIO to SIO-AsyncAPI, it's as simple as changing the import statement:
# instead of `from flask_socketio import SocketIO`
from sio_asyncapi import AsyncAPISocketIO as SocketIO
...
# There are additional arguments that you can pass to the constructor of AsyncAPISocketIO
socketio = SocketIO(app)
...
Acknowledgements
Most of the implementation follows research done by Dimitrios Dedoussis (https://www.asyncapi.com/blog/socketio-part2) and uses some Pydantic models from here
Missing Features
SIO-AsyncAPI is still in its early stages and there are some features that are not yet implemented. If you are interested in contributing to SIO-AsyncAPI any contribution is welcome. Here is the list of missing features:
- Support of AsycnAPI documentation and validation for
emitmessages - Support of Flask-SocketIO
namespacesandrooms - Authentication and security auto documentation
-
connectanddisconnecthandlers auto documentation
Metadata
Release files for sio_asyncapi 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sio_asyncapi-1.0.0.tar.gz | 43.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sio_asyncapi-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 107.1 kB
Release files / sio_asyncapi-1.0.0.tar.gz
| Download URL | sio_asyncapi-1.0.0.tar.gz |
|---|---|
| Size | 43.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1c83fd9851f93b299e59abc62ff33c8f7178df6a266c0c7e8e09e5c8cd872143
|
|
BLAKE2b-256 checksum How to use checksums |
65944245d59142dcc37e7e206820c42e1adf6ff3b891e616686cfde7fa18f4ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.3 CPython/3.11.14 Linux/6.14.0-1017-azure
|
Release files / sio_asyncapi-1.0.0-py3-none-any.whl
| Download URL | sio_asyncapi-1.0.0-py3-none-any.whl |
|---|---|
| Size | 63.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f398e813c6cc755c73925ae837868c72021d81a11ea23ebbd499d109cab0adf5
|
|
BLAKE2b-256 checksum How to use checksums |
99056aeabd56dedc3cdef6104b41f71d9a7264e1e17d4b72ca4ad5f3d75b7fd1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.3 CPython/3.11.14 Linux/6.14.0-1017-azure
|