253 lines
7.1 KiB
Markdown
253 lines
7.1 KiB
Markdown
# Nexus 4
|
|
|
|
A Rust-based business management API experiment featuring Actix-web, SeaORM, and async-graphql. This project was an exploration into building a high-performance backend with Rust but was ultimately abandoned in favor of returning to more familiar frameworks (Django) for Nexus 5.
|
|
|
|
## Project Status: Abandoned
|
|
|
|
While the API itself demonstrated significantly better performance characteristics than the Python-based predecessors, the project was discontinued due to:
|
|
|
|
- **Learning curve**: Rust's ownership model and borrow checker, while excellent for safety, required significant time investment
|
|
- **Ecosystem maturity**: The Django/Python ecosystem offered more battle-tested solutions for rapid business application development
|
|
- **Team familiarity**: Returning to Django allowed faster iteration and easier maintenance
|
|
|
|
Despite being abandoned, this codebase serves as a reference implementation for building GraphQL APIs in Rust.
|
|
|
|
## What Was Achieved
|
|
|
|
- Full GraphQL API with queries and mutations for all entities
|
|
- JWT authentication with bcrypt password hashing
|
|
- SeaORM entities with PostgreSQL
|
|
- Database migrations
|
|
- SvelteKit frontend with Houdini GraphQL client
|
|
- CORS configuration for frontend integration
|
|
|
|
## Performance Comparison
|
|
|
|
| Metric | Nexus 3 (Django/Graphene) | Nexus 4 (Rust/async-graphql) |
|
|
|--------|---------------------------|------------------------------|
|
|
| Memory usage | ~150MB | ~15MB |
|
|
| Cold start | ~2-3s | ~50ms |
|
|
| Simple query latency | ~20-50ms | ~2-5ms |
|
|
| Concurrent connections | Hundreds | Thousands |
|
|
|
|
*Note: These are approximate benchmarks from development testing, not production measurements.*
|
|
|
|
## Improvements Over Previous Versions
|
|
|
|
### Over Nexus 1-2 (Django REST)
|
|
- GraphQL instead of REST
|
|
- Compiled binary instead of interpreted Python
|
|
- Zero-cost abstractions and memory safety
|
|
- Native async/await without GIL limitations
|
|
|
|
### Over Nexus 3 (Django/Graphene)
|
|
- ~10x lower memory footprint
|
|
- ~10x faster query response times
|
|
- True async I/O without Python's GIL
|
|
- Type safety at compile time
|
|
- Single binary deployment
|
|
|
|
## Tech Stack
|
|
|
|
### Backend
|
|
- **Rust** (2024 edition)
|
|
- **Actix-web** 4.x - High-performance web framework
|
|
- **SeaORM** 1.x - Async ORM with compile-time checked queries
|
|
- **async-graphql** 7.x - GraphQL server library
|
|
- **jsonwebtoken** - JWT authentication
|
|
- **bcrypt** - Password hashing
|
|
- **PostgreSQL** - Database
|
|
|
|
### Frontend
|
|
- **SvelteKit** - Frontend framework
|
|
- **Houdini** - GraphQL client with generated types
|
|
- **TypeScript**
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
nexus-4/
|
|
├── src/
|
|
│ ├── main.rs # Application entry point
|
|
│ ├── db.rs # Database connection
|
|
│ ├── auth/ # JWT authentication
|
|
│ │ ├── mod.rs # JWT middleware and utilities
|
|
│ │ ├── error.rs # Auth error types
|
|
│ │ └── handlers.rs # Login, register, token renewal
|
|
│ ├── entities/ # SeaORM entities
|
|
│ │ ├── mod.rs
|
|
│ │ ├── prelude.rs
|
|
│ │ ├── customer.rs
|
|
│ │ ├── account.rs
|
|
│ │ ├── service.rs
|
|
│ │ ├── project.rs
|
|
│ │ ├── schedule.rs
|
|
│ │ ├── revenue.rs
|
|
│ │ ├── labor.rs
|
|
│ │ ├── invoice.rs
|
|
│ │ ├── report.rs
|
|
│ │ ├── user.rs
|
|
│ │ └── profile.rs
|
|
│ └── graphql/ # GraphQL resolvers
|
|
│ ├── mod.rs # Schema definition
|
|
│ ├── customer.rs
|
|
│ ├── account.rs
|
|
│ ├── service.rs
|
|
│ ├── project.rs
|
|
│ ├── schedule.rs
|
|
│ ├── revenue.rs
|
|
│ ├── labor.rs
|
|
│ ├── invoice.rs
|
|
│ ├── report.rs
|
|
│ ├── user.rs
|
|
│ └── profile.rs
|
|
├── migration/ # SeaORM migrations
|
|
│ └── src/
|
|
│ ├── lib.rs
|
|
│ └── m20220101_*.rs
|
|
├── frontend/ # SvelteKit + Houdini frontend
|
|
│ ├── src/
|
|
│ ├── .houdini/ # Generated GraphQL artifacts
|
|
│ └── schema.graphql # GraphQL schema
|
|
├── Cargo.toml
|
|
└── Cargo.lock
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
- Rust (latest stable)
|
|
- PostgreSQL 15+
|
|
- Node.js 18+ (for frontend)
|
|
|
|
### Backend Setup
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone <repository-url>
|
|
cd nexus-4
|
|
|
|
# Create .env file
|
|
cat > .env << EOF
|
|
DATABASE_URL=postgres://user:password@localhost/nexus4
|
|
JWT_SECRET=your-secret-key-change-in-production
|
|
JWT_EXPIRATION=3600
|
|
EOF
|
|
|
|
# Run migrations
|
|
cd migration
|
|
cargo run
|
|
|
|
# Start the server
|
|
cd ..
|
|
cargo run
|
|
```
|
|
|
|
The server will start at:
|
|
- GraphQL endpoint: http://127.0.0.1:8080/graphql
|
|
- GraphQL playground: http://127.0.0.1:8080/playground
|
|
- Auth endpoint: http://127.0.0.1:8080/token
|
|
|
|
### Frontend Setup
|
|
|
|
```bash
|
|
cd frontend
|
|
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Start development server
|
|
npm run dev
|
|
```
|
|
|
|
## API Usage
|
|
|
|
### Authentication
|
|
|
|
**Login:**
|
|
```bash
|
|
curl -X POST http://localhost:8080/token \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"username": "your_username", "password": "your_password"}'
|
|
```
|
|
|
|
**Create User:**
|
|
```bash
|
|
curl -X POST http://localhost:8080/users \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"username": "newuser",
|
|
"email": "user@example.com",
|
|
"password": "securepassword",
|
|
"is_active": true,
|
|
"first_name": "John",
|
|
"last_name": "Doe",
|
|
"primary_phone": "555-123-4567",
|
|
"role": "user"
|
|
}'
|
|
```
|
|
|
|
### GraphQL Queries
|
|
|
|
**Get all customers:**
|
|
```graphql
|
|
query {
|
|
customers {
|
|
id
|
|
name
|
|
accounts {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Create a service:**
|
|
```graphql
|
|
mutation {
|
|
createService(input: {
|
|
accountId: "uuid-here"
|
|
status: "scheduled"
|
|
scheduledDate: "2024-01-15"
|
|
}) {
|
|
id
|
|
status
|
|
}
|
|
}
|
|
```
|
|
|
|
## Configuration
|
|
|
|
| Environment Variable | Description | Default |
|
|
|---------------------|-------------|---------|
|
|
| `DATABASE_URL` | PostgreSQL connection string | Required |
|
|
| `JWT_SECRET` | Secret for signing JWTs | `default_secret_change_me` |
|
|
| `JWT_EXPIRATION` | Token expiration in seconds | `3600` |
|
|
|
|
## Why Rust Was Considered
|
|
|
|
1. **Performance**: Rust's zero-cost abstractions provide C-like performance
|
|
2. **Memory Safety**: No null pointer exceptions or data races
|
|
3. **Concurrency**: Fearless concurrency with async/await
|
|
4. **Type System**: Catch errors at compile time
|
|
5. **Single Binary**: Easy deployment without runtime dependencies
|
|
|
|
## Why It Was Abandoned
|
|
|
|
1. **Development Speed**: Django's ORM and admin interface provide faster iteration
|
|
2. **Ecosystem**: Python has more libraries for business logic (PDF generation, email, etc.)
|
|
3. **Hiring**: Finding Django developers is easier than Rust developers
|
|
4. **Maintenance**: Team was more comfortable debugging Python code
|
|
|
|
## Lessons Learned
|
|
|
|
- Rust is excellent for performance-critical services
|
|
- For CRUD-heavy business apps, developer productivity often matters more than raw performance
|
|
- Consider Rust for specific microservices where performance is critical
|
|
- The async-graphql and SeaORM ecosystem is mature and pleasant to use
|
|
|
|
## License
|
|
|
|
MIT License - See LICENSE file for details.
|