Skip to content

vmillet-dev/webserver-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust Web Server

This is a flexible Rust web server using Actix-web, Diesel ORM, and PostgreSQL.

Prerequisites

Before you begin, ensure you have the following installed:

Project Structure

The project is organized into the following structure:

src/
├── controllers/
│   ├── mod.rs
│   └── auth.rs
├── repositories/
│   ├── mod.rs
│   └── user_repository.rs
├── services/
│   ├── mod.rs
│   └── auth_service.rs
├── models.rs
├── schema.rs
├── errors.rs
├── dto/
│   ├── mod.rs
│   ├── auth_response.rs
│   ├── claims.rs
│   ├── login_user.rs
│   ├── register_user.rs
│   └── user.rs
└── lib.rs

Key Components

  1. Controllers: Handle HTTP requests and responses. They use services to process business logic.

    • auth.rs: Manages authentication-related endpoints (register, login, refresh).
  2. Repositories: Interact with the database, performing CRUD operations.

    • user_repository.rs: Handles database operations for user-related data.
  3. Services: Contain the core business logic of the application.

    • auth_service.rs: Implements authentication logic, including user registration, login, and token refresh.
  4. Models: Define the data structures that represent database tables.

    • models.rs: Contains structs for User and RefreshToken.
  5. Schema: Auto-generated by Diesel, represents the database schema.

    • schema.rs: Defines the structure of database tables.
  6. Errors: Custom error handling for the application.

    • errors.rs: Defines the ApiError type for consistent error responses.
  7. DTOs (Data Transfer Objects): Structures for data exchange between layers.

    • auth_response.rs: Defines the structure for authentication responses.
    • claims.rs: Contains JWT claims structure.
    • login_user.rs and register_user.rs: Structures for login and registration requests.
    • user.rs: DTO for user data.
  8. lib.rs: The library's root file, re-exporting modules and setting up shared components.

This structure promotes separation of concerns, making the application more modular and easier to maintain. Each component has a specific responsibility:

  • Controllers handle the web interface.
  • Repositories manage data persistence.
  • Services implement business logic.
  • Models and DTOs define data structures.
  • The errors module provides consistent error handling across the application.

Adding a New Repository

To add a new repository:

  1. Create a new file in the src/repositories/ directory (e.g., new_repository.rs).
  2. Define your repository struct and implement methods for database operations.
  3. Add a pub mod new_repository; line in src/repositories/mod.rs.

Example:

// src/repositories/new_repository.rs
use diesel::prelude::*;
use crate::{DbPool, NewModel, schema::new_table};

pub struct NewRepository;

impl NewRepository {
    pub fn create(pool: &DbPool, new_item: &NewModel) -> Result<NewModel, diesel::result::Error> {
        let mut conn = pool.get().expect("Couldn't get db connection from pool");
        diesel::insert_into(new_table::table)
            .values(new_item)
            .get_result(&mut conn)
    }

    // Add more methods as needed
}

Adding a New Controller

To add a new controller:

  1. Create a new file in the src/controllers/ directory (e.g., new_controller.rs).
  2. Define your controller functions that handle HTTP requests.
  3. Add a pub mod new_controller; line in src/controllers/mod.rs.

Example:

// src/controllers/new_controller.rs
use actix_web::{web, HttpResponse, Responder};
use crate::{DbPool, NewModel};
use crate::services::new_service::NewService;

pub async fn create_new_item(
    pool: web::Data<DbPool>,
    item_info: web::Json<NewModel>,
) -> impl Responder {
    match NewService::create(&pool, &item_info.into_inner()) {
        Ok(_) => HttpResponse::Ok().json("Item successfully created"),
        Err(_) => HttpResponse::InternalServerError().json("Failed to create item"),
    }
}

// Add more controller functions as needed

Updating Main Application

After adding new repositories, services, and controllers, update src/main.rs to include the new routes:

use actix_web::{web, App, HttpServer};
use your_project_name::controllers::auth;
use your_project_name::controllers::new_controller;

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // ... (database setup code)

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(pool.clone()))
            .service(
                web::scope("/api")
                    .configure(auth::configure)
                    .service(
                        web::scope("/new")
                            .route("/create", web::post().to(new_controller::create_new_item))
                    )
            )
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

This structure allows for easy addition of new features and maintains a clean separation of concerns.

Database Setup

To set up the database for this project, follow these steps:

Linux/macOS

  1. Start the PostgreSQL service:

    sudo systemctl start postgresql
    
  2. Create a new database for the project:

    sudo -u postgres psql -c "CREATE DATABASE rust_web_server;"
    
  3. Create a new user and grant privileges:

    sudo -u postgres psql -c "CREATE USER your_username WITH PASSWORD 'your_password';"
    sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE rust_web_server TO your_username;"
    

Windows

  1. Open the PostgreSQL shell (SQL Shell) from the Start menu.

  2. Connect to the default database (usually 'postgres') by pressing Enter for each prompt until you reach the password prompt. Enter your PostgreSQL superuser password.

  3. Create a new database for the project:

    CREATE DATABASE rust_web_server;
    
  4. Create a new user and grant privileges:

    CREATE USER your_username WITH PASSWORD 'your_password';
    GRANT ALL PRIVILEGES ON DATABASE rust_web_server TO your_username;
    

All Platforms

  1. Create a .env file in the project root directory and add your database connection details:

    DATABASE_URL=postgres://your_username:your_password@localhost/rust_web_server
    
  2. Install the Diesel CLI (if not already installed):

    cargo install diesel_cli --no-default-features --features postgres
    
  3. Run database migrations:

    diesel migration run
    

After completing these steps, your database should be set up and ready for use with the Rust web server.

Running Tests

To run the tests for this project, follow these steps:

  1. Ensure that your database is set up and running as described in the Database Setup section.

  2. Make sure you are in the project root directory.

  3. Run all tests using the following command:

    cargo test
    

    This will compile your code and run all the tests, including unit tests and integration tests.

  4. To run a specific test, you can use:

    cargo test test_name
    

    Replace test_name with the name of the test you want to run.

  5. To see the output of println! statements in tests, use:

    cargo test -- --nocapture
    
  6. To run tests with logging, set the RUST_LOG environment variable:

    • On Linux/macOS:
      RUST_LOG=debug cargo test
      
    • On Windows (PowerShell):
      $env:RUST_LOG="debug"; cargo test
      
    • On Windows (Command Prompt):
      set RUST_LOG=debug && cargo test
      

Remember to keep your tests up to date as you add new features or modify existing functionality.

Application Usage

This section provides instructions for running the application on both Unix and Windows systems.

Unix (Linux/macOS)

  1. Open a terminal and navigate to the project root directory.
  2. Run the following command to start the server:
    cargo run
    
  3. The server will start and listen on http://127.0.0.1:8080 by default.

Windows

  1. Open a Command Prompt or PowerShell window and navigate to the project root directory.
  2. Run the following command to start the server:
    cargo run
    
  3. The server will start and listen on http://127.0.0.1:8080 by default.

For both Unix and Windows systems, you can now send requests to the API endpoints using tools like curl, Postman, or any HTTP client.

Security Improvements

This project implements several security features to protect user data and prevent unauthorized access:

  1. Password Hashing: User passwords are hashed using bcrypt before being stored in the database. This ensures that even if the database is compromised, the actual passwords remain secure.

  2. JWT (JSON Web Token) Authentication: The application uses JWT for secure authentication. When a user logs in successfully, they receive a short-lived access token and a longer-lived refresh token.

  3. Refresh Token Mechanism: To improve security while maintaining user convenience, the application implements a refresh token system. This allows users to obtain a new access token without re-entering their credentials, as long as their refresh token is valid.

  4. HttpOnly Cookies: Refresh tokens are stored in HttpOnly cookies, which helps prevent cross-site scripting (XSS) attacks by making the cookie inaccessible to client-side scripts.

  5. CORS (Cross-Origin Resource Sharing) Configuration: The application includes a CORS configuration to control which domains can access the API, helping to prevent unauthorized access from other websites.

  6. Environment Variables: Sensitive information such as database credentials and JWT secrets are stored in environment variables, keeping them out of the source code and making the application more secure and configurable.

  7. Custom Error Handling: The application uses custom error types and handling to ensure that detailed error information is not leaked to clients, which could potentially expose vulnerabilities.

  8. Database Connection Pooling: The use of connection pooling helps prevent resource exhaustion attacks by efficiently managing database connections.

These security measures work together to create a robust and secure web application. However, security is an ongoing process, and it's important to regularly review and update security practices as new threats emerge and best practices evolve.

Running the Application

To run the Rust web server, follow these steps:

  1. Ensure that your database is set up and running as described in the Database Setup section.

  2. Make sure you are in the project root directory.

  3. Run the application using the following command:

    cargo run
    
  4. The server will start and listen on http://127.0.0.1:8080 by default.

  5. You can now send requests to the API endpoints using tools like curl, Postman, or any HTTP client.

Example API requests:

  • Register a new user:

    curl -X POST -H "Content-Type: application/json" -d "{\"username\":\"newuser\",\"email\":\"newuser@example.com\",\"password\":\"password123\"}" http://localhost:8080/api/auth/register
    
  • Login:

    curl -X POST -H "Content-Type: application/json" -d "{\"username\":\"newuser\",\"password\":\"password123\"}" http://localhost:8080/api/auth/login
    

Remember to replace the example values with actual data when testing the API.

Troubleshooting

If you encounter any issues while setting up or running the project, please check the following:

  1. Ensure that PostgreSQL is installed and running correctly on your system.
  2. Verify that the database connection details in your .env file are correct.
  3. Make sure you have the latest version of Rust installed (rustc --version).
  4. If you're having issues with Diesel CLI, try reinstalling it with cargo install diesel_cli --no-default-features --features postgres.

If you continue to experience problems, please open an issue on the project's GitHub repository with a detailed description of the error and the steps to reproduce it.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors