- Rust 96.4%
- Shell 2.8%
- HTML 0.8%
| .cargo | ||
| .forgejo/workflows | ||
| build | ||
| scripts | ||
| src | ||
| static | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| config.example.json | ||
| config_test.json | ||
| Cross.toml | ||
| LICENSE | ||
| README.md | ||
Home IoT Backend (rest_api_server)
This crate is the HTTP API backend for the Home IoT project. It exposes REST endpoints for:
- User management (registration, update, deletion, authentication),
- Sensor management (listing, pagination, filtering),
- Authentication using JWT tokens stored in HTTP-only cookies,
- OpenAPI documentation and Swagger UI,
- TypeScript client generation scripts based on the OpenAPI spec.
The backend relies on a separate crate, db_handler, for all database access and data models.
1. Architecture overview
-
Crates
rest_api_server(this crate): HTTP API, routing, auth, OpenAPI.db_handler: primary/history databases, repositories, models, shared error types.
-
Main modules
src/lib.rsrun_server(...): builds the Axum router, mounts routes, configures CORS, compression, Swagger UI.generate_openapi(): combines OpenAPI fragments fromuser,sensor, andauthmodules.
src/main.rs- Binary entry point (
rest_api_server), - Loads configuration from
CONFIG_FILE, - Initializes database connections via
db_handler::db::connection::Connection, - Starts the HTTP server on
0.0.0.0:2606.
- Binary entry point (
src/auth/*- JWT token generation & verification (
handlers::token), - Login / logout / refresh handlers, cookie management,
- Swagger/OpenAPI security scheme declaration (cookie-based auth).
- JWT token generation & verification (
src/user/*,src/sensor/*- REST handlers over
db_handlerservices, - Pagination, validation, error handling.
- REST handlers over
src/tools/*error.rs: centralized application error type (AppError),state.rs: sharedAppState(database connection + optional restart channel),config.rs,responses.rs: configuration and response helper types.
src/bin/generate-openapi.rs- Standalone binary to export the OpenAPI spec into a JSON file.
2. Requirements
-
Rust toolchain: Rust stable with Cargo.
-
Databases
- Primary database: SQLite (handled by
db_handlerwithsqlx). - Time-series / history: InfluxDB 2.x (also configured in
db_handler).
- Primary database: SQLite (handled by
-
Configuration file
- A JSON configuration file is required; its path is provided via the
CONFIG_FILEenvironment variable (see below).
- A JSON configuration file is required; its path is provided via the
-
Registries
-
The
db_handlercrate is fetched from a custom Cargo registry namedforgejo, configured in.cargo/config.toml:[registries.forgejo] index = "sparse+https://code.bhk-itsolutions.com/api/packages/homeiot/cargo/"You must ensure that this registry is reachable from your environment (it is public for this project).
-
3. Configuration
3.1 Application configuration file (CONFIG_FILE)
The backend expects the CONFIG_FILE environment variable to point to a JSON file. A typical pattern:
export CONFIG_FILE=/path/to/config.json
The JSON is deserialized into tools::config::Config. At minimum it should contain:
- Primary database URL (e.g. SQLite path or in-memory DB),
- Static assets folder used to serve the frontend (used by
run_server), - Any additional fields required by
db_handler(for example, history DB URL).
Recommendation: add a
config.example.json(not provided here by default) with:
- a non-production SQLite URL (e.g.
":memory:"),- a placeholder path for
static_folder,- dummy values for any additional fields.
3.2 Secret key (SECRET_KEY)
JWT tokens use a shared secret stored in the SECRET_KEY environment variable:
export SECRET_KEY="CHANGE_ME_TO_A_32_CHARS_MINIMUM_SECRET_KEY"
Constraints:
SECRET_KEYmust be set,- It must be at least 32 characters long,
- It is used for both token encoding and decoding (HS256).
4. Running the server
- Ensure
db_handleris available and the databases are reachable:- Primary SQLite DB (and migrations will be applied by
db_handler), - InfluxDB 2.x if you use history features.
- Primary SQLite DB (and migrations will be applied by
- Prepare your configuration file and export
CONFIG_FILEandSECRET_KEY:
export CONFIG_FILE=/path/to/config.json
export SECRET_KEY="CHANGE_ME_TO_A_32_CHARS_MINIMUM_SECRET_KEY"
- Run the server:
cargo run --bin rest_api_server
The server will bind to 0.0.0.0:2606 and log basic information via tracing.
Alternatively, you can use the helper script:
./scripts/run.sh
Note: adjust
scripts/run.shto export the correctCONFIG_FILEandSECRET_KEYvalues for your environment.
5. OpenAPI & Swagger UI
5.1 Generating OpenAPI JSON
Use the dedicated binary:
cargo run --bin generate-openapi -- openapi.json
or the convenience script (using the running server):
./scripts/download-openapi.sh
This will:
- Build the OpenAPI document from the code (binary),
or download it from the running server (
/api-doc/openapi.json), - Write it to
scripts/openapi.json(or another path, depending on the script).
5.2 Swagger UI in the running server
When the server is running, Swagger UI is served at:
GET /docs– Swagger UI frontend,GET /api-doc/openapi.json– OpenAPI JSON served by the backend.
Authentication is configured via the CookieAuth security scheme using HTTP-only cookies (auth_token).
6. TypeScript client generation
The scripts/ directory contains utilities to generate a TypeScript client from the OpenAPI spec:
scripts/openapi.json– a checked-in OpenAPI JSON snapshot (can be regenerated).scripts/generate-ts-client-from-file.sh– generates a TS client from a local OpenAPI JSON file.
Typical flow:
cd scripts
# Option 1: generate OpenAPI from code (binary) and copy it here
cargo run --bin generate-openapi -- openapi.json
# Option 2: or download from a running server
./download-openapi.sh http://localhost:2606/api-doc/openapi.json openapi.json
# Then generate the TS client
./generate-ts-client-from-file.sh openapi.json ../frontend/src/api
The TS client will be generated in the path configured inside the script (for example, the frontend project).
For more details about using the generated client in Vue 3, see the documentation referenced in
scripts/README.md.
7. Scripts overview
From the backend/ directory:
-
scripts/tests.sh- Exports
CONFIG_FILE(pointing to a test configuration file), - Exports a
SECRET_KEYvalue (should be dummy for public use), - Runs
cargo test -- --test-threads=1 --nocapture.
- Exports
-
scripts/run.sh- Helper to run the API server (you can customize environment variables here).
-
scripts/build.sh- Helper to build the API server in release mode.
-
scripts/deploy.sh- Placeholder for your deployment logic (currently minimal; adapt to your environment).
-
scripts/download-openapi.sh- Downloads OpenAPI JSON from a running backend and saves it under
scripts/openapi.json.
- Downloads OpenAPI JSON from a running backend and saves it under
-
scripts/generate-ts-client-from-file.sh- Consumes a local OpenAPI JSON file and generates a TypeScript client.
Security note: do not commit real secrets (keys, passwords, tokens) into these scripts. Use dummy values or rely on CI/CD environment variables.
8. Tests
8.1 Rust tests
The project includes:
- Unit tests for handlers in
src/**/tests.rs, - Integration tests in
tests/general/*.rsandtests/users/*.rs.
To run all tests from the backend directory:
./scripts/tests.sh
This script:
- Exports a
CONFIG_FILEpointing to a test configuration file, - Ensures
SECRET_KEYis set for JWT tests, - Runs
cargo testwith a single test thread and--nocaptureto show output.
8.2 Integration tests behaviour
Integration tests:
- Start an Axum HTTP server on a random local port,
- Use
reqwestclients (with or without cookie jar) to:- Register a user,
- Log in and verify HTTP-only cookies,
- Call authenticated routes (e.g. updating and reading users),
- Verify error codes (401, 404, 400, etc.).
9. Error handling
- All API-level errors use the
AppErrortype (src/tools/error.rs), which:- Logs errors via
tracing, - Maps them to appropriate HTTP status codes,
- Returns generic or user-friendly messages to clients.
- Logs errors via
- Database-layer errors are encapsulated in
db_handler(e.g.CommonError), and then converted intoAppErroras needed.
10. Notes on publishing
Before publishing this crate in a public Git repository, you should:
- Ensure there are no real secrets:
- No real
SECRET_KEYinscripts/tests.shor any config file, - No
.env,config.json, or other sensitive files tracked by Git.
- No real
- Decide how to distribute
db_handler:- Either include it in the same repository,
- Or publish it separately and reference it via
gitURL or crates.io (if you ever choose to).
- Optionally add:
config.example.json,.env.example,- A
README.DOCKER.mdif you add Docker-based workflows.