Migrating from Baseweb 0.x to 1.0.0
Baseweb 1.0.0 represents a major architecture change: migration from Flask to Quart for async support.
Breaking Changes
Python Version
Baseweb 1.0.0 requires Python 3.11 or higher for async/await support.
Flask → Quart
All route handlers must now be async functions.
Before (0.x):
from baseweb import Baseweb
app = Baseweb("myapp")
@app.route("/api/data")
def get_data():
return {"data": "value"}
After (1.0.0):
from baseweb import Baseweb
app = Baseweb("myapp")
@app.route("/api/data")
async def get_data():
return {"data": "value"}
Template Rendering
render_template() must now be awaited.
Before:
@app.route("/page")
def page():
return render_template("page.html", title="My Page")
After:
@app.route("/page")
async def page():
return await render_template("page.html", title="My Page")
Request JSON
request.get_json() must now be awaited.
Before:
@app.route("/api/submit", methods=["POST"])
def submit():
data = request.get_json()
return {"received": data}
After:
@app.route("/api/submit", methods=["POST"])
async def submit():
data = await request.get_json()
return {"received": data}
Static File Serving
send_from_directory() must now be awaited.
Before:
from flask import send_from_directory
@app.route("/static/<path:filename>")
def serve_static(filename):
return send_from_directory("static", filename)
After:
from quart import send_from_directory
@app.route("/static/<path:filename>")
async def serve_static(filename):
return await send_from_directory("static", filename)
WebSocket
Flask-SocketIO is replaced with Quart’s native WebSocket support.
Before:
from flask_socketio import SocketIO, emit
socketio = SocketIO(app)
@socketio.on("message")
def handle_message(data):
emit("response", {"received": data})
After:
from quart import websocket
@app.websocket("/ws")
async def ws():
while True:
data = await websocket.receive()
await websocket.send_json({"received": data})
API Endpoints (Flask-RESTful Removed)
Breaking Change: Flask-RESTful has been removed from Baseweb 1.0.0. It is not compatible with Quart’s async architecture.
Option 1: Use the new Resource class (Recommended for RESTful APIs)
Baseweb 1.0.0 includes a native Resource class that provides the familiar Flask-RESTful pattern:
Before (Flask-RESTful):
from baseweb import server
from flask_restful import Resource
class MyResource(Resource):
def get(self, item_id):
return {"item": item_id}
def post(self):
data = request.get_json()
return {"created": data}, 201
server.api.add_resource(MyResource, '/api/items/<int:item_id>')
After (Baseweb Resource):
from baseweb import server, Resource
class MyResource(Resource):
async def get(self, item_id):
return {"item": item_id}
async def post(self):
data = await request.get_json()
return {"created": data}, 201
server.add_resource(MyResource, '/api/items/<int:item_id>')
Resource class features:
Familiar Flask-RESTful pattern with async support
Automatic 405 Method Not Allowed for unimplemented methods
Support for authentication:
server.add_resource(MyResource, '/api/items', security_scope='api.items')Works alongside regular routes
Option 2: Use native Quart routes (Simple APIs)
For simple APIs without resource classes:
Before:
server.api.add_resource(MyResource, '/api/my')
After:
@server.route('/api/my')
async def get_my():
data = await request.get_json()
return {"data": data}
Option 3: Use quart-schema (For validation)
For API validation with schemas:
pip install quart-schema
from baseweb import server
from quart_schema import validate_request, validate_response
from dataclasses import dataclass
@dataclass
class MyInput:
name: str
@dataclass
class MyOutput:
id: int
name: str
@server.post('/api/items')
@validate_request(MyInput)
@validate_response(MyOutput, 201)
async def create_item(data: MyInput) -> MyOutput:
return MyOutput(id=1, name=data.name)
Authentication Decorators
Custom authentication decorators must be updated to work with async handlers.
Before:
def auth_required(f):
@wraps(f)
def decorated(*args, **kwargs):
if not current_user.is_authenticated:
return {"error": "Unauthorized"}, 401
return f(*args, **kwargs)
return decorated
After:
def auth_required(f):
@wraps(f)
async def decorated(*args, **kwargs):
if not current_user.is_authenticated:
return {"error": "Unauthorized"}, 401
return await f(*args, **kwargs)
return decorated
Vue Components
Page Component (Unified)
Baseweb 1.0.0 unifies the Page, PageWithBanner, and PageWithStatus components into a single unified Page component with configurable props and slots.
Breaking Change: PageWithBanner and PageWithStatus components have been removed. Use the unified Page component instead.
Before (0.x):
<!-- Basic page -->
<Page>
<v-container>Content</v-container>
</Page>
<!-- Page with banner -->
<PageWithBanner>
<v-container>Content</v-container>
</PageWithBanner>
<!-- Page with status notifications -->
<PageWithStatus>
<v-container>Content</v-container>
</PageWithStatus>
After (1.0.0):
<!-- Basic page (unchanged) -->
<Page>
<v-container>Content</v-container>
</Page>
<!-- Page with banner -->
<Page banner>
<v-container>Content</v-container>
</Page>
<!-- Page with status notifications -->
<Page status>
<v-container>Content</v-container>
</Page>
<!-- Page with both banner and status -->
<Page banner status>
<v-container>Content</v-container>
</Page>
Store Mutations:
// Banner control
store.commit('page/banner', { alert: true, type: 'success', message: 'Hello!' });
// Status notifications
store.commit('page/success', 'Operation completed!');
store.commit('page/error', 'Something went wrong!');
store.commit('page/warning', 'Be careful!');
store.commit('page/info', 'For your information...');
Full-Page Layout (New Feature):
<Page full-page>
<template #header>
<v-toolbar>
<v-toolbar-title>Dashboard</v-toolbar-title>
</v-toolbar>
</template>
<v-container>Scrollable content here</v-container>
<template #footer>
<v-toolbar>
<v-btn>Save</v-btn>
</v-toolbar>
</template>
</Page>
Migration Steps for Components
Page - No changes required (backward compatible)
PageWithBanner - Replace with
<Page banner>and usestore.commit('page/banner', {...})PageWithStatus - Replace with
<Page status>and usestore.commit('page/success', 'message')
Migration Checklist
[ ] Update Python to 3.11+
[ ] Update baseweb to 1.0.0
[ ] Convert all route handlers to async functions
[ ] Add
awaitto allrender_template()calls[ ] Add
awaitto allrequest.get_json()calls[ ] Add
awaitto allsend_from_directory()calls[ ] Update WebSocket code to Quart native format
[ ] Replace
<PageWithBanner>with<Page banner>[ ] Replace
<PageWithStatus>with<Page status>[ ] Update store mutations: use
page/bannerandpage/success(namespaced)[ ] Run tests and verify all functionality
Estimated Migration Time
For a typical Baseweb application: less than 1 hour.