228 lines
6.6 KiB
Plaintext
228 lines
6.6 KiB
Plaintext
syntax = "v1"
|
|
|
|
info (
|
|
title: "Blog API"
|
|
desc: "Blog service API with file upload/download and CRUD operations"
|
|
author: "cialloo"
|
|
date: "2025-10-22"
|
|
version: "v1"
|
|
)
|
|
|
|
// ============= File Upload/Download Types =============
|
|
type (
|
|
// Request for generating presigned upload URL
|
|
GenerateUploadUrlReq {
|
|
FileName string `json:"file_name"` // Original file name
|
|
FileSize int64 `json:"file_size"` // File size in bytes
|
|
}
|
|
|
|
GenerateUploadUrlResp {
|
|
FileId int64 `json:"file_id"` // Generated file ID
|
|
PresignedUrl string `json:"presigned_url"` // S3 presigned upload URL
|
|
FileKey string `json:"file_key"` // S3 file key
|
|
ExpiresIn int `json:"expires_in"` // URL expiration time in seconds
|
|
}
|
|
|
|
// Request for generating presigned download URL
|
|
GenerateDownloadUrlReq {
|
|
FileId int64 `path:"file_id"` // File ID to download
|
|
}
|
|
|
|
GenerateDownloadUrlResp {
|
|
FileName string `json:"file_name"` // Original file name
|
|
PresignedUrl string `json:"presigned_url"` // S3 presigned download URL
|
|
FileSize int64 `json:"file_size"` // File size in bytes
|
|
ExpiresIn int `json:"expires_in"` // URL expiration time in seconds
|
|
}
|
|
|
|
// Confirm upload completion
|
|
ConfirmUploadReq {
|
|
FileId int64 `json:"file_id"` // File ID to confirm
|
|
}
|
|
|
|
ConfirmUploadResp {
|
|
Success bool `json:"success"` // Upload confirmation status
|
|
Message string `json:"message"` // Status message
|
|
}
|
|
)
|
|
|
|
// ============= Post Types =============
|
|
type (
|
|
// Create post request
|
|
CreatePostReq {
|
|
Title string `json:"title"` // Post title
|
|
Content string `json:"content"` // Post content
|
|
Hashtags []string `json:"hashtags,optional"` // Associated hashtags
|
|
}
|
|
|
|
CreatePostResp {
|
|
PostId int64 `json:"post_id"` // Created post ID
|
|
}
|
|
|
|
// Update post request
|
|
UpdatePostReq {
|
|
PostId int64 `path:"post_id"` // Post ID to update
|
|
Title string `json:"title,optional"` // New title
|
|
Content string `json:"content,optional"` // New content
|
|
Hashtags []string `json:"hashtags,optional"` // New hashtags (replaces all)
|
|
}
|
|
|
|
UpdatePostResp {
|
|
Success bool `json:"success"` // Update status
|
|
}
|
|
|
|
// Delete post request
|
|
DeletePostReq {
|
|
PostId int64 `path:"post_id"` // Post ID to delete
|
|
}
|
|
|
|
DeletePostResp {
|
|
Success bool `json:"success"` // Delete status
|
|
}
|
|
|
|
// Get post detail request
|
|
GetPostReq {
|
|
PostId int64 `path:"post_id"` // Post ID to retrieve
|
|
}
|
|
|
|
PostDetail {
|
|
PostId int64 `json:"post_id"` // Post ID
|
|
Title string `json:"title"` // Post title
|
|
Content string `json:"content"` // Post content
|
|
ViewCount int64 `json:"view_count"` // View count
|
|
Hashtags []Hashtag `json:"hashtags"` // Associated hashtags
|
|
CreatedAt string `json:"created_at"` // Creation timestamp
|
|
UpdatedAt string `json:"updated_at"` // Last update timestamp
|
|
}
|
|
|
|
GetPostResp {
|
|
Post PostDetail `json:"post"` // Post detail
|
|
}
|
|
|
|
// List posts request
|
|
ListPostsReq {
|
|
Page int `form:"page,default=1"` // Page number
|
|
PageSize int `form:"page_size,default=10"` // Items per page
|
|
Hashtag string `form:"hashtag,optional"` // Filter by hashtag name
|
|
SortBy string `form:"sort_by,default=created_at,options=created_at|view_count|updated_at"` // Sort field
|
|
}
|
|
|
|
PostItem {
|
|
PostId int64 `json:"post_id"` // Post ID
|
|
Title string `json:"title"` // Post title
|
|
ViewCount int64 `json:"view_count"` // View count
|
|
Hashtags []Hashtag `json:"hashtags"` // Associated hashtags
|
|
CreatedAt string `json:"created_at"` // Creation timestamp
|
|
UpdatedAt string `json:"updated_at"` // Last update timestamp
|
|
}
|
|
|
|
ListPostsResp {
|
|
Posts []PostItem `json:"posts"` // List of posts
|
|
Total int64 `json:"total"` // Total count
|
|
Page int `json:"page"` // Current page
|
|
PageSize int `json:"page_size"` // Items per page
|
|
TotalPages int `json:"total_pages"` // Total pages
|
|
}
|
|
)
|
|
|
|
// ============= Hashtag Types =============
|
|
type (
|
|
Hashtag {
|
|
HashtagId int64 `json:"hashtag_id"` // Hashtag ID
|
|
Name string `json:"name"` // Hashtag name
|
|
UsageCount int64 `json:"usage_count"` // Usage count
|
|
}
|
|
|
|
// List hashtags request
|
|
ListHashtagsReq {
|
|
Page int `form:"page,default=1"` // Page number
|
|
PageSize int `form:"page_size,default=20"` // Items per page
|
|
SortBy string `form:"sort_by,default=usage_count,options=usage_count|created_at|name"` // Sort field
|
|
}
|
|
|
|
ListHashtagsResp {
|
|
Hashtags []Hashtag `json:"hashtags"` // List of hashtags
|
|
Total int64 `json:"total"` // Total count
|
|
Page int `json:"page"` // Current page
|
|
PageSize int `json:"page_size"` // Items per page
|
|
TotalPages int `json:"total_pages"` // Total pages
|
|
}
|
|
|
|
// Get popular hashtags
|
|
GetPopularHashtagsReq {
|
|
Limit int `form:"limit,default=10"` // Number of hashtags to return
|
|
}
|
|
|
|
GetPopularHashtagsResp {
|
|
Hashtags []Hashtag `json:"hashtags"` // Popular hashtags
|
|
}
|
|
)
|
|
|
|
// ============= Service Definition =============
|
|
@server (
|
|
prefix: /api/v1/blog
|
|
group: file
|
|
)
|
|
service Blog {
|
|
@doc "Generate presigned URL for file upload"
|
|
@handler generateUploadUrl
|
|
post /files/upload/url (GenerateUploadUrlReq) returns (GenerateUploadUrlResp)
|
|
|
|
@doc "Generate presigned URL for file download"
|
|
@handler generateDownloadUrl
|
|
get /files/download/:file_id (GenerateDownloadUrlReq) returns (GenerateDownloadUrlResp)
|
|
|
|
@doc "Confirm file upload completion"
|
|
@handler confirmUpload
|
|
post /files/upload/confirm (ConfirmUploadReq) returns (ConfirmUploadResp)
|
|
}
|
|
|
|
@server (
|
|
prefix: /api/v1/blog
|
|
group: post
|
|
)
|
|
service Blog {
|
|
@doc "Create a new blog post"
|
|
@handler createPost
|
|
post /posts (CreatePostReq) returns (CreatePostResp)
|
|
|
|
@doc "Update an existing blog post"
|
|
@handler updatePost
|
|
put /posts/:post_id (UpdatePostReq) returns (UpdatePostResp)
|
|
|
|
@doc "Delete a blog post"
|
|
@handler deletePost
|
|
delete /posts/:post_id (DeletePostReq) returns (DeletePostResp)
|
|
|
|
@doc "Get blog post detail"
|
|
@handler getPost
|
|
get /posts/:post_id (GetPostReq) returns (GetPostResp)
|
|
|
|
@doc "List blog posts with pagination and filtering"
|
|
@handler listPosts
|
|
get /posts (ListPostsReq) returns (ListPostsResp)
|
|
}
|
|
|
|
@server (
|
|
prefix: /api/v1/blog
|
|
group: hashtag
|
|
)
|
|
service Blog {
|
|
@doc "List all hashtags with pagination"
|
|
@handler listHashtags
|
|
get /hashtags (ListHashtagsReq) returns (ListHashtagsResp)
|
|
|
|
@doc "Get popular hashtags"
|
|
@handler getPopularHashtags
|
|
get /hashtags/popular (GetPopularHashtagsReq) returns (GetPopularHashtagsResp)
|
|
}
|
|
|
|
@server (
|
|
prefix: /api/v1/blog
|
|
group: common
|
|
)
|
|
service Blog {
|
|
@doc "Health check endpoint"
|
|
@handler ping
|
|
get /ping
|
|
} |