Server Modes
Server Modes
Section titled “Server Modes”Stowry supports three server modes that change how requests are handled. Choose the mode that fits your use case.
Overview
Section titled “Overview”| Mode | Use Case | Path Fallback |
|---|---|---|
store | Object storage API | None (404 if not found) |
static | Static file server | {path}/index.html |
spa | Single-page application | /index.html |
Store Mode (Default)
Section titled “Store Mode (Default)”The default mode for object storage operations.
server: mode: storeBehavior
Section titled “Behavior”GET /{path}- Returns the exact file or 404GET /- Returns JSON list of objects- Full CRUD operations (PUT, DELETE)
- No automatic fallbacks
Use Cases
Section titled “Use Cases”- Backend file storage for applications
- User upload handling
- Asset management systems
- API-driven file operations
Example
Section titled “Example”# Start in store mode./stowry serve --mode store
# Upload a filecurl -X PUT -d "content" http://localhost:5708/documents/report.pdf
# Download - returns exact filecurl http://localhost:5708/documents/report.pdf # 200 OK
# Missing file - returns 404curl http://localhost:5708/documents/missing.pdf # 404 Not Found
# List objectscurl http://localhost:5708/ # JSON responseStatic Mode
Section titled “Static Mode”Serves static files with automatic index.html resolution.
server: mode: staticBehavior
Section titled “Behavior”GET /{path}- Returns file, or tries{path}/index.htmlGET /- Returns/index.html- Suitable for static websites
- PUT and DELETE still work for content management
Fallback Logic
Section titled “Fallback Logic”- Try exact path
- If not found and path has no extension, try
{path}/index.html - Return 404 if neither exists
Use Cases
Section titled “Use Cases”- Static website hosting
- Documentation sites
- Marketing pages
- Any site with traditional URL structure
Example
Section titled “Example”Given this storage structure:
data/├── index.html├── about/│ └── index.html├── blog/│ ├── index.html│ └── post-1.html└── assets/ └── style.cssRequest handling:
GET / → data/index.htmlGET /about → data/about/index.htmlGET /about/ → data/about/index.htmlGET /blog → data/blog/index.htmlGET /blog/post-1.html → data/blog/post-1.htmlGET /assets/style.css → data/assets/style.cssGET /missing → 404 (no index.html in missing/)Configuration
Section titled “Configuration”server: mode: static port: 80
storage: path: /var/www/html
access: public_read: true public_write: falseSPA Mode
Section titled “SPA Mode”Designed for single-page applications with client-side routing.
server: mode: spaBehavior
Section titled “Behavior”GET /{path}- Returns file if exists, otherwise/index.html- Enables client-side routing (React Router, Vue Router, etc.)
- PUT and DELETE still work for content management
Fallback Logic
Section titled “Fallback Logic”- Try exact path
- If not found, return
/index.html - Client-side JavaScript handles routing
Use Cases
Section titled “Use Cases”- React applications
- Vue.js applications
- Angular applications
- Any SPA with client-side routing
Example
Section titled “Example”Given this storage structure:
dist/├── index.html├── assets/│ ├── main.js│ └── style.css└── favicon.icoRequest handling:
GET / → dist/index.htmlGET /dashboard → dist/index.html (SPA handles route)GET /users/123 → dist/index.html (SPA handles route)GET /assets/main.js → dist/assets/main.jsGET /favicon.ico → dist/favicon.icoConfiguration
Section titled “Configuration”server: mode: spa port: 3000
storage: path: ./dist
access: public_read: true public_write: falseClient-Side Router Setup
Section titled “Client-Side Router Setup”Ensure your SPA handles the current URL on load:
React Router:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home />} /> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/users/:id" element={<UserProfile />} /> </Routes> </BrowserRouter> );}Vue Router:
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', component: Home }, { path: '/dashboard', component: Dashboard }, { path: '/users/:id', component: UserProfile }, ],});Comparing Modes
Section titled “Comparing Modes”GET Request Behavior
Section titled “GET Request Behavior”| Request | Store | Static | SPA |
|---|---|---|---|
GET / | List objects (JSON) | /index.html | /index.html |
GET /about | Exact file or 404 | /about/index.html | /index.html |
GET /file.txt | Exact file or 404 | Exact file or 404 | Exact file or 404 |
GET /missing | 404 | 404 | /index.html |
When to Use Each
Section titled “When to Use Each”Use Store when:
- Building an API-driven application
- You need full control over responses
- Implementing custom 404 handling on the client
- File paths are dynamic/generated
Use Static when:
- Hosting a traditional static website
- Each URL corresponds to a specific page
- You want automatic directory index resolution
- SEO is important (each route has its own file)
Use SPA when:
- Building a single-page application
- Using client-side routing
- All routes should load the same entry point
- Deep linking should work for all routes
Switching Modes
Section titled “Switching Modes”You can change modes without modifying your stored files:
# Development with SPA mode./stowry serve --mode spa
# Production static hosting./stowry serve --mode static
# API mode for backend./stowry serve --mode storeOr via configuration:
server: mode: ${STOWRY_MODE:-store} # Default to store, override with env var