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 }