The Serve class embeds DIZEST workflows in a Flask web server and provides them as REST APIs.
from dizest import Serve
serve = Serve(**config)Creates a Serve object and initializes the Flask app.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
cwd |
str |
✗ | os.getcwd() |
Workflow working directory |
max_log_size |
int |
✗ | 50 |
Maximum number of log entries |
host |
str |
✗ | 127.0.0.1 |
Web server host address |
port |
int |
✗ | 8000 |
Web server port |
# Default configuration
serve = Serve()
# Custom configuration
serve = Serve(
host='0.0.0.0',
port=5000,
cwd='/path/to/workdir',
max_log_size=100
)Server configuration object.
Type: Config
Properties:
cwd: Working directorymax_log_size: Maximum log sizehost: Server hostport: Server port
Internal workflow object.
Type: Workflow
Flask app instance.
Type: flask.Flask
Flask module reference.
Type: module
Starts the web server (blocking).
serve = Serve(host='0.0.0.0', port=8000)
serve.run() # Start server (exit with Ctrl+C)Registers a workflow event listener.
| Parameter | Type | Description |
|---|---|---|
name |
str |
Event name |
fn |
callable |
Event handler function |
workflow.status: Workflow status changeflow.status: Flow status changeflow.index: Flow execution orderlog.append: Log appendedlog.clear: Log clearedresult: Result output
serve = Serve()
def on_log(flow_id, event_name, log_message):
print(f"[{flow_id}] {log_message}")
serve.on('log.append', on_log)
serve.run()Gets query parameters from the current request.
| Parameter | Type | Description |
|---|---|---|
key |
str or None |
Parameter name to query (or None for all) |
default |
any |
Default value |
key=None: Dictionary of all query parameterskeyspecified: Value of that parameter (ordefaultif not found)
from dizest import Serve
serve = Serve()
@serve.app.route('/api/test')
def test():
# All parameters
all_params = serve.query()
# Specific parameters
message = serve.query('message', default='Hello')
count = serve.query('count', default=0)
return {'message': message, 'count': count}
serve.run()The Serve class automatically binds the following REST API endpoints:
Endpoint: GET /health
Checks server status.
Response:
{
"code": 200
}Example:
curl http://localhost:8000/healthEndpoint: POST /workflow/update
Updates the workflow.
Parameters:
package(JSON string): Workflow package
Response:
{
"code": 200,
"data": { /* sync data */ }
}Example:
curl -X POST http://localhost:8000/workflow/update \
-d 'package={"apps":{...},"flow":{...}}'Endpoint: GET /workflow/status
Gets the workflow execution status.
Response:
{
"code": 200,
"status": "idle"
}Example:
curl http://localhost:8000/workflow/statusEndpoint: POST /workflow/run
Executes the workflow.
Response:
{
"code": 200,
"status": "start"
}Example:
curl -X POST http://localhost:8000/workflow/runEndpoint: POST /workflow/stop
Stops the running workflow.
Response:
{
"code": 200
}Example:
curl -X POST http://localhost:8000/workflow/stopEndpoint: GET /flow/status/<flow_id>
Gets the status of a specific Flow.
Response:
{
"code": 200,
"status": "idle",
"index": -1,
"log": []
}Example:
curl http://localhost:8000/flow/status/my_flow-1234567890Endpoint: POST /flow/run/<flow_id>
Executes a specific Flow.
Parameters: Pass inputs as URL query parameters
Response:
{
"code": 200,
"status": "start"
}Example:
curl -X POST "http://localhost:8000/flow/run/my_flow-1234567890?param1=value1¶m2=value2"from dizest import Serve
serve = Serve()
@serve.app.route('/custom/api')
def custom_api():
# Get query parameters
message = serve.query('message', default='Hello')
# Load and execute workflow
workflow = serve.workflow
workflow.load('myworkflow.dwp')
workflow.run()
# Return results
return {'status': 'success', 'message': message}
serve.run()from dizest.base.binding import BaseBinding
class CustomBinding(BaseBinding):
NAMESPACE = "custom"
def hello(self):
name = self.serve.query('name', default='World')
return {'code': 200, 'message': f'Hello, {name}!'}
def process(self):
data = self.serve.query('data')
# Data processing logic
result = process_data(data)
return {'code': 200, 'result': result}
# Extend Serve class
from dizest import Serve
class MyServe(Serve):
def bind(self):
super().bind()
CustomBinding(self).bind()
serve = MyServe()
serve.run()Now you can use these endpoints:
GET /custom/hello?name=JohnPOST /custom/process?data=...
from dizest import Serve
# Create server
serve = Serve(host='0.0.0.0', port=8000)
# Event listener
def on_log(flow_id, event, value):
print(f"[{flow_id}] {value}")
serve.on('log.append', on_log)
# Run server
serve.run()from dizest import Serve
import dizest
serve = Serve(host='0.0.0.0', port=5000)
@serve.app.route('/api/run/<workflow_name>')
def run_workflow(workflow_name):
# Load workflow
workflow_path = f'/workflows/{workflow_name}.dwp'
workflow = dizest.Workflow(workflow_path)
# Collect parameters
params = serve.query()
# Execute
workflow.run(**params)
# Collect results
requested, outputs = workflow.spec()
result = {}
for flow_id in outputs:
flow = workflow.flow(flow_id)
instance = workflow.run.instance(flow)
for output_name in outputs[flow_id]:
result[output_name] = instance.output_data.get(output_name)
return {'status': 'success', 'result': result}
serve.run()from dizest import Serve
from functools import wraps
serve = Serve()
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
token = serve.query('token')
if token != 'secret-token':
return {'code': 401, 'error': 'Unauthorized'}, 401
return f(*args, **kwargs)
return decorated
@serve.app.route('/api/secure')
@require_auth
def secure_api():
return {'code': 200, 'data': 'Secure data'}
serve.run()# app.py
from dizest import Serve
serve = Serve()
# uWSGI app object
app = serve.app
if __name__ == '__main__':
serve.run()uWSGI Configuration (uwsgi.ini):
[uwsgi]
module = app:app
master = true
processes = 4
threads = 2
socket = 0.0.0.0:8000
chmod-socket = 660
vacuum = true
die-on-term = trueRun:
uwsgi --ini uwsgi.ini# app.py
from dizest import Serve
serve = Serve()
app = serve.appRun:
gunicorn -w 4 -b 0.0.0.0:8000 app:appFROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]The Serve class automatically handles all exceptions and returns them as JSON responses:
@serve.app.errorhandler(Exception)
def handle_exception(e):
return {"code": 500, "data": str(e)}You can add custom error handlers:
@serve.app.errorhandler(404)
def not_found(e):
return {"code": 404, "error": "Not Found"}, 404
@serve.app.errorhandler(ValueError)
def value_error(e):
return {"code": 400, "error": str(e)}, 400from flask_cors import CORS
serve = Serve()
CORS(serve.app)from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
serve = Serve()
limiter = Limiter(
serve.app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@serve.app.route('/api/limited')
@limiter.limit("10 per minute")
def limited():
return {'status': 'ok'}