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/cmd/api/docs"
|
||||
_ "api-service/docs"
|
||||
)
|
||||
|
||||
// @title API Service
|
||||
|
||||
335
docs/docs.go
335
docs/docs.go
@@ -24,6 +24,7 @@ const docTemplate = `{
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/": {
|
||||
"get": {
|
||||
"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": {
|
||||
"get": {
|
||||
"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": {
|
||||
"get": {
|
||||
"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": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -477,6 +781,37 @@ const docTemplate = `{
|
||||
"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": {
|
||||
"get": {
|
||||
"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": {
|
||||
"get": {
|
||||
"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": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -475,6 +778,37 @@
|
||||
"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:
|
||||
type: string
|
||||
type: object
|
||||
models.LoginRequest:
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
required:
|
||||
- password
|
||||
- username
|
||||
type: object
|
||||
models.ProductCreateRequest:
|
||||
properties:
|
||||
name:
|
||||
@@ -99,6 +109,26 @@ definitions:
|
||||
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:
|
||||
@@ -128,6 +158,129 @@ paths:
|
||||
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:
|
||||
@@ -291,6 +444,71 @@ paths:
|
||||
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:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"api-service/internal/models"
|
||||
"api-service/internal/services"
|
||||
models "api-service/internal/models/auth"
|
||||
services "api-service/internal/services/auth"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -1,8 +1,8 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"api-service/internal/models"
|
||||
"api-service/internal/services"
|
||||
models "api-service/internal/models/auth"
|
||||
services "api-service/internal/services/auth"
|
||||
"net/http"
|
||||
|
||||
"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
|
||||
|
||||
import (
|
||||
"api-service/internal/services"
|
||||
services "api-service/internal/services/auth"
|
||||
"net/http"
|
||||
"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"
|
||||
|
||||
"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/services"
|
||||
services "api-service/internal/services/auth"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
@@ -34,13 +36,13 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
|
||||
{
|
||||
// Public routes (no authentication required)
|
||||
// Health endpoints
|
||||
healthHandler := handlers.NewHealthHandler()
|
||||
healthHandler := componentHandlers.NewHealthHandler()
|
||||
v1.GET("/health", healthHandler.GetHealth)
|
||||
v1.GET("/", healthHandler.HelloWorld)
|
||||
|
||||
// Authentication routes
|
||||
authHandler := handlers.NewAuthHandler(authService)
|
||||
tokenHandler := handlers.NewTokenHandler(authService)
|
||||
authHandler := authHandlers.NewAuthHandler(authService)
|
||||
tokenHandler := authHandlers.NewTokenHandler(authService)
|
||||
|
||||
v1.POST("/auth/login", authHandler.Login)
|
||||
v1.POST("/auth/register", authHandler.Register)
|
||||
@@ -52,11 +54,20 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
|
||||
v1.POST("/token/generate-direct", tokenHandler.GenerateTokenDirect)
|
||||
|
||||
// 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.Use(middleware.JWTAuthMiddleware(authService))
|
||||
{
|
||||
// Product endpoints
|
||||
productHandler := handlers.NewProductHandler()
|
||||
productHandler := componentHandlers.NewProductHandler()
|
||||
protected.GET("/products", productHandler.GetProduct)
|
||||
protected.GET("/products/:id", productHandler.GetProductByID)
|
||||
protected.POST("/products", productHandler.CreateProduct)
|
||||
@@ -64,7 +75,7 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
|
||||
protected.DELETE("/products/:id", productHandler.DeleteProduct)
|
||||
|
||||
// Example endpoints
|
||||
exampleHandler := handlers.NewExampleHandler()
|
||||
exampleHandler := componentHandlers.NewExampleHandler()
|
||||
protected.GET("/example", exampleHandler.GetExample)
|
||||
protected.POST("/example", exampleHandler.PostExample)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"api-service/internal/config"
|
||||
"api-service/internal/models"
|
||||
models "api-service/internal/models/auth"
|
||||
"errors"
|
||||
"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
|
||||
```bash
|
||||
# Dari root project
|
||||
# .. run tools/generate-handler.go : Perintahnya
|
||||
# .. user nama module nya dan handlernya
|
||||
# .. get post put delete metod yang di gunakan
|
||||
go run tools/generate-handler.go <nama-handler> [methods]
|
||||
|
||||
# Contoh:
|
||||
go run tools/generate-handler.go user get post put delete
|
||||
go run tools/generate-handler.go product get post
|
||||
```
|
||||
|
||||
## Method yang Tersedia
|
||||
@@ -41,9 +42,11 @@ go run tools/generate-handler.go user get post put delete
|
||||
|
||||
## File yang Dibuat Otomatis
|
||||
|
||||
1. **Handler**: `internal/handlers/<nama>.go`
|
||||
2. **Models**: `internal/models/<nama>.go`
|
||||
1. **Handler**: `internal/handlers/<nama>/<nama>.go`
|
||||
2. **Models**: `internal/models/<nama>/<nama>.go`
|
||||
3. **Routes**: Update otomatis di `internal/routes/v1/routes.go`
|
||||
- **<nama>**: `Nama Directori`
|
||||
- **<nama>.go**: `Nama file class`
|
||||
|
||||
## Contoh Penggunaan
|
||||
|
||||
@@ -66,7 +69,7 @@ go run tools/generate-handler.go user get post put delete
|
||||
|
||||
1. Jalankan swagger generator:
|
||||
```bash
|
||||
swag init -g cmd/api/main.go --output cmd/api/docs
|
||||
swag init -g cmd/api/main.go
|
||||
```
|
||||
|
||||
2. Jalankan aplikasi:
|
||||
@@ -81,20 +84,23 @@ http://localhost:8080/swagger/index.html
|
||||
|
||||
## Struktur File yang Dibuat
|
||||
|
||||
### Handler File (`internal/handlers/<nama>.go`)
|
||||
### Handler File (`internal/handlers/<nama>/<nama>.go`)
|
||||
- Struct handler
|
||||
- Constructor function
|
||||
- Endpoint methods dengan swagger documentation
|
||||
- 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
|
||||
- Response models
|
||||
- Error response models
|
||||
- Package name sesuai dengan nama handler
|
||||
|
||||
### Routes Update
|
||||
- Otomatis menambahkan routes ke `/api/v1/<nama-plural>`
|
||||
- Support parameter ID untuk endpoint spesifik
|
||||
- Menggunakan componentHandlers untuk handler baru
|
||||
|
||||
## Contoh Output
|
||||
|
||||
@@ -105,7 +111,38 @@ Untuk command: `./generate.sh user get post`
|
||||
- `GET /api/v1/users/:id` - Get user by ID
|
||||
- `POST /api/v1/users` - Create new user
|
||||
|
||||
### Struktur Direktori:
|
||||
```
|
||||
internal/
|
||||
├── handlers/
|
||||
│ └── user/
|
||||
│ └── user.go
|
||||
├── models/
|
||||
│ └── user/
|
||||
│ └── user.go
|
||||
```
|
||||
|
||||
### Swagger Documentation
|
||||
Semua endpoint otomatis memiliki swagger documentation yang bisa diakses di:
|
||||
```
|
||||
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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -26,9 +26,9 @@ type HandlerData struct {
|
||||
|
||||
func main() {
|
||||
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("Methods: get, post, put, delete (optional, default: get post)")
|
||||
fmt.Println("Example: go run generate-handler.go product get post")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -71,217 +71,267 @@ func main() {
|
||||
|
||||
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
|
||||
os.MkdirAll("internal/handlers", 0755)
|
||||
os.MkdirAll("internal/models", 0755)
|
||||
dirs := []string{
|
||||
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
|
||||
generateHandlerFile(data)
|
||||
generateModelFile(data)
|
||||
generateHandlerFile(data, handlerDir)
|
||||
generateModelFile(data, modelDir)
|
||||
updateRoutesFile(data)
|
||||
|
||||
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) {
|
||||
handlerTemplate := `package handlers
|
||||
func generateHandlerFile(data HandlerData, handlerDir string) {
|
||||
handlerContent := fmt.Sprintf(`package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"{{.ModuleName}}/internal/models"
|
||||
|
||||
"api-service/internal/models/%s"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// {{.Name}}Handler handles {{.NameLower}} services
|
||||
type {{.Name}}Handler struct{}
|
||||
// %sHandler handles %s services
|
||||
type %sHandler struct{}
|
||||
|
||||
// New{{.Name}}Handler creates a new {{.Name}}Handler
|
||||
func New{{.Name}}Handler() *{{.Name}}Handler {
|
||||
return &{{.Name}}Handler{}
|
||||
}
|
||||
{{if .HasGet}}
|
||||
// Get{{.Name}} godoc
|
||||
// @Summary Get {{.NameLower}}
|
||||
// @Description Returns a list of {{.NamePlural}}
|
||||
// @Tags {{.NameLower}}
|
||||
// New%sHandler creates a new %sHandler
|
||||
func New%sHandler() *%sHandler {
|
||||
return &%sHandler{}
|
||||
}`, data.NameLower, data.Name, data.NameLower, data.Name, data.Name, data.Name, data.Name, data.Name)
|
||||
|
||||
// Add methods based on requested operations
|
||||
var methodsContent string
|
||||
|
||||
if data.HasGet {
|
||||
methodsContent += fmt.Sprintf(`
|
||||
// Get%s godoc
|
||||
// @Summary Get %s
|
||||
// @Description Returns a list of %s
|
||||
// @Tags %s
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} models.{{.Name}}GetResponse "{{.Name}} GET response"
|
||||
// @Router /api/v1/{{.NamePlural}} [get]
|
||||
func (h *{{.Name}}Handler) Get{{.Name}}(c *gin.Context) {
|
||||
response := models.{{.Name}}GetResponse{
|
||||
Message: "List of {{.NamePlural}}",
|
||||
Data: []string{"{{.Name}} 1", "{{.Name}} 2"},
|
||||
// @Success 200 {object} %s.%sGetResponse "%s GET response"
|
||||
// @Router /api/v1/%s [get]
|
||||
func (h *%sHandler) Get%s(c *gin.Context) {
|
||||
response := %s.%sGetResponse{
|
||||
Message: "List of %s",
|
||||
Data: []string{"%s 1", "%s 2"},
|
||||
}
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasGet}}
|
||||
// Get{{.Name}}ByID godoc
|
||||
// @Summary Get {{.NameLower}} by ID
|
||||
// @Description Returns a single {{.NameLower}} by ID
|
||||
// @Tags {{.NameLower}}
|
||||
|
||||
// Get%sByID godoc
|
||||
// @Summary Get %s by ID
|
||||
// @Description Returns a single %s by ID
|
||||
// @Tags %s
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "{{.Name}} ID"
|
||||
// @Success 200 {object} models.{{.Name}}GetByIDResponse "{{.Name}} GET by ID response"
|
||||
// @Failure 404 {object} models.ErrorResponse "{{.Name}} not found"
|
||||
// @Router /api/v1/{{.NamePlural}}/{id} [get]
|
||||
func (h *{{.Name}}Handler) Get{{.Name}}ByID(c *gin.Context) {
|
||||
// @Param id path string true "%s ID"
|
||||
// @Success 200 {object} %s.%sGetByIDResponse "%s GET by ID response"
|
||||
// @Failure 404 {object} %s.ErrorResponse "%s not found"
|
||||
// @Router /api/v1/%s/{id} [get]
|
||||
func (h *%sHandler) Get%sByID(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
response := models.{{.Name}}GetByIDResponse{
|
||||
response := %s.%sGetByIDResponse{
|
||||
ID: id,
|
||||
Message: "{{.Name}} details",
|
||||
Message: "%s details",
|
||||
}
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasPost}}
|
||||
// Create{{.Name}} godoc
|
||||
// @Summary Create {{.NameLower}}
|
||||
// @Description Creates a new {{.NameLower}}
|
||||
// @Tags {{.NameLower}}
|
||||
}`,
|
||||
data.Name, data.NameLower, data.NamePlural, data.NameLower,
|
||||
data.NameLower, data.Name, data.Name, data.NamePlural,
|
||||
data.Name, data.Name, data.NameLower, data.Name, data.Name, data.Name,
|
||||
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.NameLower, data.Name)
|
||||
}
|
||||
|
||||
if data.HasPost {
|
||||
methodsContent += fmt.Sprintf(`
|
||||
// Create%s godoc
|
||||
// @Summary Create %s
|
||||
// @Description Creates a new %s
|
||||
// @Tags %s
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body models.{{.Name}}CreateRequest true "{{.Name}} creation request"
|
||||
// @Success 201 {object} models.{{.Name}}CreateResponse "{{.Name}} created successfully"
|
||||
// @Failure 400 {object} models.ErrorResponse "Bad request"
|
||||
// @Router /api/v1/{{.NamePlural}} [post]
|
||||
func (h *{{.Name}}Handler) Create{{.Name}}(c *gin.Context) {
|
||||
var req models.{{.Name}}CreateRequest
|
||||
// @Param request body %s.%sCreateRequest true "%s creation request"
|
||||
// @Success 201 {object} %s.%sCreateResponse "%s created successfully"
|
||||
// @Failure 400 {object} %s.ErrorResponse "Bad request"
|
||||
// @Router /api/v1/%s [post]
|
||||
func (h *%sHandler) Create%s(c *gin.Context) {
|
||||
var req %s.%sCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
response := models.{{.Name}}CreateResponse{
|
||||
response := %s.%sCreateResponse{
|
||||
ID: uuid.NewString(),
|
||||
Message: "{{.Name}} created successfully",
|
||||
Message: "%s created successfully",
|
||||
Data: req,
|
||||
}
|
||||
c.JSON(http.StatusCreated, response)
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasPut}}
|
||||
// Update{{.Name}} godoc
|
||||
// @Summary Update {{.NameLower}}
|
||||
// @Description Updates an existing {{.NameLower}}
|
||||
// @Tags {{.NameLower}}
|
||||
}`,
|
||||
data.Name, data.NameLower, data.NameLower, data.NameLower,
|
||||
data.NameLower, data.Name, data.Name, data.NameLower, data.Name,
|
||||
data.Name, data.NameLower, data.Name, data.Name, data.NameLower,
|
||||
data.Name, data.Name)
|
||||
}
|
||||
|
||||
if data.HasPut {
|
||||
methodsContent += fmt.Sprintf(`
|
||||
// Update%s godoc
|
||||
// @Summary Update %s
|
||||
// @Description Updates an existing %s
|
||||
// @Tags %s
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "{{.Name}} ID"
|
||||
// @Param request body models.{{.Name}}UpdateRequest true "{{.Name}} update request"
|
||||
// @Success 200 {object} models.{{.Name}}UpdateResponse "{{.Name}} updated successfully"
|
||||
// @Failure 400 {object} models.ErrorResponse "Bad request"
|
||||
// @Failure 404 {object} models.ErrorResponse "{{.Name}} not found"
|
||||
// @Router /api/v1/{{.NamePlural}}/{id} [put]
|
||||
func (h *{{.Name}}Handler) Update{{.Name}}(c *gin.Context) {
|
||||
// @Param id path string true "%s ID"
|
||||
// @Param request body %s.%sUpdateRequest true "%s update request"
|
||||
// @Success 200 {object} %s.%sUpdateResponse "%s updated successfully"
|
||||
// @Failure 400 {object} %s.ErrorResponse "Bad request"
|
||||
// @Failure 404 {object} %s.ErrorResponse "%s not found"
|
||||
// @Router /api/v1/%s/{id} [put]
|
||||
func (h *%sHandler) Update%s(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var req models.{{.Name}}UpdateRequest
|
||||
var req %s.%sUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
response := models.{{.Name}}UpdateResponse{
|
||||
response := %s.%sUpdateResponse{
|
||||
ID: id,
|
||||
Message: "{{.Name}} updated successfully",
|
||||
Message: "%s updated successfully",
|
||||
Data: req,
|
||||
}
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasDelete}}
|
||||
// Delete{{.Name}} godoc
|
||||
// @Summary Delete {{.NameLower}}
|
||||
// @Description Deletes a {{.NameLower}} by ID
|
||||
// @Tags {{.NameLower}}
|
||||
}`,
|
||||
data.Name, data.NameLower, data.NameLower, data.NameLower,
|
||||
data.Name, data.NameLower, data.Name, data.Name, data.Name,
|
||||
data.NameLower, data.Name, data.NameLower, data.Name, data.NameLower,
|
||||
data.Name, data.Name, data.Name, data.Name)
|
||||
}
|
||||
|
||||
if data.HasDelete {
|
||||
methodsContent += fmt.Sprintf(`
|
||||
// Delete%s godoc
|
||||
// @Summary Delete %s
|
||||
// @Description Deletes a %s by ID
|
||||
// @Tags %s
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "{{.Name}} ID"
|
||||
// @Success 200 {object} models.{{.Name}}DeleteResponse "{{.Name}} deleted successfully"
|
||||
// @Failure 404 {object} models.ErrorResponse "{{.Name}} not found"
|
||||
// @Router /api/v1/{{.NamePlural}}/{id} [delete]
|
||||
func (h *{{.Name}}Handler) Delete{{.Name}}(c *gin.Context) {
|
||||
// @Param id path string true "%s ID"
|
||||
// @Success 200 {object} %s.%sDeleteResponse "%s deleted successfully"
|
||||
// @Failure 404 {object} %s.ErrorResponse "%s not found"
|
||||
// @Router /api/v1/%s/{id} [delete]
|
||||
func (h *%sHandler) Delete%s(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
response := models.{{.Name}}DeleteResponse{
|
||||
response := %s.%sDeleteResponse{
|
||||
ID: id,
|
||||
Message: "{{.Name}} deleted successfully",
|
||||
Message: "%s deleted successfully",
|
||||
}
|
||||
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) {
|
||||
modelTemplate := `package models
|
||||
func generateModelFile(data HandlerData, modelDir string) {
|
||||
modelContent := fmt.Sprintf("package %s\n\n", data.NameLower)
|
||||
|
||||
{{if .HasGet}}
|
||||
// {{.Name}}GetResponse represents the response for GET {{.NamePlural}}
|
||||
type {{.Name}}GetResponse struct {
|
||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
||||
Data interface{} {{.Backtick}}json:"data"{{.Backtick}}
|
||||
if data.HasGet {
|
||||
modelContent += fmt.Sprintf(`// %sGetResponse represents the response for GET %s
|
||||
type %sGetResponse struct {
|
||||
Message string `+"`json:\"message\"`"+`
|
||||
Data interface{} `+"`json:\"data\"`"+`
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasGet}}
|
||||
// {{.Name}}GetByIDResponse represents the response for GET {{.NameLower}} by ID
|
||||
type {{.Name}}GetByIDResponse struct {
|
||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
||||
|
||||
// %sGetByIDResponse represents the response for GET %s by ID
|
||||
type %sGetByIDResponse struct {
|
||||
ID string `+"`json:\"id\"`"+`
|
||||
Message string `+"`json:\"message\"`"+`
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasPost}}
|
||||
// {{.Name}}CreateRequest represents the request for creating {{.NameLower}}
|
||||
type {{.Name}}CreateRequest struct {
|
||||
Name string {{.Backtick}}json:"name" binding:"required"{{.Backtick}}
|
||||
`, data.Name, data.NamePlural, data.Name, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||
}
|
||||
|
||||
if data.HasPost {
|
||||
modelContent += fmt.Sprintf(`// %sCreateRequest represents the request for creating %s
|
||||
type %sCreateRequest struct {
|
||||
Name string `+"`json:\"name\" binding:\"required\"`"+`
|
||||
// Add more fields as needed
|
||||
}
|
||||
|
||||
// {{.Name}}CreateResponse represents the response for creating {{.NameLower}}
|
||||
type {{.Name}}CreateResponse struct {
|
||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
||||
Data interface{} {{.Backtick}}json:"data"{{.Backtick}}
|
||||
// %sCreateResponse represents the response for creating %s
|
||||
type %sCreateResponse struct {
|
||||
ID string `+"`json:\"id\"`"+`
|
||||
Message string `+"`json:\"message\"`"+`
|
||||
Data interface{} `+"`json:\"data\"`"+`
|
||||
}
|
||||
{{end}}
|
||||
{{if .HasPut}}
|
||||
// {{.Name}}UpdateRequest represents the request for updating {{.NameLower}}
|
||||
type {{.Name}}UpdateRequest struct {
|
||||
Name string {{.Backtick}}json:"name" binding:"required"{{.Backtick}}
|
||||
`, data.Name, data.NameLower, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||
}
|
||||
|
||||
if data.HasPut {
|
||||
modelContent += fmt.Sprintf(`// %sUpdateRequest represents the request for updating %s
|
||||
type %sUpdateRequest struct {
|
||||
Name string `+"`json:\"name\" binding:\"required\"`"+`
|
||||
// Add more fields as needed
|
||||
}
|
||||
|
||||
// {{.Name}}UpdateResponse represents the response for updating {{.NameLower}}
|
||||
type {{.Name}}UpdateResponse struct {
|
||||
ID string {{.Backtick}}json:"id"{{.Backtick}}
|
||||
Message string {{.Backtick}}json:"message"{{.Backtick}}
|
||||
Data interface{} {{.Backtick}}json:"data"{{.Backtick}}
|
||||
// %sUpdateResponse represents the response for updating %s
|
||||
type %sUpdateResponse struct {
|
||||
ID string `+"`json:\"id\"`"+`
|
||||
Message string `+"`json:\"message\"`"+`
|
||||
Data interface{} `+"`json:\"data\"`"+`
|
||||
}
|
||||
{{end}}
|
||||
{{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}}
|
||||
`, data.Name, data.NameLower, data.Name, data.NameLower, data.Name, data.NameLower, data.Name)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Error string {{.Backtick}}json:"error"{{.Backtick}}
|
||||
Error string ` + "`json:\"error\"`" + `
|
||||
}
|
||||
`
|
||||
|
||||
// Replace backtick with actual backtick
|
||||
modelTemplate = strings.ReplaceAll(modelTemplate, "{{.Backtick}}", "`")
|
||||
writeFile("internal/models/"+data.NameLower+".go", modelTemplate, data)
|
||||
modelFile := filepath.Join(modelDir, data.NameLower+".go")
|
||||
writeFile(modelFile, modelContent)
|
||||
}
|
||||
|
||||
func updateRoutesFile(data HandlerData) {
|
||||
@@ -294,28 +344,65 @@ func updateRoutesFile(data HandlerData) {
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to string
|
||||
routesContent := string(content)
|
||||
|
||||
// Find the place to insert new routes
|
||||
insertMarker := "\t\t// Example endpoints"
|
||||
// Check if import already exists
|
||||
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
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
if data.HasGet {
|
||||
newRoutes += fmt.Sprintf("\t\tv1.GET(\"/%s/:id\", %sHandler.Get%sByID)\n", data.NamePlural, data.NameLower, data.Name)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -329,8 +416,17 @@ func updateRoutesFile(data HandlerData) {
|
||||
|
||||
newRoutes += "\n"
|
||||
|
||||
// Insert new routes after the marker
|
||||
newContent := strings.Replace(routesContent, insertMarker, insertMarker+"\n"+newRoutes, 1)
|
||||
// Find the place to insert new routes (after the protected group)
|
||||
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
|
||||
err = os.WriteFile(routesFile, []byte(newContent), 0644)
|
||||
@@ -338,27 +434,15 @@ func updateRoutesFile(data HandlerData) {
|
||||
fmt.Printf("Error writing routes file: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Updated routes file with %s endpoints\n", data.Name)
|
||||
}
|
||||
|
||||
func writeFile(filename, templateStr string, data HandlerData) {
|
||||
tmpl, err := template.New("template").Parse(templateStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing template: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Create(filename)
|
||||
func writeFile(filename, content string) {
|
||||
err := os.WriteFile(filename, []byte(content), 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating file %s: %v\n", filename, err)
|
||||
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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user