473 lines
8.3 KiB
Markdown
473 lines
8.3 KiB
Markdown
|
|
# TypeDialog Web Backend
|
||
|
|
|
||
|
|
HTTP server with browser-based forms powered by [Axum](https://github.com/tokio-rs/axum).
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The Web backend (`typedialog-web`) provides a full-featured HTTP server with browser-based forms. Built with Axum for high performance, supporting REST APIs, WebSockets, and modern web interfaces.
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
- **HTTP Server**: Fast async server with Axum
|
||
|
|
- **Browser Forms**: Responsive HTML forms with JavaScript
|
||
|
|
- **REST API**: JSON endpoints for form submission
|
||
|
|
- **Real-time Validation**: Client-side and server-side validation
|
||
|
|
- **RepeatingGroups**: Inline expandable cards with live counter
|
||
|
|
- **Mobile-Friendly**: Responsive design for all screen sizes
|
||
|
|
- **HTTPS Support**: TLS/SSL for production
|
||
|
|
- **Session Management**: Stateful forms with session persistence
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
### Installation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cargo build --release -p typedialog-web
|
||
|
|
sudo cp target/release/typedialog-web /usr/local/bin/
|
||
|
|
|
||
|
|
# Or use just
|
||
|
|
just build::web
|
||
|
|
```
|
||
|
|
|
||
|
|
### Basic Usage
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Start server (default: http://localhost:3000)
|
||
|
|
typedialog-web --config examples/form.toml
|
||
|
|
|
||
|
|
# Custom port
|
||
|
|
typedialog-web --config form.toml --port 8080
|
||
|
|
|
||
|
|
# With HTTPS
|
||
|
|
typedialog-web --config form.toml --tls-cert cert.pem --tls-key key.pem
|
||
|
|
|
||
|
|
# From config file
|
||
|
|
typedialog-web --config config/web/production.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
## Server Endpoints
|
||
|
|
|
||
|
|
### Form Endpoints
|
||
|
|
|
||
|
|
| Method | Path | Description |
|
||
|
|
| -------- | ------ | ------------- |
|
||
|
|
| `GET` | `/` | Render form HTML |
|
||
|
|
| `POST` | `/submit` | Submit form data |
|
||
|
|
| `GET` | `/api/form` | Get form definition (JSON) |
|
||
|
|
| `POST` | `/api/validate` | Validate field |
|
||
|
|
| `GET` | `/health` | Health check |
|
||
|
|
|
||
|
|
### Static Assets
|
||
|
|
|
||
|
|
| Path | Description |
|
||
|
|
| ------ | ------------- |
|
||
|
|
| `/static/css/form.css` | Form styles |
|
||
|
|
| `/static/js/form.js` | Form logic |
|
||
|
|
| `/static/js/repeating-group.js` | RepeatingGroup handler |
|
||
|
|
|
||
|
|
## Configuration
|
||
|
|
|
||
|
|
### Server Config
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web]
|
||
|
|
host = "0.0.0.0"
|
||
|
|
port = 3000
|
||
|
|
tls_enabled = false
|
||
|
|
|
||
|
|
[web.cors]
|
||
|
|
allow_origin = "*"
|
||
|
|
allow_methods = ["GET", "POST"]
|
||
|
|
allow_headers = ["Content-Type"]
|
||
|
|
|
||
|
|
[web.session]
|
||
|
|
secret_key = "change-me-in-production"
|
||
|
|
timeout_seconds = 3600
|
||
|
|
```
|
||
|
|
|
||
|
|
### TLS/HTTPS Config
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web.tls]
|
||
|
|
enabled = true
|
||
|
|
cert_path = "/path/to/cert.pem"
|
||
|
|
key_path = "/path/to/key.pem"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Form Config
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[form]
|
||
|
|
title = "Registration Form"
|
||
|
|
description = "User registration"
|
||
|
|
submit_text = "Register"
|
||
|
|
cancel_text = "Cancel"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "email"
|
||
|
|
field_type = "Text"
|
||
|
|
label = "Email"
|
||
|
|
validation = "email"
|
||
|
|
required = true
|
||
|
|
```
|
||
|
|
|
||
|
|
## API Usage
|
||
|
|
|
||
|
|
### Get Form Definition
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl http://localhost:3000/api/form
|
||
|
|
```
|
||
|
|
|
||
|
|
Response:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"form": {
|
||
|
|
"title": "Registration",
|
||
|
|
"fields": [...]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Submit Form
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -X POST http://localhost:3000/submit \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"name":"John","email":"john@example.com"}'
|
||
|
|
```
|
||
|
|
|
||
|
|
Response:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "success",
|
||
|
|
"data": {
|
||
|
|
"name": "John",
|
||
|
|
"email": "john@example.com"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Validate Field
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -X POST http://localhost:3000/api/validate \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"field":"email","value":"invalid"}'
|
||
|
|
```
|
||
|
|
|
||
|
|
Response:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"valid": false,
|
||
|
|
"error": "Invalid email format"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Frontend Features
|
||
|
|
|
||
|
|
### JavaScript API
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Form submission
|
||
|
|
document.getElementById('form').addEventListener('submit', async (e) => {
|
||
|
|
e.preventDefault();
|
||
|
|
const formData = new FormData(e.target);
|
||
|
|
const data = Object.fromEntries(formData);
|
||
|
|
|
||
|
|
const response = await fetch('/submit', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify(data)
|
||
|
|
});
|
||
|
|
|
||
|
|
const result = await response.json();
|
||
|
|
console.log('Submitted:', result);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Real-time validation
|
||
|
|
input.addEventListener('blur', async () => {
|
||
|
|
const response = await fetch('/api/validate', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({
|
||
|
|
field: input.name,
|
||
|
|
value: input.value
|
||
|
|
})
|
||
|
|
});
|
||
|
|
|
||
|
|
const result = await response.json();
|
||
|
|
if (!result.valid) {
|
||
|
|
showError(result.error);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
### RepeatingGroups
|
||
|
|
|
||
|
|
The web backend renders RepeatingGroups as inline expandable cards:
|
||
|
|
|
||
|
|
```html
|
||
|
|
<div class="repeating-group" data-min-items="1" data-max-items="10">
|
||
|
|
<div class="items-counter">Items: 0/10</div>
|
||
|
|
<div class="items-container">
|
||
|
|
<!-- Item cards here -->
|
||
|
|
</div>
|
||
|
|
<button class="add-item-btn">Add Item</button>
|
||
|
|
</div>
|
||
|
|
```
|
||
|
|
|
||
|
|
Features:
|
||
|
|
|
||
|
|
- Click "Add Item" to create new items
|
||
|
|
- Expand/collapse cards
|
||
|
|
- Delete items
|
||
|
|
- Live counter updates
|
||
|
|
- Min/max validation
|
||
|
|
- Duplicate detection (when `unique = true`)
|
||
|
|
|
||
|
|
### Styling
|
||
|
|
|
||
|
|
Custom CSS for forms:
|
||
|
|
|
||
|
|
```css
|
||
|
|
.form-container {
|
||
|
|
max-width: 600px;
|
||
|
|
margin: 0 auto;
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.field-group {
|
||
|
|
margin-bottom: 1.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.field-label {
|
||
|
|
font-weight: 600;
|
||
|
|
margin-bottom: 0.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.field-input {
|
||
|
|
width: 100%;
|
||
|
|
padding: 0.5rem;
|
||
|
|
border: 1px solid #ccc;
|
||
|
|
border-radius: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.field-error {
|
||
|
|
color: red;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
margin-top: 0.25rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.submit-btn {
|
||
|
|
background: #007bff;
|
||
|
|
color: white;
|
||
|
|
padding: 0.75rem 1.5rem;
|
||
|
|
border: none;
|
||
|
|
border-radius: 4px;
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Deployment
|
||
|
|
|
||
|
|
### Development
|
||
|
|
|
||
|
|
```bash
|
||
|
|
typedialog-web --config config/web/dev.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Production
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# With systemd
|
||
|
|
sudo systemctl start typedialog-web
|
||
|
|
|
||
|
|
# Or directly
|
||
|
|
typedialog-web \
|
||
|
|
--config config/web/production.toml \
|
||
|
|
--tls-cert /etc/ssl/cert.pem \
|
||
|
|
--tls-key /etc/ssl/key.pem \
|
||
|
|
--port 443
|
||
|
|
```
|
||
|
|
|
||
|
|
### Docker
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Build image
|
||
|
|
docker build -t typedialog-web .
|
||
|
|
|
||
|
|
# Run container
|
||
|
|
docker run -p 3000:3000 \
|
||
|
|
-v $(pwd)/config:/config \
|
||
|
|
typedialog-web --config /config/web/production.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Reverse Proxy (Nginx)
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
server {
|
||
|
|
listen 80;
|
||
|
|
server_name example.com;
|
||
|
|
|
||
|
|
location / {
|
||
|
|
proxy_pass http://localhost:3000;
|
||
|
|
proxy_set_header Host $host;
|
||
|
|
proxy_set_header X-Real-IP $remote_addr;
|
||
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Use Cases
|
||
|
|
|
||
|
|
### 1. SaaS Applications
|
||
|
|
|
||
|
|
Customer onboarding forms with validation:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
typedialog-web --config saas/onboarding.toml --port 443 --tls
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Internal Tools
|
||
|
|
|
||
|
|
Admin panels and configuration interfaces:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
typedialog-web --config admin/settings.toml --host 0.0.0.0
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Public Forms
|
||
|
|
|
||
|
|
Contact forms, surveys, registrations:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
typedialog-web --config public/contact.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. API Integration
|
||
|
|
|
||
|
|
Headless forms with JSON API:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl http://localhost:3000/api/form | jq .
|
||
|
|
```
|
||
|
|
|
||
|
|
## Security
|
||
|
|
|
||
|
|
### HTTPS
|
||
|
|
|
||
|
|
Always use HTTPS in production:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web.tls]
|
||
|
|
enabled = true
|
||
|
|
cert_path = "/etc/ssl/cert.pem"
|
||
|
|
key_path = "/etc/ssl/key.pem"
|
||
|
|
```
|
||
|
|
|
||
|
|
### CORS
|
||
|
|
|
||
|
|
Configure CORS for cross-origin requests:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web.cors]
|
||
|
|
allow_origin = "https://example.com"
|
||
|
|
allow_methods = ["GET", "POST"]
|
||
|
|
allow_headers = ["Content-Type", "Authorization"]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Session Security
|
||
|
|
|
||
|
|
Use strong session secrets:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web.session]
|
||
|
|
secret_key = "generate-random-32-byte-key"
|
||
|
|
timeout_seconds = 1800 # 30 minutes
|
||
|
|
secure_cookies = true
|
||
|
|
http_only = true
|
||
|
|
```
|
||
|
|
|
||
|
|
### Input Validation
|
||
|
|
|
||
|
|
Always validate on server-side:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[[fields]]
|
||
|
|
name = "email"
|
||
|
|
validation = "email"
|
||
|
|
required = true
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "age"
|
||
|
|
validation = "range(18..120)"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
See [examples/04-backends/web/](../../examples/04-backends/web/) for:
|
||
|
|
|
||
|
|
- Basic forms
|
||
|
|
- REST API integration
|
||
|
|
- RepeatingGroups
|
||
|
|
- Custom styling
|
||
|
|
- HTTPS configuration
|
||
|
|
- Multi-page forms
|
||
|
|
|
||
|
|
## Related Documentation
|
||
|
|
|
||
|
|
- [Installation](../installation.md) - Setup guide
|
||
|
|
- [Configuration](../configuration.md) - Web configuration options
|
||
|
|
- [Field Types](../field_types.md) - Available field types
|
||
|
|
- [Encryption](../encryption/) - Secure field handling
|
||
|
|
- [Examples](../../examples/04-backends/web/) - Working examples
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### "Address already in use"
|
||
|
|
|
||
|
|
Port is occupied. Use different port:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
typedialog-web --config form.toml --port 8080
|
||
|
|
```
|
||
|
|
|
||
|
|
### "TLS certificate error"
|
||
|
|
|
||
|
|
Check cert paths and permissions:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
ls -l /path/to/cert.pem /path/to/key.pem
|
||
|
|
```
|
||
|
|
|
||
|
|
### "CORS error"
|
||
|
|
|
||
|
|
Configure CORS in config:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web.cors]
|
||
|
|
allow_origin = "http://localhost:3000"
|
||
|
|
```
|
||
|
|
|
||
|
|
### "Form not submitting"
|
||
|
|
|
||
|
|
Check JavaScript console for errors. Ensure `/submit` endpoint is reachable.
|
||
|
|
|
||
|
|
### "Session expired"
|
||
|
|
|
||
|
|
Increase session timeout:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[web.session]
|
||
|
|
timeout_seconds = 7200 # 2 hours
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Ready to start?** See [examples/04-backends/web/](../../examples/04-backends/web/)
|