Generete Module Handler
This commit is contained in:
289
LAYOUT.md
Normal file
289
LAYOUT.md
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
# 📊 API Service Project Layout
|
||||||
|
|
||||||
|
## 🎯 Project Overview Dashboard
|
||||||
|
|
||||||
|
### 📈 Key Metrics
|
||||||
|
- **Language**: Go 1.24.4
|
||||||
|
- **Framework**: Gin 1.10.1
|
||||||
|
- **Database**: PostgreSQL with GORM
|
||||||
|
- **Authentication**: JWT + Keycloak
|
||||||
|
- **Documentation**: Swagger/OpenAPI 3.0
|
||||||
|
- **Container**: Docker & Docker Compose
|
||||||
|
|
||||||
|
### 🏗️ Architecture Overview
|
||||||
|
```
|
||||||
|
api-service/
|
||||||
|
├── cmd/
|
||||||
|
│ └── api/
|
||||||
|
│ └── main.go
|
||||||
|
├── internal/
|
||||||
|
│ ├── config/ # Config loader
|
||||||
|
│ ├── server/ # HTTP server setup + routes binding
|
||||||
|
│ ├── handler/ # HTTP handlers (controller layer)
|
||||||
|
│ ├── service/ # Business logic
|
||||||
|
│ ├── repository/ # DB access layer
|
||||||
|
│ ├── model/ # App/domain models
|
||||||
|
│ └── middleware/ # HTTP middlewares
|
||||||
|
├── pkg/ # Reusable packages independent of business logic
|
||||||
|
│ ├── logger/
|
||||||
|
│ ├── utils/
|
||||||
|
│ └── validator/
|
||||||
|
├── scripts/ # Deployment & build automation
|
||||||
|
└── docs/ # Documentation (incl. swagger)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Development Environment Layout
|
||||||
|
|
||||||
|
### 📋 Prerequisites Setup
|
||||||
|
```bash
|
||||||
|
# Required tools
|
||||||
|
- Go 1.24.4+
|
||||||
|
- PostgreSQL 12+
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- Keycloak Server (optional)
|
||||||
|
|
||||||
|
# Development tools
|
||||||
|
- Air (hot reload)
|
||||||
|
- Swag (Swagger docs)
|
||||||
|
- Make (build automation)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔧 Configuration Files Layout
|
||||||
|
```
|
||||||
|
project-root/
|
||||||
|
├── .env # Environment variables
|
||||||
|
├── .air.toml # Air configuration
|
||||||
|
├── Makefile # Build commands
|
||||||
|
├── docker-compose.yml # Docker services
|
||||||
|
├── Dockerfile # Container image
|
||||||
|
└── .goreleaser.yml # Release configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 API Documentation Layout
|
||||||
|
|
||||||
|
### 🌐 Base URL Structure
|
||||||
|
```
|
||||||
|
http://localhost:8080/api/v1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📖 Endpoint Categories
|
||||||
|
|
||||||
|
#### 🔍 Health & Monitoring
|
||||||
|
- `GET /api/v1/health` - Health check
|
||||||
|
- `GET /api/v1/` - Hello world
|
||||||
|
- `GET /api/v1/metrics` - Application metrics
|
||||||
|
|
||||||
|
#### 🔐 Authentication Endpoints
|
||||||
|
- `POST /api/v1/auth/login` - User login
|
||||||
|
- `POST /api/v1/auth/register` - User registration
|
||||||
|
- `POST /api/v1/auth/refresh` - Token refresh
|
||||||
|
- `POST /api/v1/auth/logout` - User logout
|
||||||
|
|
||||||
|
#### 👤 User Management
|
||||||
|
- `GET /api/v1/users/profile` - Get user profile
|
||||||
|
- `PUT /api/v1/users/profile` - Update user profile
|
||||||
|
- `GET /api/v1/users` - List users (admin)
|
||||||
|
- `GET /api/v1/users/:id` - Get user by ID
|
||||||
|
|
||||||
|
#### 📦 Product Management
|
||||||
|
- `GET /api/v1/products` - List products
|
||||||
|
- `POST /api/v1/products` - Create product
|
||||||
|
- `GET /api/v1/products/:id` - Get product
|
||||||
|
- `PUT /api/v1/products/:id` - Update product
|
||||||
|
- `DELETE /api/v1/products/:id` - Delete product
|
||||||
|
|
||||||
|
#### 🔄 Real-time Features
|
||||||
|
- `GET /api/v1/websocket` - WebSocket connection
|
||||||
|
- `GET /api/v1/webservice` - Web service endpoint
|
||||||
|
|
||||||
|
### 📊 Swagger Documentation
|
||||||
|
- **Interactive UI**: http://localhost:8080/swagger/index.html
|
||||||
|
- **OpenAPI JSON**: http://localhost:8080/swagger/doc.json
|
||||||
|
|
||||||
|
## 🐳 Docker Deployment Layout
|
||||||
|
|
||||||
|
### 🏃 Development Environment
|
||||||
|
```bash
|
||||||
|
# Start all services
|
||||||
|
make docker-run
|
||||||
|
|
||||||
|
# Services included:
|
||||||
|
- PostgreSQL database
|
||||||
|
- API service with hot reload
|
||||||
|
- pgAdmin (database management)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🚀 Production Environment
|
||||||
|
```bash
|
||||||
|
# Build production image
|
||||||
|
docker build -t api-service:prod .
|
||||||
|
|
||||||
|
# Run production container
|
||||||
|
docker run -d \
|
||||||
|
-p 8080:8080 \
|
||||||
|
--env-file .env \
|
||||||
|
--name api-service \
|
||||||
|
api-service:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📦 Docker Compose Services
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: api_service
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
api:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
environment:
|
||||||
|
- BLUEPRINT_DB_HOST=postgres
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
command: air -c .air.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ Development Workflow Layout
|
||||||
|
|
||||||
|
### 🔄 Daily Development Cycle
|
||||||
|
```bash
|
||||||
|
# 1. Start development environment
|
||||||
|
make watch
|
||||||
|
|
||||||
|
# 2. Run tests
|
||||||
|
make test
|
||||||
|
|
||||||
|
# 3. Check code quality
|
||||||
|
make lint
|
||||||
|
|
||||||
|
# 4. Build for production
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🧪 Testing Strategy
|
||||||
|
```
|
||||||
|
tests/
|
||||||
|
├── unit/ # Unit tests
|
||||||
|
├── integration/ # Integration tests
|
||||||
|
├── e2e/ # End-to-end tests
|
||||||
|
└── fixtures/ # Test data
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📊 Monitoring & Logging
|
||||||
|
- **Health Check**: `/api/v1/health`
|
||||||
|
- **Metrics**: Prometheus metrics
|
||||||
|
- **Logging**: Structured JSON logs
|
||||||
|
- **Tracing**: Distributed tracing support
|
||||||
|
|
||||||
|
## 📁 File Structure Detailed Layout
|
||||||
|
|
||||||
|
### 📄 Configuration Files
|
||||||
|
```
|
||||||
|
.env.example # Environment template
|
||||||
|
config/
|
||||||
|
├── config.go # Configuration struct
|
||||||
|
├── config_test.go # Configuration tests
|
||||||
|
└── validation.go # Config validation
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🗄️ Database Layout
|
||||||
|
```
|
||||||
|
database/
|
||||||
|
├── migrations/ # Database migrations
|
||||||
|
├── seeds/ # Seed data
|
||||||
|
├── models/ # GORM models
|
||||||
|
└── repositories/ # Data access layer
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🎯 Handler Layout
|
||||||
|
```
|
||||||
|
handlers/
|
||||||
|
├── auth.go # Authentication handlers
|
||||||
|
├── user.go # User management handlers
|
||||||
|
├── product.go # Product handlers
|
||||||
|
├── health.go # Health check handlers
|
||||||
|
└── middleware/ # HTTP middleware
|
||||||
|
├── auth.go # JWT middleware
|
||||||
|
├── cors.go # CORS middleware
|
||||||
|
└── logger.go # Logging middleware
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🌐 Route Layout
|
||||||
|
```
|
||||||
|
routes/
|
||||||
|
├── v1/
|
||||||
|
│ ├── routes.go # Route definitions
|
||||||
|
│ ├── auth_routes.go # Auth routes
|
||||||
|
│ ├── user_routes.go # User routes
|
||||||
|
│ └── product_routes.go # Product routes
|
||||||
|
└── middleware.go # Route middleware
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Quick Start Commands
|
||||||
|
|
||||||
|
### 🏃 Development
|
||||||
|
```bash
|
||||||
|
# Clone and setup
|
||||||
|
git clone <repo-url>
|
||||||
|
cd api-service
|
||||||
|
cp .env.example .env
|
||||||
|
make docker-run
|
||||||
|
|
||||||
|
# Start development
|
||||||
|
make watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🧪 Testing
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
make all
|
||||||
|
|
||||||
|
# Run specific test
|
||||||
|
make test
|
||||||
|
make itest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🚀 Production
|
||||||
|
```bash
|
||||||
|
# Build and run
|
||||||
|
make build
|
||||||
|
./main.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Performance Monitoring Layout
|
||||||
|
|
||||||
|
### 📈 Metrics Collection
|
||||||
|
- **Request Duration**: Track API response times
|
||||||
|
- **Error Rates**: Monitor error frequencies
|
||||||
|
- **Database Performance**: Query execution times
|
||||||
|
- **Memory Usage**: Application memory consumption
|
||||||
|
|
||||||
|
### 🔍 Health Checks
|
||||||
|
- **Database Connectivity**: PostgreSQL connection status
|
||||||
|
- **External Services**: Keycloak availability
|
||||||
|
- **Resource Usage**: CPU and memory utilization
|
||||||
|
|
||||||
|
## 🎯 Next Steps
|
||||||
|
|
||||||
|
1. **Setup Environment**: Copy `.env.example` to `.env`
|
||||||
|
2. **Start Database**: Run `make docker-run`
|
||||||
|
3. **Start Development**: Run `make watch`
|
||||||
|
4. **Test API**: Visit `http://localhost:8080/swagger/index.html`
|
||||||
|
5. **Run Tests**: Execute `make all`
|
||||||
|
|
||||||
|
## 📞 Support & Resources
|
||||||
|
|
||||||
|
- **Documentation**: Check `/docs` folder
|
||||||
|
- **API Testing**: Use Swagger UI at `/swagger/index.html`
|
||||||
|
- **Database**: Access pgAdmin at `http://localhost:5050`
|
||||||
|
- **Issues**: Create GitHub issues for bugs/features
|
||||||
@@ -1,833 +0,0 @@
|
|||||||
// Code generated by swaggo/swag. DO NOT EDIT.
|
|
||||||
|
|
||||||
package docs
|
|
||||||
|
|
||||||
import "github.com/swaggo/swag"
|
|
||||||
|
|
||||||
const docTemplate = `{
|
|
||||||
"schemes": {{ marshal .Schemes }},
|
|
||||||
"swagger": "2.0",
|
|
||||||
"info": {
|
|
||||||
"description": "{{escape .Description}}",
|
|
||||||
"title": "{{.Title}}",
|
|
||||||
"termsOfService": "http://swagger.io/terms/",
|
|
||||||
"contact": {
|
|
||||||
"name": "API Support",
|
|
||||||
"url": "http://www.swagger.io/support",
|
|
||||||
"email": "support@swagger.io"
|
|
||||||
},
|
|
||||||
"license": {
|
|
||||||
"name": "Apache 2.0",
|
|
||||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
|
||||||
},
|
|
||||||
"version": "{{.Version}}"
|
|
||||||
},
|
|
||||||
"host": "{{.Host}}",
|
|
||||||
"basePath": "{{.BasePath}}",
|
|
||||||
"paths": {
|
|
||||||
"/": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a hello world message",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"root"
|
|
||||||
],
|
|
||||||
"summary": "Hello World endpoint",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Hello world message",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.HelloWorldResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/login": {
|
|
||||||
"post": {
|
|
||||||
"description": "Authenticate user with username and password to receive JWT token",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Login user and get JWT token",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Login credentials",
|
|
||||||
"name": "login",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.LoginRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/me": {
|
|
||||||
"get": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"Bearer": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Get information about the currently authenticated user",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Get current user info",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.User"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/refresh": {
|
|
||||||
"post": {
|
|
||||||
"description": "Refresh the JWT token using a valid refresh token",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Refresh JWT token",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Refresh token",
|
|
||||||
"name": "refresh",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/register": {
|
|
||||||
"post": {
|
|
||||||
"description": "Register a new user account",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Register new user",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Registration data",
|
|
||||||
"name": "register",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"description": "Created",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/example": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a simple message for GET request",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"example"
|
|
||||||
],
|
|
||||||
"summary": "Example GET service",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Example GET response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ExampleGetResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
|
||||||
"description": "Accepts a JSON payload and returns a response with an ID",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"example"
|
|
||||||
],
|
|
||||||
"summary": "Example POST service",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Example POST request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ExamplePostRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Example POST response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ExamplePostResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/products": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a list of products",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Get product",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product GET response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductGetResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
|
||||||
"description": "Creates a new product",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Create product",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Product creation request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductCreateRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"description": "Product created successfully",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductCreateResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/products/{id}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a single product by ID",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Get product by ID",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Product ID",
|
|
||||||
"name": "id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product GET by ID response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductGetByIDResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Product not found",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"put": {
|
|
||||||
"description": "Updates an existing product",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Update product",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Product ID",
|
|
||||||
"name": "id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Product update request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductUpdateRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product updated successfully",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductUpdateResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Product not found",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"delete": {
|
|
||||||
"description": "Deletes a product by ID",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Delete product",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Product ID",
|
|
||||||
"name": "id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product deleted successfully",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductDeleteResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Product not found",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/token/generate": {
|
|
||||||
"post": {
|
|
||||||
"description": "Generate a JWT token for a user",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Token"
|
|
||||||
],
|
|
||||||
"summary": "Generate JWT token",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "User credentials",
|
|
||||||
"name": "token",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.LoginRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/token/generate-direct": {
|
|
||||||
"post": {
|
|
||||||
"description": "Generate a JWT token directly without password verification (for testing)",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Token"
|
|
||||||
],
|
|
||||||
"summary": "Generate token directly",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "User info",
|
|
||||||
"name": "user",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/health": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns the health status of the API service",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"health"
|
|
||||||
],
|
|
||||||
"summary": "Health check endpoint",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Health status",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.HealthResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"definitions": {
|
|
||||||
"models.ErrorResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"code": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ExampleGetResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ExamplePostRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"age",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"age": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ExamplePostResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.HealthResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"details": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.HelloWorldResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.LoginRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"password",
|
|
||||||
"username"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"password": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductCreateRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductCreateResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductDeleteResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductGetByIDResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductGetResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductUpdateRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductUpdateResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.TokenResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"access_token": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"expires_in": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"token_type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.User": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"email": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"role": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
|
||||||
var SwaggerInfo = &swag.Spec{
|
|
||||||
Version: "1.0.0",
|
|
||||||
Host: "localhost:8080",
|
|
||||||
BasePath: "/api/v1",
|
|
||||||
Schemes: []string{"http", "https"},
|
|
||||||
Title: "API Service",
|
|
||||||
Description: "A comprehensive Go API service with Swagger documentation",
|
|
||||||
InfoInstanceName: "swagger",
|
|
||||||
SwaggerTemplate: docTemplate,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
|
||||||
}
|
|
||||||
@@ -1,814 +0,0 @@
|
|||||||
{
|
|
||||||
"schemes": [
|
|
||||||
"http",
|
|
||||||
"https"
|
|
||||||
],
|
|
||||||
"swagger": "2.0",
|
|
||||||
"info": {
|
|
||||||
"description": "A comprehensive Go API service with Swagger documentation",
|
|
||||||
"title": "API Service",
|
|
||||||
"termsOfService": "http://swagger.io/terms/",
|
|
||||||
"contact": {
|
|
||||||
"name": "API Support",
|
|
||||||
"url": "http://www.swagger.io/support",
|
|
||||||
"email": "support@swagger.io"
|
|
||||||
},
|
|
||||||
"license": {
|
|
||||||
"name": "Apache 2.0",
|
|
||||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
|
||||||
},
|
|
||||||
"version": "1.0.0"
|
|
||||||
},
|
|
||||||
"host": "localhost:8080",
|
|
||||||
"basePath": "/api/v1",
|
|
||||||
"paths": {
|
|
||||||
"/": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a hello world message",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"root"
|
|
||||||
],
|
|
||||||
"summary": "Hello World endpoint",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Hello world message",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.HelloWorldResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/login": {
|
|
||||||
"post": {
|
|
||||||
"description": "Authenticate user with username and password to receive JWT token",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Login user and get JWT token",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Login credentials",
|
|
||||||
"name": "login",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.LoginRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/me": {
|
|
||||||
"get": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"Bearer": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Get information about the currently authenticated user",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Get current user info",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.User"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/refresh": {
|
|
||||||
"post": {
|
|
||||||
"description": "Refresh the JWT token using a valid refresh token",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Refresh JWT token",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Refresh token",
|
|
||||||
"name": "refresh",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/auth/register": {
|
|
||||||
"post": {
|
|
||||||
"description": "Register a new user account",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Authentication"
|
|
||||||
],
|
|
||||||
"summary": "Register new user",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Registration data",
|
|
||||||
"name": "register",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"description": "Created",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/example": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a simple message for GET request",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"example"
|
|
||||||
],
|
|
||||||
"summary": "Example GET service",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Example GET response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ExampleGetResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
|
||||||
"description": "Accepts a JSON payload and returns a response with an ID",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"example"
|
|
||||||
],
|
|
||||||
"summary": "Example POST service",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Example POST request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ExamplePostRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Example POST response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ExamplePostResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/products": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a list of products",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Get product",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product GET response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductGetResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
|
||||||
"description": "Creates a new product",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Create product",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "Product creation request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductCreateRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"201": {
|
|
||||||
"description": "Product created successfully",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductCreateResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/products/{id}": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns a single product by ID",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Get product by ID",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Product ID",
|
|
||||||
"name": "id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product GET by ID response",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductGetByIDResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Product not found",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"put": {
|
|
||||||
"description": "Updates an existing product",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Update product",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Product ID",
|
|
||||||
"name": "id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Product update request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductUpdateRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product updated successfully",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductUpdateResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Product not found",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"delete": {
|
|
||||||
"description": "Deletes a product by ID",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"product"
|
|
||||||
],
|
|
||||||
"summary": "Delete product",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Product ID",
|
|
||||||
"name": "id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Product deleted successfully",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ProductDeleteResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Product not found",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/token/generate": {
|
|
||||||
"post": {
|
|
||||||
"description": "Generate a JWT token for a user",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Token"
|
|
||||||
],
|
|
||||||
"summary": "Generate JWT token",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "User credentials",
|
|
||||||
"name": "token",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.LoginRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"description": "Unauthorized",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/token/generate-direct": {
|
|
||||||
"post": {
|
|
||||||
"description": "Generate a JWT token directly without password verification (for testing)",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Token"
|
|
||||||
],
|
|
||||||
"summary": "Generate token directly",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "User info",
|
|
||||||
"name": "user",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.TokenResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad request",
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/health": {
|
|
||||||
"get": {
|
|
||||||
"description": "Returns the health status of the API service",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"health"
|
|
||||||
],
|
|
||||||
"summary": "Health check endpoint",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Health status",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.HealthResponse"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal server error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/models.ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"definitions": {
|
|
||||||
"models.ErrorResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"code": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ExampleGetResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ExamplePostRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"age",
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"age": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ExamplePostResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.HealthResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"details": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timestamp": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.HelloWorldResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.LoginRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"password",
|
|
||||||
"username"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"password": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductCreateRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductCreateResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductDeleteResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductGetByIDResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductGetResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductUpdateRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.ProductUpdateResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.TokenResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"access_token": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"expires_in": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"token_type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"models.User": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"email": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"role": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,534 +0,0 @@
|
|||||||
basePath: /api/v1
|
|
||||||
definitions:
|
|
||||||
models.ErrorResponse:
|
|
||||||
properties:
|
|
||||||
code:
|
|
||||||
type: integer
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.ExampleGetResponse:
|
|
||||||
properties:
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.ExamplePostRequest:
|
|
||||||
properties:
|
|
||||||
age:
|
|
||||||
type: integer
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- age
|
|
||||||
- name
|
|
||||||
type: object
|
|
||||||
models.ExamplePostResponse:
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.HealthResponse:
|
|
||||||
properties:
|
|
||||||
details:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
timestamp:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.HelloWorldResponse:
|
|
||||||
properties:
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
version:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.LoginRequest:
|
|
||||||
properties:
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
username:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- password
|
|
||||||
- username
|
|
||||||
type: object
|
|
||||||
models.ProductCreateRequest:
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- name
|
|
||||||
type: object
|
|
||||||
models.ProductCreateResponse:
|
|
||||||
properties:
|
|
||||||
data: {}
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.ProductDeleteResponse:
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.ProductGetByIDResponse:
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.ProductGetResponse:
|
|
||||||
properties:
|
|
||||||
data: {}
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.ProductUpdateRequest:
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- name
|
|
||||||
type: object
|
|
||||||
models.ProductUpdateResponse:
|
|
||||||
properties:
|
|
||||||
data: {}
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.TokenResponse:
|
|
||||||
properties:
|
|
||||||
access_token:
|
|
||||||
type: string
|
|
||||||
expires_in:
|
|
||||||
type: integer
|
|
||||||
token_type:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
models.User:
|
|
||||||
properties:
|
|
||||||
email:
|
|
||||||
type: string
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
role:
|
|
||||||
type: string
|
|
||||||
username:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
host: localhost:8080
|
|
||||||
info:
|
|
||||||
contact:
|
|
||||||
email: support@swagger.io
|
|
||||||
name: API Support
|
|
||||||
url: http://www.swagger.io/support
|
|
||||||
description: A comprehensive Go API service with Swagger documentation
|
|
||||||
license:
|
|
||||||
name: Apache 2.0
|
|
||||||
url: http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
termsOfService: http://swagger.io/terms/
|
|
||||||
title: API Service
|
|
||||||
version: 1.0.0
|
|
||||||
paths:
|
|
||||||
/:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Returns a hello world message
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Hello world message
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.HelloWorldResponse'
|
|
||||||
summary: Hello World endpoint
|
|
||||||
tags:
|
|
||||||
- root
|
|
||||||
/api/v1/auth/login:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Authenticate user with username and password to receive JWT token
|
|
||||||
parameters:
|
|
||||||
- description: Login credentials
|
|
||||||
in: body
|
|
||||||
name: login
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.LoginRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.TokenResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
summary: Login user and get JWT token
|
|
||||||
tags:
|
|
||||||
- Authentication
|
|
||||||
/api/v1/auth/me:
|
|
||||||
get:
|
|
||||||
description: Get information about the currently authenticated user
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.User'
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
security:
|
|
||||||
- Bearer: []
|
|
||||||
summary: Get current user info
|
|
||||||
tags:
|
|
||||||
- Authentication
|
|
||||||
/api/v1/auth/refresh:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Refresh the JWT token using a valid refresh token
|
|
||||||
parameters:
|
|
||||||
- description: Refresh token
|
|
||||||
in: body
|
|
||||||
name: refresh
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.TokenResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
summary: Refresh JWT token
|
|
||||||
tags:
|
|
||||||
- Authentication
|
|
||||||
/api/v1/auth/register:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Register a new user account
|
|
||||||
parameters:
|
|
||||||
- description: Registration data
|
|
||||||
in: body
|
|
||||||
name: register
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"201":
|
|
||||||
description: Created
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
summary: Register new user
|
|
||||||
tags:
|
|
||||||
- Authentication
|
|
||||||
/api/v1/example:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Returns a simple message for GET request
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Example GET response
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ExampleGetResponse'
|
|
||||||
summary: Example GET service
|
|
||||||
tags:
|
|
||||||
- example
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Accepts a JSON payload and returns a response with an ID
|
|
||||||
parameters:
|
|
||||||
- description: Example POST request
|
|
||||||
in: body
|
|
||||||
name: request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ExamplePostRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Example POST response
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ExamplePostResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
summary: Example POST service
|
|
||||||
tags:
|
|
||||||
- example
|
|
||||||
/api/v1/products:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Returns a list of products
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Product GET response
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductGetResponse'
|
|
||||||
summary: Get product
|
|
||||||
tags:
|
|
||||||
- product
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Creates a new product
|
|
||||||
parameters:
|
|
||||||
- description: Product creation request
|
|
||||||
in: body
|
|
||||||
name: request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductCreateRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"201":
|
|
||||||
description: Product created successfully
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductCreateResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
summary: Create product
|
|
||||||
tags:
|
|
||||||
- product
|
|
||||||
/api/v1/products/{id}:
|
|
||||||
delete:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Deletes a product by ID
|
|
||||||
parameters:
|
|
||||||
- description: Product ID
|
|
||||||
in: path
|
|
||||||
name: id
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Product deleted successfully
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductDeleteResponse'
|
|
||||||
"404":
|
|
||||||
description: Product not found
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
summary: Delete product
|
|
||||||
tags:
|
|
||||||
- product
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Returns a single product by ID
|
|
||||||
parameters:
|
|
||||||
- description: Product ID
|
|
||||||
in: path
|
|
||||||
name: id
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Product GET by ID response
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductGetByIDResponse'
|
|
||||||
"404":
|
|
||||||
description: Product not found
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
summary: Get product by ID
|
|
||||||
tags:
|
|
||||||
- product
|
|
||||||
put:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Updates an existing product
|
|
||||||
parameters:
|
|
||||||
- description: Product ID
|
|
||||||
in: path
|
|
||||||
name: id
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- description: Product update request
|
|
||||||
in: body
|
|
||||||
name: request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductUpdateRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Product updated successfully
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ProductUpdateResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
"404":
|
|
||||||
description: Product not found
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
summary: Update product
|
|
||||||
tags:
|
|
||||||
- product
|
|
||||||
/api/v1/token/generate:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Generate a JWT token for a user
|
|
||||||
parameters:
|
|
||||||
- description: User credentials
|
|
||||||
in: body
|
|
||||||
name: token
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.LoginRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.TokenResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
"401":
|
|
||||||
description: Unauthorized
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
summary: Generate JWT token
|
|
||||||
tags:
|
|
||||||
- Token
|
|
||||||
/api/v1/token/generate-direct:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Generate a JWT token directly without password verification (for
|
|
||||||
testing)
|
|
||||||
parameters:
|
|
||||||
- description: User info
|
|
||||||
in: body
|
|
||||||
name: user
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.TokenResponse'
|
|
||||||
"400":
|
|
||||||
description: Bad request
|
|
||||||
schema:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
summary: Generate token directly
|
|
||||||
tags:
|
|
||||||
- Token
|
|
||||||
/health:
|
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: Returns the health status of the API service
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: Health status
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.HealthResponse'
|
|
||||||
"500":
|
|
||||||
description: Internal server error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/models.ErrorResponse'
|
|
||||||
summary: Health check endpoint
|
|
||||||
tags:
|
|
||||||
- health
|
|
||||||
schemes:
|
|
||||||
- http
|
|
||||||
- https
|
|
||||||
swagger: "2.0"
|
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"api-service/internal/server"
|
"api-service/internal/server"
|
||||||
|
|
||||||
_ "api-service/cmd/api/docs"
|
_ "api-service/docs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title API Service
|
// @title API Service
|
||||||
|
|||||||
335
docs/docs.go
335
docs/docs.go
@@ -24,6 +24,7 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
"host": "{{.Host}}",
|
"host": "{{.Host}}",
|
||||||
"basePath": "{{.BasePath}}",
|
"basePath": "{{.BasePath}}",
|
||||||
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns a hello world message",
|
"description": "Returns a hello world message",
|
||||||
@@ -47,6 +48,196 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/auth/login": {
|
||||||
|
"post": {
|
||||||
|
"description": "Authenticate user with username and password to receive JWT token",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Login user and get JWT token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Login credentials",
|
||||||
|
"name": "login",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.LoginRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/auth/me": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Get information about the currently authenticated user",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Get current user info",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/auth/refresh": {
|
||||||
|
"post": {
|
||||||
|
"description": "Refresh the JWT token using a valid refresh token",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Refresh JWT token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Refresh token",
|
||||||
|
"name": "refresh",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/auth/register": {
|
||||||
|
"post": {
|
||||||
|
"description": "Register a new user account",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Register new user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Registration data",
|
||||||
|
"name": "register",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/example": {
|
"/api/v1/example": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns a simple message for GET request",
|
"description": "Returns a simple message for GET request",
|
||||||
@@ -294,6 +485,104 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/token/generate": {
|
||||||
|
"post": {
|
||||||
|
"description": "Generate a JWT token for a user",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Token"
|
||||||
|
],
|
||||||
|
"summary": "Generate JWT token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User credentials",
|
||||||
|
"name": "token",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.LoginRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/token/generate-direct": {
|
||||||
|
"post": {
|
||||||
|
"description": "Generate a JWT token directly without password verification (for testing)",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Token"
|
||||||
|
],
|
||||||
|
"summary": "Generate token directly",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User info",
|
||||||
|
"name": "user",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/health": {
|
"/health": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns the health status of the API service",
|
"description": "Returns the health status of the API service",
|
||||||
@@ -401,6 +690,21 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.LoginRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"password",
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"password": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.ProductCreateRequest": {
|
"models.ProductCreateRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -477,6 +781,37 @@ const docTemplate = `{
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"models.TokenResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expires_in": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"token_type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"models.User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|||||||
@@ -45,6 +45,196 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/auth/login": {
|
||||||
|
"post": {
|
||||||
|
"description": "Authenticate user with username and password to receive JWT token",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Login user and get JWT token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Login credentials",
|
||||||
|
"name": "login",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.LoginRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/auth/me": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Get information about the currently authenticated user",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Get current user info",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/auth/refresh": {
|
||||||
|
"post": {
|
||||||
|
"description": "Refresh the JWT token using a valid refresh token",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Refresh JWT token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Refresh token",
|
||||||
|
"name": "refresh",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/auth/register": {
|
||||||
|
"post": {
|
||||||
|
"description": "Register a new user account",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Authentication"
|
||||||
|
],
|
||||||
|
"summary": "Register new user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Registration data",
|
||||||
|
"name": "register",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/example": {
|
"/api/v1/example": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns a simple message for GET request",
|
"description": "Returns a simple message for GET request",
|
||||||
@@ -292,6 +482,104 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/token/generate": {
|
||||||
|
"post": {
|
||||||
|
"description": "Generate a JWT token for a user",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Token"
|
||||||
|
],
|
||||||
|
"summary": "Generate JWT token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User credentials",
|
||||||
|
"name": "token",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.LoginRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/token/generate-direct": {
|
||||||
|
"post": {
|
||||||
|
"description": "Generate a JWT token directly without password verification (for testing)",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Token"
|
||||||
|
],
|
||||||
|
"summary": "Generate token directly",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User info",
|
||||||
|
"name": "user",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.TokenResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/health": {
|
"/health": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns the health status of the API service",
|
"description": "Returns the health status of the API service",
|
||||||
@@ -399,6 +687,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.LoginRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"password",
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"password": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.ProductCreateRequest": {
|
"models.ProductCreateRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -475,6 +778,37 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"models.TokenResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expires_in": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"token_type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"models.User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,6 +49,16 @@ definitions:
|
|||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.LoginRequest:
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- password
|
||||||
|
- username
|
||||||
|
type: object
|
||||||
models.ProductCreateRequest:
|
models.ProductCreateRequest:
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
@@ -99,6 +109,26 @@ definitions:
|
|||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.TokenResponse:
|
||||||
|
properties:
|
||||||
|
access_token:
|
||||||
|
type: string
|
||||||
|
expires_in:
|
||||||
|
type: integer
|
||||||
|
token_type:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
models.User:
|
||||||
|
properties:
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
role:
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
host: localhost:8080
|
host: localhost:8080
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
@@ -128,6 +158,129 @@ paths:
|
|||||||
summary: Hello World endpoint
|
summary: Hello World endpoint
|
||||||
tags:
|
tags:
|
||||||
- root
|
- root
|
||||||
|
/api/v1/auth/login:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Authenticate user with username and password to receive JWT token
|
||||||
|
parameters:
|
||||||
|
- description: Login credentials
|
||||||
|
in: body
|
||||||
|
name: login
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.LoginRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.TokenResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
summary: Login user and get JWT token
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
/api/v1/auth/me:
|
||||||
|
get:
|
||||||
|
description: Get information about the currently authenticated user
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.User'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get current user info
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
/api/v1/auth/refresh:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Refresh the JWT token using a valid refresh token
|
||||||
|
parameters:
|
||||||
|
- description: Refresh token
|
||||||
|
in: body
|
||||||
|
name: refresh
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.TokenResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
summary: Refresh JWT token
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
/api/v1/auth/register:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Register a new user account
|
||||||
|
parameters:
|
||||||
|
- description: Registration data
|
||||||
|
in: body
|
||||||
|
name: register
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
summary: Register new user
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
/api/v1/example:
|
/api/v1/example:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
@@ -291,6 +444,71 @@ paths:
|
|||||||
summary: Update product
|
summary: Update product
|
||||||
tags:
|
tags:
|
||||||
- product
|
- product
|
||||||
|
/api/v1/token/generate:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Generate a JWT token for a user
|
||||||
|
parameters:
|
||||||
|
- description: User credentials
|
||||||
|
in: body
|
||||||
|
name: token
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.LoginRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.TokenResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
summary: Generate JWT token
|
||||||
|
tags:
|
||||||
|
- Token
|
||||||
|
/api/v1/token/generate-direct:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Generate a JWT token directly without password verification (for
|
||||||
|
testing)
|
||||||
|
parameters:
|
||||||
|
- description: User info
|
||||||
|
in: body
|
||||||
|
name: user
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.TokenResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad request
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
summary: Generate token directly
|
||||||
|
tags:
|
||||||
|
- Token
|
||||||
/health:
|
/health:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"api-service/internal/models"
|
models "api-service/internal/models/auth"
|
||||||
"api-service/internal/services"
|
services "api-service/internal/services/auth"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"api-service/internal/models"
|
models "api-service/internal/models/auth"
|
||||||
"api-service/internal/services"
|
services "api-service/internal/services/auth"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
121
internal/handlers/employee/employee.go
Normal file
121
internal/handlers/employee/employee.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"api-service/internal/models/employee"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EmployeeHandler handles employee services
|
||||||
|
type EmployeeHandler struct{}
|
||||||
|
|
||||||
|
// NewEmployeeHandler creates a new EmployeeHandler
|
||||||
|
func NewEmployeeHandler() *EmployeeHandler {
|
||||||
|
return &%!s(MISSING)Handler{}
|
||||||
|
}
|
||||||
|
// GetEmployee godoc
|
||||||
|
// @Summary Get employee
|
||||||
|
// @Description Returns a list of employees
|
||||||
|
// @Tags employee
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} employee.EmployeeGetResponse "Employee GET response"
|
||||||
|
// @Router /api/v1/employees [get]
|
||||||
|
func (h *EmployeeHandler) GetEmployee(c *gin.Context) {
|
||||||
|
response := employee.EmployeeGetResponse{
|
||||||
|
Message: "List of Employee",
|
||||||
|
Data: []string{"Employee 1", "Employee 2"},
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetemployeeByID godoc
|
||||||
|
// @Summary Get employee by ID
|
||||||
|
// @Description Returns a single employee by ID
|
||||||
|
// @Tags Employee
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "employee ID"
|
||||||
|
// @Success 200 {object} Employee.EmployeeGetByIDResponse "employee GET by ID response"
|
||||||
|
// @Failure 404 {object} Employee.ErrorResponse "Employee not found"
|
||||||
|
// @Router /api/v1/employee/{id} [get]
|
||||||
|
func (h *EmployeeHandler) GetemployeeByID(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
response := Employee.%!s(MISSING)GetByIDResponse{
|
||||||
|
ID: id,
|
||||||
|
Message: "%!s(MISSING) details",
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
// CreateEmployee godoc
|
||||||
|
// @Summary Create employee
|
||||||
|
// @Description Creates a new employee
|
||||||
|
// @Tags employee
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body employee.EmployeeCreateRequest true "Employee creation request"
|
||||||
|
// @Success 201 {object} employee.EmployeeCreateResponse "Employee created successfully"
|
||||||
|
// @Failure 400 {object} employee.ErrorResponse "Bad request"
|
||||||
|
// @Router /api/v1/Employee [post]
|
||||||
|
func (h *EmployeeHandler) Createemployee(c *gin.Context) {
|
||||||
|
var req Employee.EmployeeCreateRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := %!s(MISSING).%!s(MISSING)CreateResponse{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
Message: "%!s(MISSING) created successfully",
|
||||||
|
Data: req,
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusCreated, response)
|
||||||
|
}
|
||||||
|
// UpdateEmployee godoc
|
||||||
|
// @Summary Update employee
|
||||||
|
// @Description Updates an existing employee
|
||||||
|
// @Tags employee
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Employee ID"
|
||||||
|
// @Param request body employee.EmployeeUpdateRequest true "Employee update request"
|
||||||
|
// @Success 200 {object} Employee.employeeUpdateResponse "Employee updated successfully"
|
||||||
|
// @Failure 400 {object} employee.ErrorResponse "Bad request"
|
||||||
|
// @Failure 404 {object} Employee.ErrorResponse "employee not found"
|
||||||
|
// @Router /api/v1/Employee/{id} [put]
|
||||||
|
func (h *EmployeeHandler) UpdateEmployee(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
var req Employee.%!s(MISSING)UpdateRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := %!s(MISSING).%!s(MISSING)UpdateResponse{
|
||||||
|
ID: id,
|
||||||
|
Message: "%!s(MISSING) updated successfully",
|
||||||
|
Data: req,
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
// DeleteEmployee godoc
|
||||||
|
// @Summary Delete employee
|
||||||
|
// @Description Deletes a employee by ID
|
||||||
|
// @Tags employee
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Employee ID"
|
||||||
|
// @Success 200 {object} employee.EmployeeDeleteResponse "Employee deleted successfully"
|
||||||
|
// @Failure 404 {object} employee.ErrorResponse "Employee not found"
|
||||||
|
// @Router /api/v1/Employee/{id} [delete]
|
||||||
|
func (h *employeeHandler) DeleteEmployee(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
response := Employee.%!s(MISSING)DeleteResponse{
|
||||||
|
ID: id,
|
||||||
|
Message: "%!s(MISSING) deleted successfully",
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"api-service/internal/services"
|
services "api-service/internal/services/auth"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|||||||
46
internal/models/employee/employee.go
Normal file
46
internal/models/employee/employee.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package employee
|
||||||
|
|
||||||
|
// EmployeeGetResponse represents the response for GET employees
|
||||||
|
type EmployeeGetResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmployeeGetByIDResponse represents the response for GET employee by ID
|
||||||
|
type EmployeeGetByIDResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
%!(EXTRA string=employee, string=Employee)// EmployeeCreateRequest represents the request for creating employee
|
||||||
|
type EmployeeCreateRequest struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
// Add more fields as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// employeeCreateResponse represents the response for creating Employee
|
||||||
|
type employeeCreateResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
%!(EXTRA string=Employee)// EmployeeUpdateRequest represents the request for updating employee
|
||||||
|
type EmployeeUpdateRequest struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
// Add more fields as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// employeeUpdateResponse represents the response for updating Employee
|
||||||
|
type employeeUpdateResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
%!(EXTRA string=Employee)// EmployeeDeleteResponse represents the response for deleting employee
|
||||||
|
type EmployeeDeleteResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
%!(EXTRA string=employee)// ErrorResponse represents an error response
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
42
internal/models/product/product.go
Normal file
42
internal/models/product/product.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Product represents the product domain model
|
||||||
|
type Product struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Price float64 `json:"price"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductCreateRequest represents the request for creating a product
|
||||||
|
type ProductCreateRequest struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Price float64 `json:"price" binding:"required,gt=0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductUpdateRequest represents the request for updating a product
|
||||||
|
type ProductUpdateRequest struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Price float64 `json:"price" binding:"required,gt=0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductResponse represents the response for product operations
|
||||||
|
type ProductResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Price float64 `json:"price"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProductsResponse represents the response for listing products
|
||||||
|
type ProductsResponse struct {
|
||||||
|
Data []*Product `json:"data"`
|
||||||
|
}
|
||||||
131
internal/repository/product/product_repository.go
Normal file
131
internal/repository/product/product_repository.go
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package product
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
model "api-service/internal/models/product"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Repository defines the interface for product data operations
|
||||||
|
type Repository interface {
|
||||||
|
Create(ctx context.Context, product *model.Product) error
|
||||||
|
GetByID(ctx context.Context, id string) (*model.Product, error)
|
||||||
|
GetAll(ctx context.Context) ([]*model.Product, error)
|
||||||
|
Update(ctx context.Context, product *model.Product) error
|
||||||
|
Delete(ctx context.Context, id string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// repository implements the Repository interface
|
||||||
|
type repository struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRepository creates a new product repository
|
||||||
|
func NewRepository(db *sql.DB) Repository {
|
||||||
|
return &repository{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create adds a new product to the database
|
||||||
|
func (r *repository) Create(ctx context.Context, product *model.Product) error {
|
||||||
|
query := `
|
||||||
|
INSERT INTO products (id, name, description, price, created_at, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := r.db.ExecContext(ctx, query,
|
||||||
|
product.ID,
|
||||||
|
product.Name,
|
||||||
|
product.Description,
|
||||||
|
product.Price,
|
||||||
|
product.CreatedAt,
|
||||||
|
product.UpdatedAt,
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByID retrieves a product by its ID
|
||||||
|
func (r *repository) GetByID(ctx context.Context, id string) (*model.Product, error) {
|
||||||
|
query := `
|
||||||
|
SELECT id, name, description, price, created_at, updated_at
|
||||||
|
FROM products
|
||||||
|
WHERE id = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
var product model.Product
|
||||||
|
err := r.db.QueryRowContext(ctx, query, id).Scan(
|
||||||
|
&product.ID,
|
||||||
|
&product.Name,
|
||||||
|
&product.Description,
|
||||||
|
&product.Price,
|
||||||
|
&product.CreatedAt,
|
||||||
|
&product.UpdatedAt,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &product, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAll retrieves all products
|
||||||
|
func (r *repository) GetAll(ctx context.Context) ([]*model.Product, error) {
|
||||||
|
query := `
|
||||||
|
SELECT id, name, description, price, created_at, updated_at
|
||||||
|
FROM products
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := r.db.QueryContext(ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var products []*model.Product
|
||||||
|
for rows.Next() {
|
||||||
|
var product model.Product
|
||||||
|
err := rows.Scan(
|
||||||
|
&product.ID,
|
||||||
|
&product.Name,
|
||||||
|
&product.Description,
|
||||||
|
&product.Price,
|
||||||
|
&product.CreatedAt,
|
||||||
|
&product.UpdatedAt,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
products = append(products, &product)
|
||||||
|
}
|
||||||
|
|
||||||
|
return products, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing product
|
||||||
|
func (r *repository) Update(ctx context.Context, product *model.Product) error {
|
||||||
|
query := `
|
||||||
|
UPDATE products
|
||||||
|
SET name = ?, description = ?, price = ?, updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err := r.db.ExecContext(ctx, query,
|
||||||
|
product.Name,
|
||||||
|
product.Description,
|
||||||
|
product.Price,
|
||||||
|
product.UpdatedAt,
|
||||||
|
product.ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a product from the database
|
||||||
|
func (r *repository) Delete(ctx context.Context, id string) error {
|
||||||
|
query := `DELETE FROM products WHERE id = ?`
|
||||||
|
_, err := r.db.ExecContext(ctx, query, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"api-service/internal/config"
|
"api-service/internal/config"
|
||||||
"api-service/internal/handlers"
|
authHandlers "api-service/internal/handlers/auth"
|
||||||
|
componentHandlers "api-service/internal/handlers/component"
|
||||||
|
employeeHandlers "api-service/internal/handlers/employee"
|
||||||
"api-service/internal/middleware"
|
"api-service/internal/middleware"
|
||||||
"api-service/internal/services"
|
services "api-service/internal/services/auth"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
@@ -34,13 +36,13 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
|
|||||||
{
|
{
|
||||||
// Public routes (no authentication required)
|
// Public routes (no authentication required)
|
||||||
// Health endpoints
|
// Health endpoints
|
||||||
healthHandler := handlers.NewHealthHandler()
|
healthHandler := componentHandlers.NewHealthHandler()
|
||||||
v1.GET("/health", healthHandler.GetHealth)
|
v1.GET("/health", healthHandler.GetHealth)
|
||||||
v1.GET("/", healthHandler.HelloWorld)
|
v1.GET("/", healthHandler.HelloWorld)
|
||||||
|
|
||||||
// Authentication routes
|
// Authentication routes
|
||||||
authHandler := handlers.NewAuthHandler(authService)
|
authHandler := authHandlers.NewAuthHandler(authService)
|
||||||
tokenHandler := handlers.NewTokenHandler(authService)
|
tokenHandler := authHandlers.NewTokenHandler(authService)
|
||||||
|
|
||||||
v1.POST("/auth/login", authHandler.Login)
|
v1.POST("/auth/login", authHandler.Login)
|
||||||
v1.POST("/auth/register", authHandler.Register)
|
v1.POST("/auth/register", authHandler.Register)
|
||||||
@@ -52,11 +54,20 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
|
|||||||
v1.POST("/token/generate-direct", tokenHandler.GenerateTokenDirect)
|
v1.POST("/token/generate-direct", tokenHandler.GenerateTokenDirect)
|
||||||
|
|
||||||
// Protected routes (require authentication)
|
// Protected routes (require authentication)
|
||||||
|
|
||||||
|
// Employee endpoints
|
||||||
|
employeeHandler := employeeHandlers.NewEmployeeHandler()
|
||||||
|
v1.GET("/employees", employeeHandler.GetEmployee)
|
||||||
|
v1.GET("/employees/:id", employeeHandler.GetEmployeeByID)
|
||||||
|
v1.POST("/employees", employeeHandler.CreateEmployee)
|
||||||
|
v1.PUT("/employees/:id", employeeHandler.UpdateEmployee)
|
||||||
|
v1.DELETE("/employees/:id", employeeHandler.DeleteEmployee)
|
||||||
|
|
||||||
protected := v1.Group("/")
|
protected := v1.Group("/")
|
||||||
protected.Use(middleware.JWTAuthMiddleware(authService))
|
protected.Use(middleware.JWTAuthMiddleware(authService))
|
||||||
{
|
{
|
||||||
// Product endpoints
|
// Product endpoints
|
||||||
productHandler := handlers.NewProductHandler()
|
productHandler := componentHandlers.NewProductHandler()
|
||||||
protected.GET("/products", productHandler.GetProduct)
|
protected.GET("/products", productHandler.GetProduct)
|
||||||
protected.GET("/products/:id", productHandler.GetProductByID)
|
protected.GET("/products/:id", productHandler.GetProductByID)
|
||||||
protected.POST("/products", productHandler.CreateProduct)
|
protected.POST("/products", productHandler.CreateProduct)
|
||||||
@@ -64,7 +75,7 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
|
|||||||
protected.DELETE("/products/:id", productHandler.DeleteProduct)
|
protected.DELETE("/products/:id", productHandler.DeleteProduct)
|
||||||
|
|
||||||
// Example endpoints
|
// Example endpoints
|
||||||
exampleHandler := handlers.NewExampleHandler()
|
exampleHandler := componentHandlers.NewExampleHandler()
|
||||||
protected.GET("/example", exampleHandler.GetExample)
|
protected.GET("/example", exampleHandler.GetExample)
|
||||||
protected.POST("/example", exampleHandler.PostExample)
|
protected.POST("/example", exampleHandler.PostExample)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"api-service/internal/config"
|
"api-service/internal/config"
|
||||||
"api-service/internal/models"
|
models "api-service/internal/models/auth"
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
141
internal/services/product/product_service.go
Normal file
141
internal/services/product/product_service.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package product
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
model "api-service/internal/models/product"
|
||||||
|
"api-service/internal/repository/product"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service defines the interface for product business logic
|
||||||
|
type Service interface {
|
||||||
|
CreateProduct(ctx context.Context, req *model.ProductCreateRequest) (*model.ProductResponse, error)
|
||||||
|
GetProduct(ctx context.Context, id string) (*model.ProductResponse, error)
|
||||||
|
GetAllProducts(ctx context.Context) (*model.ProductsResponse, error)
|
||||||
|
UpdateProduct(ctx context.Context, id string, req *model.ProductUpdateRequest) (*model.ProductResponse, error)
|
||||||
|
DeleteProduct(ctx context.Context, id string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// service implements the Service interface
|
||||||
|
type service struct {
|
||||||
|
repo product.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new product service
|
||||||
|
func NewService(repo product.Repository) Service {
|
||||||
|
return &service{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProduct creates a new product
|
||||||
|
func (s *service) CreateProduct(ctx context.Context, req *model.ProductCreateRequest) (*model.ProductResponse, error) {
|
||||||
|
if req.Name == "" {
|
||||||
|
return nil, errors.New("product name is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Price <= 0 {
|
||||||
|
return nil, errors.New("product price must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
product := &model.Product{
|
||||||
|
ID: generateID(),
|
||||||
|
Name: req.Name,
|
||||||
|
Description: req.Description,
|
||||||
|
Price: req.Price,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.repo.Create(ctx, product)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.ProductResponse{
|
||||||
|
ID: product.ID,
|
||||||
|
Name: product.Name,
|
||||||
|
Description: product.Description,
|
||||||
|
Price: product.Price,
|
||||||
|
CreatedAt: product.CreatedAt,
|
||||||
|
UpdatedAt: product.UpdatedAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProduct retrieves a product by ID
|
||||||
|
func (s *service) GetProduct(ctx context.Context, id string) (*model.ProductResponse, error) {
|
||||||
|
if id == "" {
|
||||||
|
return nil, errors.New("product ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
product, err := s.repo.GetByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.ProductResponse{
|
||||||
|
ID: product.ID,
|
||||||
|
Name: product.Name,
|
||||||
|
Description: product.Description,
|
||||||
|
Price: product.Price,
|
||||||
|
CreatedAt: product.CreatedAt,
|
||||||
|
UpdatedAt: product.UpdatedAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllProducts retrieves all products
|
||||||
|
func (s *service) GetAllProducts(ctx context.Context) (*model.ProductsResponse, error) {
|
||||||
|
products, err := s.repo.GetAll(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.ProductsResponse{
|
||||||
|
Data: products,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateProduct updates an existing product
|
||||||
|
func (s *service) UpdateProduct(ctx context.Context, id string, req *model.ProductUpdateRequest) (*model.ProductResponse, error) {
|
||||||
|
if id == "" {
|
||||||
|
return nil, errors.New("product ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
existingProduct, err := s.repo.GetByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
existingProduct.Name = req.Name
|
||||||
|
existingProduct.Description = req.Description
|
||||||
|
existingProduct.Price = req.Price
|
||||||
|
existingProduct.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
err = s.repo.Update(ctx, existingProduct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.ProductResponse{
|
||||||
|
ID: existingProduct.ID,
|
||||||
|
Name: existingProduct.Name,
|
||||||
|
Description: existingProduct.Description,
|
||||||
|
Price: existingProduct.Price,
|
||||||
|
CreatedAt: existingProduct.CreatedAt,
|
||||||
|
UpdatedAt: existingProduct.UpdatedAt,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProduct deletes a product
|
||||||
|
func (s *service) DeleteProduct(ctx context.Context, id string) error {
|
||||||
|
if id == "" {
|
||||||
|
return errors.New("product ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.repo.Delete(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
func generateID() string {
|
||||||
|
return "prod_" + time.Now().Format("20060102150405")
|
||||||
|
}
|
||||||
@@ -27,10 +27,11 @@ generate.bat product get post put delete
|
|||||||
### Langsung dengan Go
|
### Langsung dengan Go
|
||||||
```bash
|
```bash
|
||||||
# Dari root project
|
# Dari root project
|
||||||
# .. run tools/generate-handler.go : Perintahnya
|
go run tools/generate-handler.go <nama-handler> [methods]
|
||||||
# .. user nama module nya dan handlernya
|
|
||||||
# .. get post put delete metod yang di gunakan
|
# Contoh:
|
||||||
go run tools/generate-handler.go user get post put delete
|
go run tools/generate-handler.go user get post put delete
|
||||||
|
go run tools/generate-handler.go product get post
|
||||||
```
|
```
|
||||||
|
|
||||||
## Method yang Tersedia
|
## Method yang Tersedia
|
||||||
@@ -41,9 +42,11 @@ go run tools/generate-handler.go user get post put delete
|
|||||||
|
|
||||||
## File yang Dibuat Otomatis
|
## File yang Dibuat Otomatis
|
||||||
|
|
||||||
1. **Handler**: `internal/handlers/<nama>.go`
|
1. **Handler**: `internal/handlers/<nama>/<nama>.go`
|
||||||
2. **Models**: `internal/models/<nama>.go`
|
2. **Models**: `internal/models/<nama>/<nama>.go`
|
||||||
3. **Routes**: Update otomatis di `internal/routes/v1/routes.go`
|
3. **Routes**: Update otomatis di `internal/routes/v1/routes.go`
|
||||||
|
- **<nama>**: `Nama Directori`
|
||||||
|
- **<nama>.go**: `Nama file class`
|
||||||
|
|
||||||
## Contoh Penggunaan
|
## Contoh Penggunaan
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ go run tools/generate-handler.go user get post put delete
|
|||||||
|
|
||||||
1. Jalankan swagger generator:
|
1. Jalankan swagger generator:
|
||||||
```bash
|
```bash
|
||||||
swag init -g cmd/api/main.go --output cmd/api/docs
|
swag init -g cmd/api/main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Jalankan aplikasi:
|
2. Jalankan aplikasi:
|
||||||
@@ -81,20 +84,23 @@ http://localhost:8080/swagger/index.html
|
|||||||
|
|
||||||
## Struktur File yang Dibuat
|
## Struktur File yang Dibuat
|
||||||
|
|
||||||
### Handler File (`internal/handlers/<nama>.go`)
|
### Handler File (`internal/handlers/<nama>/<nama>.go`)
|
||||||
- Struct handler
|
- Struct handler
|
||||||
- Constructor function
|
- Constructor function
|
||||||
- Endpoint methods dengan swagger documentation
|
- Endpoint methods dengan swagger documentation
|
||||||
- Error handling
|
- Error handling
|
||||||
|
- Import models dari `api-service/internal/models/<nama>`
|
||||||
|
|
||||||
### Model File (`internal/models/<nama>.go`)
|
### Model File (`internal/models/<nama>/<nama>.go`)
|
||||||
- Request models
|
- Request models
|
||||||
- Response models
|
- Response models
|
||||||
- Error response models
|
- Error response models
|
||||||
|
- Package name sesuai dengan nama handler
|
||||||
|
|
||||||
### Routes Update
|
### Routes Update
|
||||||
- Otomatis menambahkan routes ke `/api/v1/<nama-plural>`
|
- Otomatis menambahkan routes ke `/api/v1/<nama-plural>`
|
||||||
- Support parameter ID untuk endpoint spesifik
|
- Support parameter ID untuk endpoint spesifik
|
||||||
|
- Menggunakan componentHandlers untuk handler baru
|
||||||
|
|
||||||
## Contoh Output
|
## Contoh Output
|
||||||
|
|
||||||
@@ -105,7 +111,38 @@ Untuk command: `./generate.sh user get post`
|
|||||||
- `GET /api/v1/users/:id` - Get user by ID
|
- `GET /api/v1/users/:id` - Get user by ID
|
||||||
- `POST /api/v1/users` - Create new user
|
- `POST /api/v1/users` - Create new user
|
||||||
|
|
||||||
|
### Struktur Direktori:
|
||||||
|
```
|
||||||
|
internal/
|
||||||
|
├── handlers/
|
||||||
|
│ └── user/
|
||||||
|
│ └── user.go
|
||||||
|
├── models/
|
||||||
|
│ └── user/
|
||||||
|
│ └── user.go
|
||||||
|
```
|
||||||
|
|
||||||
### Swagger Documentation
|
### Swagger Documentation
|
||||||
Semua endpoint otomatis memiliki swagger documentation yang bisa diakses di:
|
Semua endpoint otomatis memiliki swagger documentation yang bisa diakses di:
|
||||||
```
|
```
|
||||||
http://localhost:8080/swagger/index.html
|
http://localhost:8080/swagger/index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips Penggunaan
|
||||||
|
|
||||||
|
1. **Nama Handler**: Gunakan nama singular (user, product, order)
|
||||||
|
2. **Method**: Pilih method sesuai kebutuhan CRUD
|
||||||
|
3. **Custom Fields**: Edit file models yang dibuat untuk menambahkan custom fields
|
||||||
|
4. **Service Layer**: Tambahkan service layer untuk business logic yang kompleks
|
||||||
|
5. **Repository Layer**: Tambahkan repository layer untuk database operations
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Jika generate gagal:
|
||||||
|
- Pastikan berada di root project
|
||||||
|
- Pastikan file `internal/routes/v1/routes.go` ada
|
||||||
|
- Pastikan permission untuk menulis file
|
||||||
|
|
||||||
|
### Jika routes tidak muncul:
|
||||||
|
- Cek file `internal/routes/v1/routes.go` untuk duplikasi nama handler
|
||||||
|
- Pastikan tidak ada nama handler yang sama dengan yang sudah ada
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,9 +26,9 @@ type HandlerData struct {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
fmt.Println("Usage: go run generate-handler.go <handler-name> [methods]")
|
fmt.Println("Usage: go run generate-handler.go <nama-handler> [methods]")
|
||||||
fmt.Println("Example: go run generate-handler.go user get post put delete")
|
fmt.Println("Example: go run generate-handler.go user get post put delete")
|
||||||
fmt.Println("Methods: get, post, put, delete (optional, default: get post)")
|
fmt.Println("Example: go run generate-handler.go product get post")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,217 +71,267 @@ func main() {
|
|||||||
|
|
||||||
fmt.Printf("Generating handler: %s with methods: %v\n", handlerName, methods)
|
fmt.Printf("Generating handler: %s with methods: %v\n", handlerName, methods)
|
||||||
|
|
||||||
|
// Create directories with proper structure
|
||||||
|
handlerDir := filepath.Join("internal", "handlers", handlerLower)
|
||||||
|
modelDir := filepath.Join("internal", "models", handlerLower)
|
||||||
|
|
||||||
// Create directories if they don't exist
|
// Create directories if they don't exist
|
||||||
os.MkdirAll("internal/handlers", 0755)
|
dirs := []string{
|
||||||
os.MkdirAll("internal/models", 0755)
|
handlerDir,
|
||||||
|
modelDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dir := range dirs {
|
||||||
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
fmt.Printf("Error creating directory %s: %v\n", dir, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Created directory: %s\n", dir)
|
||||||
|
}
|
||||||
|
|
||||||
// Generate files
|
// Generate files
|
||||||
generateHandlerFile(data)
|
generateHandlerFile(data, handlerDir)
|
||||||
generateModelFile(data)
|
generateModelFile(data, modelDir)
|
||||||
updateRoutesFile(data)
|
updateRoutesFile(data)
|
||||||
|
|
||||||
fmt.Printf("Successfully generated handler: %s\n", handlerName)
|
fmt.Printf("Successfully generated handler: %s\n", handlerName)
|
||||||
fmt.Println("Don't forget to run: swag init -g cmd/api/main.go")
|
fmt.Println("Don't forget to:")
|
||||||
|
fmt.Println("1. Run: swag init -g cmd/api/main.go")
|
||||||
|
fmt.Println("2. Update your service layer if needed")
|
||||||
|
fmt.Println("3. Add repository layer if required")
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateHandlerFile(data HandlerData) {
|
func generateHandlerFile(data HandlerData, handlerDir string) {
|
||||||
handlerTemplate := `package handlers
|
handlerContent := fmt.Sprintf(`package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
"{{.ModuleName}}/internal/models"
|
"api-service/internal/models/%s"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// {{.Name}}Handler handles {{.NameLower}} services
|
// %sHandler handles %s services
|
||||||
type {{.Name}}Handler struct{}
|
type %sHandler struct{}
|
||||||
|
|
||||||
// New{{.Name}}Handler creates a new {{.Name}}Handler
|
// New%sHandler creates a new %sHandler
|
||||||
func New{{.Name}}Handler() *{{.Name}}Handler {
|
func New%sHandler() *%sHandler {
|
||||||
return &{{.Name}}Handler{}
|
return &%sHandler{}
|
||||||
}
|
}`, data.NameLower, data.Name, data.NameLower, data.Name, data.Name, data.Name, data.Name, data.Name)
|
||||||
{{if .HasGet}}
|
|
||||||
// Get{{.Name}} godoc
|
// Add methods based on requested operations
|
||||||
// @Summary Get {{.NameLower}}
|
var methodsContent string
|
||||||
// @Description Returns a list of {{.NamePlural}}
|
|
||||||
// @Tags {{.NameLower}}
|
if data.HasGet {
|
||||||
|
methodsContent += fmt.Sprintf(`
|
||||||
|
// Get%s godoc
|
||||||
|
// @Summary Get %s
|
||||||
|
// @Description Returns a list of %s
|
||||||
|
// @Tags %s
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} models.{{.Name}}GetResponse "{{.Name}} GET response"
|
// @Success 200 {object} %s.%sGetResponse "%s GET response"
|
||||||
// @Router /api/v1/{{.NamePlural}} [get]
|
// @Router /api/v1/%s [get]
|
||||||
func (h *{{.Name}}Handler) Get{{.Name}}(c *gin.Context) {
|
func (h *%sHandler) Get%s(c *gin.Context) {
|
||||||
response := models.{{.Name}}GetResponse{
|
response := %s.%sGetResponse{
|
||||||
Message: "List of {{.NamePlural}}",
|
Message: "List of %s",
|
||||||
Data: []string{"{{.Name}} 1", "{{.Name}} 2"},
|
Data: []string{"%s 1", "%s 2"},
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}
|
||||||
{{end}}
|
|
||||||
{{if .HasGet}}
|
// Get%sByID godoc
|
||||||
// Get{{.Name}}ByID godoc
|
// @Summary Get %s by ID
|
||||||
// @Summary Get {{.NameLower}} by ID
|
// @Description Returns a single %s by ID
|
||||||
// @Description Returns a single {{.NameLower}} by ID
|
// @Tags %s
|
||||||
// @Tags {{.NameLower}}
|
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path string true "{{.Name}} ID"
|
// @Param id path string true "%s ID"
|
||||||
// @Success 200 {object} models.{{.Name}}GetByIDResponse "{{.Name}} GET by ID response"
|
// @Success 200 {object} %s.%sGetByIDResponse "%s GET by ID response"
|
||||||
// @Failure 404 {object} models.ErrorResponse "{{.Name}} not found"
|
// @Failure 404 {object} %s.ErrorResponse "%s not found"
|
||||||
// @Router /api/v1/{{.NamePlural}}/{id} [get]
|
// @Router /api/v1/%s/{id} [get]
|
||||||
func (h *{{.Name}}Handler) Get{{.Name}}ByID(c *gin.Context) {
|
func (h *%sHandler) Get%sByID(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
response := models.{{.Name}}GetByIDResponse{
|
response := %s.%sGetByIDResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
Message: "{{.Name}} details",
|
Message: "%s details",
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}`,
|
||||||
{{end}}
|
data.Name, data.NameLower, data.NamePlural, data.NameLower,
|
||||||
{{if .HasPost}}
|
data.NameLower, data.Name, data.Name, data.NamePlural,
|
||||||
// Create{{.Name}} godoc
|
data.Name, data.Name, data.NameLower, data.Name, data.Name, data.Name,
|
||||||
// @Summary Create {{.NameLower}}
|
data.Name, data.NameLower, data.NameLower, data.NameLower,
|
||||||
// @Description Creates a new {{.NameLower}}
|
data.Name, data.NameLower, data.Name, data.Name, data.NameLower,
|
||||||
// @Tags {{.NameLower}}
|
data.Name, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.HasPost {
|
||||||
|
methodsContent += fmt.Sprintf(`
|
||||||
|
// Create%s godoc
|
||||||
|
// @Summary Create %s
|
||||||
|
// @Description Creates a new %s
|
||||||
|
// @Tags %s
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param request body models.{{.Name}}CreateRequest true "{{.Name}} creation request"
|
// @Param request body %s.%sCreateRequest true "%s creation request"
|
||||||
// @Success 201 {object} models.{{.Name}}CreateResponse "{{.Name}} created successfully"
|
// @Success 201 {object} %s.%sCreateResponse "%s created successfully"
|
||||||
// @Failure 400 {object} models.ErrorResponse "Bad request"
|
// @Failure 400 {object} %s.ErrorResponse "Bad request"
|
||||||
// @Router /api/v1/{{.NamePlural}} [post]
|
// @Router /api/v1/%s [post]
|
||||||
func (h *{{.Name}}Handler) Create{{.Name}}(c *gin.Context) {
|
func (h *%sHandler) Create%s(c *gin.Context) {
|
||||||
var req models.{{.Name}}CreateRequest
|
var req %s.%sCreateRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := models.{{.Name}}CreateResponse{
|
response := %s.%sCreateResponse{
|
||||||
ID: uuid.NewString(),
|
ID: uuid.NewString(),
|
||||||
Message: "{{.Name}} created successfully",
|
Message: "%s created successfully",
|
||||||
Data: req,
|
Data: req,
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusCreated, response)
|
c.JSON(http.StatusCreated, response)
|
||||||
}
|
}`,
|
||||||
{{end}}
|
data.Name, data.NameLower, data.NameLower, data.NameLower,
|
||||||
{{if .HasPut}}
|
data.NameLower, data.Name, data.Name, data.NameLower, data.Name,
|
||||||
// Update{{.Name}} godoc
|
data.Name, data.NameLower, data.Name, data.Name, data.NameLower,
|
||||||
// @Summary Update {{.NameLower}}
|
data.Name, data.Name)
|
||||||
// @Description Updates an existing {{.NameLower}}
|
}
|
||||||
// @Tags {{.NameLower}}
|
|
||||||
|
if data.HasPut {
|
||||||
|
methodsContent += fmt.Sprintf(`
|
||||||
|
// Update%s godoc
|
||||||
|
// @Summary Update %s
|
||||||
|
// @Description Updates an existing %s
|
||||||
|
// @Tags %s
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path string true "{{.Name}} ID"
|
// @Param id path string true "%s ID"
|
||||||
// @Param request body models.{{.Name}}UpdateRequest true "{{.Name}} update request"
|
// @Param request body %s.%sUpdateRequest true "%s update request"
|
||||||
// @Success 200 {object} models.{{.Name}}UpdateResponse "{{.Name}} updated successfully"
|
// @Success 200 {object} %s.%sUpdateResponse "%s updated successfully"
|
||||||
// @Failure 400 {object} models.ErrorResponse "Bad request"
|
// @Failure 400 {object} %s.ErrorResponse "Bad request"
|
||||||
// @Failure 404 {object} models.ErrorResponse "{{.Name}} not found"
|
// @Failure 404 {object} %s.ErrorResponse "%s not found"
|
||||||
// @Router /api/v1/{{.NamePlural}}/{id} [put]
|
// @Router /api/v1/%s/{id} [put]
|
||||||
func (h *{{.Name}}Handler) Update{{.Name}}(c *gin.Context) {
|
func (h *%sHandler) Update%s(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
var req models.{{.Name}}UpdateRequest
|
var req %s.%sUpdateRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := models.{{.Name}}UpdateResponse{
|
response := %s.%sUpdateResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
Message: "{{.Name}} updated successfully",
|
Message: "%s updated successfully",
|
||||||
Data: req,
|
Data: req,
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}`,
|
||||||
{{end}}
|
data.Name, data.NameLower, data.NameLower, data.NameLower,
|
||||||
{{if .HasDelete}}
|
data.Name, data.NameLower, data.Name, data.Name, data.Name,
|
||||||
// Delete{{.Name}} godoc
|
data.NameLower, data.Name, data.NameLower, data.Name, data.NameLower,
|
||||||
// @Summary Delete {{.NameLower}}
|
data.Name, data.Name, data.Name, data.Name)
|
||||||
// @Description Deletes a {{.NameLower}} by ID
|
}
|
||||||
// @Tags {{.NameLower}}
|
|
||||||
|
if data.HasDelete {
|
||||||
|
methodsContent += fmt.Sprintf(`
|
||||||
|
// Delete%s godoc
|
||||||
|
// @Summary Delete %s
|
||||||
|
// @Description Deletes a %s by ID
|
||||||
|
// @Tags %s
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path string true "{{.Name}} ID"
|
// @Param id path string true "%s ID"
|
||||||
// @Success 200 {object} models.{{.Name}}DeleteResponse "{{.Name}} deleted successfully"
|
// @Success 200 {object} %s.%sDeleteResponse "%s deleted successfully"
|
||||||
// @Failure 404 {object} models.ErrorResponse "{{.Name}} not found"
|
// @Failure 404 {object} %s.ErrorResponse "%s not found"
|
||||||
// @Router /api/v1/{{.NamePlural}}/{id} [delete]
|
// @Router /api/v1/%s/{id} [delete]
|
||||||
func (h *{{.Name}}Handler) Delete{{.Name}}(c *gin.Context) {
|
func (h *%sHandler) Delete%s(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
response := models.{{.Name}}DeleteResponse{
|
response := %s.%sDeleteResponse{
|
||||||
ID: id,
|
ID: id,
|
||||||
Message: "{{.Name}} deleted successfully",
|
Message: "%s deleted successfully",
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}`,
|
||||||
{{end}}
|
data.Name, data.NameLower, data.NameLower, data.NameLower,
|
||||||
`
|
data.Name, data.NameLower, data.Name, data.Name, data.NameLower,
|
||||||
|
data.Name, data.Name, data.NameLower, data.Name, data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
writeFile("internal/handlers/"+data.NameLower+".go", handlerTemplate, data)
|
fullContent := handlerContent + methodsContent
|
||||||
|
handlerFile := filepath.Join(handlerDir, data.NameLower+".go")
|
||||||
|
writeFile(handlerFile, fullContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateModelFile(data HandlerData) {
|
func generateModelFile(data HandlerData, modelDir string) {
|
||||||
modelTemplate := `package models
|
modelContent := fmt.Sprintf("package %s\n\n", data.NameLower)
|
||||||
|
|
||||||
{{if .HasGet}}
|
if data.HasGet {
|
||||||
// {{.Name}}GetResponse represents the response for GET {{.NamePlural}}
|
modelContent += fmt.Sprintf(`// %sGetResponse represents the response for GET %s
|
||||||
type {{.Name}}GetResponse struct {
|
type %sGetResponse struct {
|
||||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
Message string `+"`json:\"message\"`"+`
|
||||||
Data interface{} {{.Backtick}}json:"data"{{.Backtick}}
|
Data interface{} `+"`json:\"data\"`"+`
|
||||||
}
|
}
|
||||||
{{end}}
|
|
||||||
{{if .HasGet}}
|
// %sGetByIDResponse represents the response for GET %s by ID
|
||||||
// {{.Name}}GetByIDResponse represents the response for GET {{.NameLower}} by ID
|
type %sGetByIDResponse struct {
|
||||||
type {{.Name}}GetByIDResponse struct {
|
ID string `+"`json:\"id\"`"+`
|
||||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
Message string `+"`json:\"message\"`"+`
|
||||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
|
||||||
}
|
}
|
||||||
{{end}}
|
`, data.Name, data.NamePlural, data.Name, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||||
{{if .HasPost}}
|
}
|
||||||
// {{.Name}}CreateRequest represents the request for creating {{.NameLower}}
|
|
||||||
type {{.Name}}CreateRequest struct {
|
if data.HasPost {
|
||||||
Name string {{.Backtick}}json:"name" binding:"required"{{.Backtick}}
|
modelContent += fmt.Sprintf(`// %sCreateRequest represents the request for creating %s
|
||||||
|
type %sCreateRequest struct {
|
||||||
|
Name string `+"`json:\"name\" binding:\"required\"`"+`
|
||||||
// Add more fields as needed
|
// Add more fields as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// {{.Name}}CreateResponse represents the response for creating {{.NameLower}}
|
// %sCreateResponse represents the response for creating %s
|
||||||
type {{.Name}}CreateResponse struct {
|
type %sCreateResponse struct {
|
||||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
ID string `+"`json:\"id\"`"+`
|
||||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
Message string `+"`json:\"message\"`"+`
|
||||||
Data interface{} {{.Backtick}}json:"data"{{.Backtick}}
|
Data interface{} `+"`json:\"data\"`"+`
|
||||||
}
|
}
|
||||||
{{end}}
|
`, data.Name, data.NameLower, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||||
{{if .HasPut}}
|
}
|
||||||
// {{.Name}}UpdateRequest represents the request for updating {{.NameLower}}
|
|
||||||
type {{.Name}}UpdateRequest struct {
|
if data.HasPut {
|
||||||
Name string {{.Backtick}}json:"name" binding:"required"{{.Backtick}}
|
modelContent += fmt.Sprintf(`// %sUpdateRequest represents the request for updating %s
|
||||||
|
type %sUpdateRequest struct {
|
||||||
|
Name string `+"`json:\"name\" binding:\"required\"`"+`
|
||||||
// Add more fields as needed
|
// Add more fields as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// {{.Name}}UpdateResponse represents the response for updating {{.NameLower}}
|
// %sUpdateResponse represents the response for updating %s
|
||||||
type {{.Name}}UpdateResponse struct {
|
type %sUpdateResponse struct {
|
||||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
ID string `+"`json:\"id\"`"+`
|
||||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
Message string `+"`json:\"message\"`"+`
|
||||||
Data interface{} {{.Backtick}}json:"data"{{.Backtick}}
|
Data interface{} `+"`json:\"data\"`"+`
|
||||||
}
|
}
|
||||||
{{end}}
|
`, data.Name, data.NameLower, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||||
{{if .HasDelete}}
|
}
|
||||||
// {{.Name}}DeleteResponse represents the response for deleting {{.NameLower}}
|
|
||||||
type {{.Name}}DeleteResponse struct {
|
|
||||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
|
||||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
// ErrorResponse represents an error response
|
if data.HasDelete {
|
||||||
|
modelContent += fmt.Sprintf(`// %sDeleteResponse represents the response for deleting %s
|
||||||
|
type %sDeleteResponse struct {
|
||||||
|
ID string `+"`json:\"id\"`"+`
|
||||||
|
Message string `+"`json:\"message\"`"+`
|
||||||
|
}
|
||||||
|
`, data.Name, data.NameLower, data.Name, data.NameLower)
|
||||||
|
}
|
||||||
|
|
||||||
|
modelContent += `// ErrorResponse represents an error response
|
||||||
type ErrorResponse struct {
|
type ErrorResponse struct {
|
||||||
Error string {{.Backtick}}json:"error"{{.Backtick}}
|
Error string ` + "`json:\"error\"`" + `
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
// Replace backtick with actual backtick
|
modelFile := filepath.Join(modelDir, data.NameLower+".go")
|
||||||
modelTemplate = strings.ReplaceAll(modelTemplate, "{{.Backtick}}", "`")
|
writeFile(modelFile, modelContent)
|
||||||
writeFile("internal/models/"+data.NameLower+".go", modelTemplate, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRoutesFile(data HandlerData) {
|
func updateRoutesFile(data HandlerData) {
|
||||||
@@ -294,28 +344,65 @@ func updateRoutesFile(data HandlerData) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to string
|
|
||||||
routesContent := string(content)
|
routesContent := string(content)
|
||||||
|
|
||||||
// Find the place to insert new routes
|
// Check if import already exists
|
||||||
insertMarker := "\t\t// Example endpoints"
|
importPattern := fmt.Sprintf(`%sHandlers "api-service/internal/handlers/%s"`, data.NameLower, data.NameLower)
|
||||||
|
if !strings.Contains(routesContent, importPattern) {
|
||||||
|
// Find the import block and insert the new import
|
||||||
|
importToAdd := fmt.Sprintf("\t%sHandlers \"api-service/internal/handlers/%s\"", data.NameLower, data.NameLower)
|
||||||
|
|
||||||
|
// Find the import block end
|
||||||
|
importEndMarker := "\n)\n\n// RegisterRoutes"
|
||||||
|
if !strings.Contains(routesContent, importEndMarker) {
|
||||||
|
importEndMarker = "\n)\n\nfunc RegisterRoutes"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the line before the closing parenthesis
|
||||||
|
lines := strings.Split(routesContent, "\n")
|
||||||
|
var newLines []string
|
||||||
|
importBlockFound := false
|
||||||
|
importAdded := false
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
newLines = append(newLines, line)
|
||||||
|
|
||||||
|
// Check if we're in the import block
|
||||||
|
if strings.Contains(line, "import (") {
|
||||||
|
importBlockFound = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're at the end of import block
|
||||||
|
if importBlockFound && strings.TrimSpace(line) == ")" && !importAdded {
|
||||||
|
// Insert the new import before the closing parenthesis
|
||||||
|
newLines = newLines[:len(newLines)-1] // Remove the last line (closing parenthesis)
|
||||||
|
newLines = append(newLines, importToAdd)
|
||||||
|
newLines = append(newLines, line) // Add back the closing parenthesis
|
||||||
|
importAdded = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if importAdded {
|
||||||
|
routesContent = strings.Join(newLines, "\n")
|
||||||
|
} else {
|
||||||
|
// Fallback to simple string replacement
|
||||||
|
if strings.Contains(routesContent, importEndMarker) {
|
||||||
|
routesContent = strings.Replace(routesContent, importEndMarker, "\n"+importToAdd+importEndMarker, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generate new routes
|
// Generate new routes
|
||||||
newRoutes := fmt.Sprintf("\t\t// %s endpoints\n", data.Name)
|
newRoutes := fmt.Sprintf("\t\t// %s endpoints\n", data.Name)
|
||||||
|
newRoutes += fmt.Sprintf("\t\t%sHandler := %sHandlers.New%sHandler()\n", data.NameLower, data.NameLower, data.Name)
|
||||||
|
|
||||||
if data.HasGet {
|
if data.HasGet {
|
||||||
newRoutes += fmt.Sprintf("\t\t%sHandler := handlers.New%sHandler()\n", data.NameLower, data.Name)
|
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s\", %sHandler.Get%s)\n", data.NamePlural, data.NameLower, data.Name)
|
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s\", %sHandler.Get%s)\n", data.NamePlural, data.NameLower, data.Name)
|
||||||
}
|
|
||||||
|
|
||||||
if data.HasGet {
|
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n", data.NamePlural, data.NameLower, data.Name)
|
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n", data.NamePlural, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.HasPost {
|
if data.HasPost {
|
||||||
if !data.HasGet {
|
|
||||||
newRoutes += fmt.Sprintf("\t\t%sHandler := handlers.New%sHandler()\n", data.NameLower, data.Name)
|
|
||||||
}
|
|
||||||
newRoutes += fmt.Sprintf("\t\tv1.POST(\"/%s\", %sHandler.Create%s)\n", data.NamePlural, data.NameLower, data.Name)
|
newRoutes += fmt.Sprintf("\t\tv1.POST(\"/%s\", %sHandler.Create%s)\n", data.NamePlural, data.NameLower, data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,8 +416,17 @@ func updateRoutesFile(data HandlerData) {
|
|||||||
|
|
||||||
newRoutes += "\n"
|
newRoutes += "\n"
|
||||||
|
|
||||||
// Insert new routes after the marker
|
// Find the place to insert new routes (after the protected group)
|
||||||
newContent := strings.Replace(routesContent, insertMarker, insertMarker+"\n"+newRoutes, 1)
|
insertMarker := "\t\tprotected := v1.Group(\"/\")"
|
||||||
|
|
||||||
|
// Check if routes already exist
|
||||||
|
if strings.Contains(routesContent, fmt.Sprintf("New%sHandler", data.Name)) {
|
||||||
|
fmt.Printf("Routes for %s already exist, skipping...\n", data.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert new routes before the protected group
|
||||||
|
newContent := strings.Replace(routesContent, insertMarker, newRoutes+insertMarker, 1)
|
||||||
|
|
||||||
// Write back to file
|
// Write back to file
|
||||||
err = os.WriteFile(routesFile, []byte(newContent), 0644)
|
err = os.WriteFile(routesFile, []byte(newContent), 0644)
|
||||||
@@ -338,27 +434,15 @@ func updateRoutesFile(data HandlerData) {
|
|||||||
fmt.Printf("Error writing routes file: %v\n", err)
|
fmt.Printf("Error writing routes file: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Updated routes file with %s endpoints\n", data.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFile(filename, templateStr string, data HandlerData) {
|
func writeFile(filename, content string) {
|
||||||
tmpl, err := template.New("template").Parse(templateStr)
|
err := os.WriteFile(filename, []byte(content), 0644)
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error parsing template: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create(filename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error creating file %s: %v\n", filename, err)
|
fmt.Printf("Error creating file %s: %v\n", filename, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
err = tmpl.Execute(file, data)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error executing template: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Generated: %s\n", filename)
|
fmt.Printf("Generated: %s\n", filename)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user