Skip to content

Commit 0eaf96a

Browse files
authored
Merge pull request #113 from threefoldtech/development-fix-swagger
Fix and organize OpenAPI schema
2 parents 75e19dc + 01134f8 commit 0eaf96a

File tree

9 files changed

+238
-105
lines changed

9 files changed

+238
-105
lines changed

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
2-
channel = "1.74.0"
2+
channel = "1.83.0"
33

src/server/auth.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ pub struct SignInResponse {
3838

3939
#[utoipa::path(
4040
post,
41-
path = "/v1/api/signin",
41+
path = "/api/v1/signin",
42+
tag = "Authentication",
4243
request_body = SignInBody,
4344
responses(
44-
(status = 200, description = "User signed in successfully", body = SignInResponse),
45-
(status = 500, description = "Internal server error"),
46-
(status = 401, description = "Unauthorized user"),
45+
(status = 201, description = "User signed in successfully", body = SignInResponse),
46+
(status = 500, description = "Internal server error", body = ResponseError),
47+
(status = 401, description = "Unauthorized user", body = ResponseError),
4748
)
4849
)]
4950
#[debug_handler]

src/server/block_handlers.rs

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,12 @@ use crate::server::{
1313
config::AppState,
1414
db::DB,
1515
models::Block,
16-
response::{ResponseError, ResponseResult},
16+
response::{ResponseError, ResponseResult, BlockUploadedResponse},
1717
};
1818
use serde::{Deserialize, Serialize};
19-
use utoipa::{OpenApi, ToSchema};
19+
use utoipa::ToSchema;
2020

21-
#[derive(OpenApi)]
22-
#[openapi(
23-
paths(upload_block_handler, get_block_handler, check_block_handler, verify_blocks_handler, get_blocks_by_hash_handler, list_blocks_handler, get_user_blocks_handler, get_block_downloads_handler),
24-
components(schemas(Block, VerifyBlocksRequest, VerifyBlocksResponse, BlocksResponse, ListBlocksParams, ListBlocksResponse, UserBlocksResponse, BlockDownloadsResponse)),
25-
tags(
26-
(name = "blocks", description = "Block management API")
27-
)
28-
)]
29-
pub struct BlockApi;
21+
// Block API endpoints are included in the main FlistApi in handlers.rs
3022

3123
/// Query parameters for uploading a block
3224
#[derive(Debug, Serialize, Deserialize, ToSchema)]
@@ -43,16 +35,20 @@ pub struct UploadBlockParams {
4335
#[utoipa::path(
4436
post,
4537
path = "/api/v1/block",
46-
request_body(content = Vec<u8>, description = "Block data to upload", content_type = "application/octet-stream"),
38+
tag = "Block Management",
39+
request_body(content = [u8], description = "Block data to upload", content_type = "application/octet-stream"),
4740
params(
4841
("file_hash" = String, Query, description = "File hash associated with the block"),
4942
("idx" = u64, Query, description = "Block index within the file")
5043
),
5144
responses(
52-
(status = 200, description = "Block already exists", body = String),
53-
(status = 201, description = "Block created successfully", body = String),
54-
(status = 400, description = "Bad request"),
55-
(status = 500, description = "Internal server error"),
45+
(status = 200, description = "Block already exists", body = BlockUploadedResponse),
46+
(status = 201, description = "Block created successfully", body = BlockUploadedResponse),
47+
(status = 400, description = "Bad request", body = ResponseError),
48+
(status = 500, description = "Internal server error", body = ResponseError),
49+
),
50+
security(
51+
("bearerAuth" = [])
5652
)
5753
)]
5854
#[debug_handler]
@@ -98,10 +94,11 @@ pub async fn upload_block_handler(
9894
#[utoipa::path(
9995
get,
10096
path = "/api/v1/block/{hash}",
97+
tag = "Block Management",
10198
responses(
102-
(status = 200, description = "Block found", content_type = "application/octet-stream"),
103-
(status = 404, description = "Block not found"),
104-
(status = 500, description = "Internal server error"),
99+
(status = 200, description = "Block found", body = [u8], content_type = "application/octet-stream"),
100+
(status = 404, description = "Block not found", body = ResponseError),
101+
(status = 500, description = "Internal server error", body = ResponseError),
105102
),
106103
params(
107104
("hash" = String, Path, description = "Block hash")
@@ -136,9 +133,10 @@ pub async fn get_block_handler(
136133
#[utoipa::path(
137134
head,
138135
path = "/api/v1/block/{hash}",
136+
tag = "Block Management",
139137
responses(
140138
(status = 200, description = "Block found"),
141-
(status = 404, description = "Block not found"),
139+
(status = 404, description = "Block not found", body = ResponseError),
142140
),
143141
params(
144142
("hash" = String, Path, description = "Block hash")
@@ -194,11 +192,12 @@ pub struct VerifyBlocksResponse {
194192
#[utoipa::path(
195193
post,
196194
path = "/api/v1/block/verify",
195+
tag = "Block Management",
197196
request_body(content = VerifyBlocksRequest, description = "List of block hashes to verify", content_type = "application/json"),
198197
responses(
199198
(status = 200, description = "Verification completed", body = VerifyBlocksResponse),
200-
(status = 400, description = "Bad request"),
201-
(status = 500, description = "Internal server error"),
199+
(status = 400, description = "Bad request", body = ResponseError),
200+
(status = 500, description = "Internal server error", body = ResponseError),
202201
)
203202
)]
204203
#[debug_handler]
@@ -228,11 +227,29 @@ pub async fn verify_blocks_handler(
228227
))
229228
}
230229

230+
/// Block information with hash and index
231+
#[derive(Debug, Serialize, Deserialize, ToSchema)]
232+
pub struct BlockInfo {
233+
/// Block hash
234+
pub hash: String,
235+
/// Block index within the file
236+
pub index: u64,
237+
}
238+
239+
/// Block information with hash and size
240+
#[derive(Debug, Serialize, Deserialize, ToSchema)]
241+
pub struct UserBlockInfo {
242+
/// Block hash
243+
pub hash: String,
244+
/// Block size in bytes
245+
pub size: u64,
246+
}
247+
231248
/// Response for blocks by hash endpoint
232249
#[derive(Debug, Serialize, Deserialize, ToSchema)]
233250
pub struct BlocksResponse {
234251
/// List of blocks with their indices
235-
pub blocks: Vec<(String, u64)>,
252+
pub blocks: Vec<BlockInfo>,
236253
}
237254

238255
/// Retrieve blocks by hash (file hash or block hash).
@@ -241,10 +258,11 @@ pub struct BlocksResponse {
241258
#[utoipa::path(
242259
get,
243260
path = "/api/v1/blocks/{hash}",
261+
tag = "Block Management",
244262
responses(
245263
(status = 200, description = "Blocks found", body = BlocksResponse),
246-
(status = 404, description = "Hash not found"),
247-
(status = 500, description = "Internal server error"),
264+
(status = 404, description = "Hash not found", body = ResponseError),
265+
(status = 500, description = "Internal server error", body = ResponseError),
248266
),
249267
params(
250268
("hash" = String, Path, description = "File hash or block hash")
@@ -259,7 +277,10 @@ pub async fn get_blocks_by_hash_handler(
259277
match state.db.get_file_blocks_ordered(&hash).await {
260278
Ok(blocks) if !blocks.is_empty() => {
261279
// This is a file hash, return all blocks with their indices
262-
Ok((StatusCode::OK, Json(BlocksResponse { blocks })))
280+
let block_infos = blocks.into_iter()
281+
.map(|(hash, index)| BlockInfo { hash, index })
282+
.collect();
283+
Ok((StatusCode::OK, Json(BlocksResponse { blocks: block_infos })))
263284
}
264285
Ok(_) | Err(_) => {
265286
// Not a file hash or error occurred, try as block hash
@@ -269,7 +290,7 @@ pub async fn get_blocks_by_hash_handler(
269290
Ok((
270291
StatusCode::OK,
271292
Json(BlocksResponse {
272-
blocks: vec![(hash.clone(), 0)],
293+
blocks: vec![BlockInfo { hash: hash.clone(), index: 0 }],
273294
}),
274295
))
275296
}
@@ -317,6 +338,7 @@ pub struct ListBlocksResponse {
317338
#[utoipa::path(
318339
get,
319340
path = "/api/v1/blocks",
341+
tag = "Block Management",
320342
params(
321343
("page" = Option<u32>, Query, description = "Page number (1-indexed)"),
322344
("per_page" = Option<u32>, Query, description = "Number of items per page")
@@ -356,7 +378,7 @@ pub async fn list_blocks_handler(
356378
#[derive(Debug, Serialize, Deserialize, ToSchema)]
357379
pub struct UserBlocksResponse {
358380
/// List of blocks with their sizes
359-
pub blocks: Vec<(String, u64)>,
381+
pub blocks: Vec<UserBlockInfo>,
360382
/// Total number of blocks
361383
pub total: u64,
362384
/// Total number of all blocks
@@ -367,6 +389,7 @@ pub struct UserBlocksResponse {
367389
#[utoipa::path(
368390
get,
369391
path = "/api/v1/user/blocks",
392+
tag = "Block Management",
370393
params(
371394
("page" = Option<u32>, Query, description = "Page number (1-indexed)"),
372395
("per_page" = Option<u32>, Query, description = "Number of items per page")
@@ -375,6 +398,9 @@ pub struct UserBlocksResponse {
375398
(status = 200, description = "Blocks found", body = UserBlocksResponse),
376399
(status = 401, description = "Unauthorized"),
377400
(status = 500, description = "Internal server error"),
401+
),
402+
security(
403+
("bearerAuth" = [])
378404
)
379405
)]
380406
#[debug_handler]
@@ -403,7 +429,9 @@ pub async fn get_user_blocks_handler(
403429
Ok(blocks) => {
404430
let total = blocks.len() as u64;
405431
let response = UserBlocksResponse {
406-
blocks,
432+
blocks: blocks.into_iter()
433+
.map(|(hash, size)| UserBlockInfo { hash, size })
434+
.collect(),
407435
total,
408436
all_blocks,
409437
};
@@ -431,6 +459,7 @@ pub struct BlockDownloadsResponse {
431459
#[utoipa::path(
432460
get,
433461
path = "/api/v1/block/{hash}/downloads",
462+
tag = "Block Management",
434463
responses(
435464
(status = 200, description = "Download count retrieved successfully", body = BlockDownloadsResponse),
436465
(status = 404, description = "Block not found"),

src/server/file_handlers.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,11 @@ use crate::server::{
1010
response::{ResponseError, ResponseResult},
1111
};
1212
use serde::{Deserialize, Serialize};
13-
use utoipa::{OpenApi, ToSchema};
13+
use utoipa::ToSchema;
1414

1515
const BLOCK_SIZE: usize = 1024 * 1024; // 1MB
1616

17-
#[derive(OpenApi)]
18-
#[openapi(
19-
paths(upload_file_handler, get_file_handler),
20-
components(schemas(File, FileUploadResponse, FileDownloadRequest)),
21-
tags(
22-
(name = "files", description = "File management API")
23-
)
24-
)]
25-
pub struct FileApi;
17+
// File API endpoints are included in the main FlistApi in handlers.rs
2618

2719
/// Response for file upload
2820
#[derive(Debug, Serialize, Deserialize, ToSchema)]
@@ -38,11 +30,15 @@ pub struct FileUploadResponse {
3830
#[utoipa::path(
3931
post,
4032
path = "/api/v1/file",
41-
request_body(content = Vec<u8>, description = "File data to upload", content_type = "application/octet-stream"),
33+
tag = "File Management",
34+
request_body(content = [u8], description = "File data to upload", content_type = "application/octet-stream"),
4235
responses(
4336
(status = 201, description = "File uploaded successfully", body = FileUploadResponse),
44-
(status = 400, description = "Bad request"),
45-
(status = 500, description = "Internal server error"),
37+
(status = 400, description = "Bad request", body = ResponseError),
38+
(status = 500, description = "Internal server error", body = ResponseError),
39+
),
40+
security(
41+
("bearerAuth" = [])
4642
)
4743
)]
4844
#[debug_handler]
@@ -120,13 +116,14 @@ pub struct FileDownloadRequest {
120116
/// Retrieve a file by its hash from path, with optional custom filename in request body.
121117
/// The file will be reconstructed from its blocks.
122118
#[utoipa::path(
123-
post,
119+
get,
124120
path = "/api/v1/file/{hash}",
121+
tag = "File Management",
125122
request_body(content = FileDownloadRequest, description = "Optional custom filename for download", content_type = "application/json"),
126123
responses(
127-
(status = 200, description = "File found", content_type = "application/octet-stream"),
128-
(status = 404, description = "File not found"),
129-
(status = 500, description = "Internal server error"),
124+
(status = 200, description = "File found", body = [u8], content_type = "application/octet-stream"),
125+
(status = 404, description = "File not found", body = ResponseError),
126+
(status = 500, description = "Internal server error", body = ResponseError),
130127
),
131128
params(
132129
("hash" = String, Path, description = "File hash")

0 commit comments

Comments
 (0)