Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create initial project structure (Frontend) #10

Merged
merged 35 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
83bdd3e
add backend
archeoss Aug 18, 2023
beaac7b
post review fixes pt.1
archeoss Sep 7, 2023
2e8ebbb
post review fixes pt.2
archeoss Sep 10, 2023
818c26b
post review fixes (WIP)
archeoss Sep 17, 2023
357f0f9
change build flow + error handling
archeoss Sep 19, 2023
23e974f
clean up
archeoss Sep 19, 2023
76133a2
add frontend
archeoss Aug 19, 2023
e0685ef
update dev. paths for frontend + Update README
archeoss Aug 19, 2023
2f751be
migrate to astro
archeoss Aug 25, 2023
4901968
Update README
archeoss Aug 25, 2023
013fdd7
update deps
archeoss Aug 30, 2023
48fc07a
change frontend build dest.
archeoss Sep 3, 2023
34e4a90
update deps
archeoss Sep 5, 2023
eca2e14
update deps + scripts
archeoss Sep 7, 2023
1f7434a
post rebase tweaks
archeoss Sep 10, 2023
c97a42f
update readme
archeoss Sep 19, 2023
becb60d
bundle tweaks
archeoss Oct 3, 2023
76ae531
build process change + review fixes
archeoss Oct 5, 2023
8fbbb84
add windows compatibility
archeoss Oct 5, 2023
7a14556
remove redundant cfg
archeoss Oct 5, 2023
af5706b
change build process + post review fixes
archeoss Oct 6, 2023
5d20e48
log fixup
archeoss Oct 6, 2023
8470f09
fix test macro call
archeoss Oct 6, 2023
ab68a43
OpenAPI path validation + review fixes
archeoss Oct 9, 2023
df0663f
fix no-swagger build
archeoss Oct 9, 2023
5d08a3d
redo API validation + tests
archeoss Oct 12, 2023
d4b9d00
Post review fixes (+wrapper on router; -wrapper on method, etc.)
archeoss Oct 19, 2023
4206449
hotfix
archeoss Oct 19, 2023
7351399
hotfix 2
archeoss Oct 19, 2023
86a513b
add error accumulation for ContextRouter
archeoss Oct 20, 2023
9a8af15
small post-review fixes
archeoss Oct 23, 2023
bc0dab1
small post-review fixes
archeoss Oct 23, 2023
460e733
small fixes
archeoss Oct 30, 2023
03d783e
remove frontend dep.
archeoss Nov 4, 2023
4479b4e
bump deps
archeoss Nov 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Bob Management GUI changelog
#### Added

- Initial project structure, backend only (#9)
- Initial project stricture, frontend (#10)
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ codegen-units = 1
[profile.min-size]
inherits = "release"
opt-level = "s"

51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,51 @@
# bob-management
Management UI for Bob

Management UI for Bob

## Commands
archeoss marked this conversation as resolved.
Show resolved Hide resolved

Build backend server:

```sh
cargo build-backend
```

Run backend server:

```sh
cargo run-backend
```

Build frontend and move it into the backend's executable directory:

```sh
cargo build-frontend
```

---

Run debug build (Backend + Frontend):

```sh
cargo run -- --default
```

---

Make release build (Backend + Frontend):

```sh
cargo build --profile=release-lto
```

To run release build with default configuration:

```sh
cargo run --profile=release-lto -- --default
```

Or you can specify configuration file:

```sh
cargo run --profile=release-lto -- --config-file config.yaml
```
25 changes: 15 additions & 10 deletions backend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "backend"
description = "Bob Management GUI"
default-run = "backend"
description = "Bob Management GUI: Backend"
publish = false
keywords = [ "BOB", "Management", "GUI" ]
version.workspace = true
Expand All @@ -18,7 +19,7 @@ axum-macros = "0.3"
axum-login = "0.6"
axum-sessions = "0.5"
tower = "0.4"
tower-http = { version = "0.4", features = ["cors"] }
tower-http = { version = "0.4", features = ["cors", "fs"] }

## Logging
tracing = "0.1"
Expand All @@ -29,19 +30,23 @@ error-stack = "0.4"
thiserror = "1.0"

## General
tokio = { version = "1.32", features = ["rt", "macros", "rt-multi-thread"] }
tokio = { version = "1.32", features = ["rt", "macros", "rt-multi-thread" ] }
hyper = "0.14"
lazy_static = "1.4"

## OpenAPI + Swagger
utoipa = { version = "3.4", features = ["axum_extras", "chrono", "openapi_extensions"], optional = true }
utoipa-swagger-ui = { version = "3.1", features = ["axum"], optional = true }
utoipa-redoc = { version = "0.1", features = ["axum"], optional = true }
utoipa-rapidoc = { version = "0.1", features = ["axum"], optional = true }
utoipa = { version = "4.0", features = ["yaml", "axum_extras", "chrono", "openapi_extensions"], optional = true }
utoipa-swagger-ui = { version = "4.0", features = ["axum"], optional = true }
utoipa-redoc = { version = "1.0", features = ["axum"], optional = true }
utoipa-rapidoc = { version = "1.0", features = ["axum"], optional = true }

## CLI
cli = { path = "../cli" }

[features]
default = [ "swagger" ]
swagger = [ "utoipa", "utoipa-swagger-ui" , "utoipa-redoc", "utoipa-rapidoc" ]
## Frontend
frontend = { path = "../frontend", optional = true }
ikopylov marked this conversation as resolved.
Show resolved Hide resolved

[features]
default = [ "swagger", "frontend-bundle" ]
swagger = [ "dep:utoipa", "dep:utoipa-swagger-ui" , "dep:utoipa-redoc", "dep:utoipa-rapidoc" ]
frontend-bundle = [ "dep:frontend" ]
1 change: 1 addition & 0 deletions backend/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(clippy::module_name_repetitions)]

use axum::response::{IntoResponse, Response};
use hyper::StatusCode;
use thiserror::Error;
Expand Down
47 changes: 32 additions & 15 deletions backend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
#![allow(clippy::multiple_crate_versions)]
#![allow(clippy::multiple_crate_versions, clippy::module_name_repetitions)]

#[cfg(all(feature = "swagger", debug_assertions))]
use axum::{routing::get, Router};

#[cfg(feature = "swagger")]
use axum::Router;
#[cfg(feature = "swagger")]
use utoipa::OpenApi;

pub mod config;
pub mod connector;
pub mod error;
pub mod models;
pub mod router;
pub mod services;

#[derive(OpenApi)]
#[cfg_attr(not(all(feature = "swagger", debug_assertions)), openapi())]
#[cfg_attr(all(feature = "swagger", debug_assertions), openapi(
paths(root),
tags(
(name = "bob", description = "BOB management API")
)
))]
pub struct ApiDoc;

// [TEMP]
// TODO: Remove when the actual API will be implemented
#[allow(clippy::unused_async)]
#[cfg_attr(feature = "swagger", utoipa::path(
#[cfg_attr(all(feature = "swagger", debug_assertions), utoipa::path(
get,
path = "/",
path = "/root",
responses(
(status = 200, description = "Hello Bob!")
)
Expand All @@ -25,35 +37,40 @@ pub async fn root() -> &'static str {
}

/// Generate openapi documentation for the project
#[cfg(feature = "swagger")]
#[cfg(all(feature = "swagger", debug_assertions))]
pub fn openapi_doc() -> Router {
use utoipa_rapidoc::RapiDoc;
use utoipa_redoc::{Redoc, Servable};
use utoipa_swagger_ui::SwaggerUi;

/* Swagger-only routes */
#[derive(OpenApi)]
#[openapi(
paths(root),
tags(
(name = "bob", description = "BOB management API")
)
)]
struct ApiDoc;
tracing::info!("Swagger ui available at /swagger-ui");

/* Mount Swagger ui */
Router::new()
.merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
.merge(Redoc::with_url("/redoc", ApiDoc::openapi()))
// There is no need to create `RapiDoc::with_openapi` because the OpenApi is served
// via SwaggerUi instead we only make rapidoc to point to the existing doc.
.merge(RapiDoc::new("/api-docs/openapi.json").path("/rapidoc"))
.route(
"/api-docs/openapi.yaml",
get(|| async {
ApiDoc::openapi()
.to_yaml()
.expect("Couldn't produce .yaml API scheme")
}),
)
// Alternative to above
// .merge(RapiDoc::with_openapi("/api-docs/openapi2.json", ApiDoc::openapi()).path("/rapidoc"))
}

pub mod prelude {
#![allow(unused_imports)]
pub use crate::error::AppError;
pub use crate::router::RouteError;
pub use axum::response::Result as AxumResult;
pub use error_stack::{Context, Report, Result, ResultExt};
// #[cfg(all(feature = "swagger", debug_assertions))]
pub use utoipa::OpenApi;
}
40 changes: 31 additions & 9 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
#![allow(clippy::multiple_crate_versions)]

use axum::{routing::get, Router};
use backend::{config::ConfigExt, prelude::*, root, services::api_router};
use axum::Router;
use backend::{
config::ConfigExt,
prelude::*,
root,
router::{NoApi, RouterApiExt},
services::api_router,
ApiDoc,
};
use cli::Parser;
use error_stack::{Result, ResultExt};
use std::path::PathBuf;
use hyper::Method;
use std::{env, path::PathBuf};
use tower::ServiceBuilder;
use tower_http::cors::CorsLayer;
use tower_http::{cors::CorsLayer, services::ServeDir};
use tracing::Level;

const FRONTEND_FOLDER: &str = "frontend";

#[tokio::main]
#[allow(clippy::unwrap_used, clippy::expect_used)]
async fn main() -> Result<(), AppError> {
Expand All @@ -28,7 +38,7 @@ async fn main() -> Result<(), AppError> {
tracing::info!("Listening on {addr}");

let app = router(cors);
#[cfg(feature = "swagger")]
#[cfg(all(feature = "swagger", debug_assertions))]
let app = app.merge(backend::openapi_doc());

axum::Server::bind(&addr)
Expand All @@ -46,10 +56,22 @@ fn init_tracer(_log_file: &Option<PathBuf>, trace_level: Level) {
}

fn router(cors: CorsLayer) -> Router {
// Add api
Router::new()
// Unsecured Routes
.route("/", get(root))
let mut frontend = env::current_exe().expect("Couldn't get current executable path.");
frontend.pop();
frontend.push(FRONTEND_FOLDER);
tracing::info!("serving frontend at: {frontend:?}");
let router = Router::new()
// Frontend
.nest_service("/", ServeDir::new(frontend));

// Add API
let router = router
.with_context::<NoApi, ApiDoc>()
.api_route("/root", Method::GET, root)
.expect("Couldn't register new API route")
.no_context();
// .no_context();
router
.nest("/api", api_router())
.layer(ServiceBuilder::new().layer(cors))
}
Loading