365 lines
10 KiB
Go
365 lines
10 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"text/template"
|
|
"time"
|
|
)
|
|
|
|
// HandlerData contains template data for handler generation
|
|
type HandlerData struct {
|
|
Name string
|
|
NameLower string
|
|
NamePlural string
|
|
ModuleName string
|
|
HasGet bool
|
|
HasPost bool
|
|
HasPut bool
|
|
HasDelete bool
|
|
HasParam bool
|
|
HasRequest bool
|
|
HasResponse bool
|
|
Timestamp string
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
fmt.Println("Usage: go run generate-handler.go <handler-name> [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)")
|
|
os.Exit(1)
|
|
}
|
|
|
|
handlerName := strings.Title(os.Args[1])
|
|
methods := []string{"get", "post"}
|
|
if len(os.Args) > 2 {
|
|
methods = os.Args[2:]
|
|
}
|
|
|
|
// Convert to lowercase for file names
|
|
handlerLower := strings.ToLower(handlerName)
|
|
handlerPlural := handlerLower + "s"
|
|
|
|
data := HandlerData{
|
|
Name: handlerName,
|
|
NameLower: handlerLower,
|
|
NamePlural: handlerPlural,
|
|
ModuleName: "api-service",
|
|
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
|
|
}
|
|
|
|
// Check which methods are requested
|
|
for _, method := range methods {
|
|
switch strings.ToLower(method) {
|
|
case "get":
|
|
data.HasGet = true
|
|
case "post":
|
|
data.HasPost = true
|
|
case "put":
|
|
data.HasPut = true
|
|
case "delete":
|
|
data.HasDelete = true
|
|
}
|
|
}
|
|
|
|
// Check if we need request/response models
|
|
data.HasRequest = data.HasPost || data.HasPut
|
|
data.HasResponse = true
|
|
data.HasParam = data.HasGet || data.HasPut || data.HasDelete
|
|
|
|
fmt.Printf("Generating handler: %s with methods: %v\n", handlerName, methods)
|
|
|
|
// Create directories if they don't exist
|
|
os.MkdirAll("internal/handlers", 0755)
|
|
os.MkdirAll("internal/models", 0755)
|
|
|
|
// Generate files
|
|
generateHandlerFile(data)
|
|
generateModelFile(data)
|
|
updateRoutesFile(data)
|
|
|
|
fmt.Printf("Successfully generated handler: %s\n", handlerName)
|
|
fmt.Println("Don't forget to run: swag init -g cmd/api/main.go")
|
|
}
|
|
|
|
func generateHandlerFile(data HandlerData) {
|
|
handlerTemplate := `package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"{{.ModuleName}}/internal/models"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// {{.Name}}Handler handles {{.NameLower}} services
|
|
type {{.Name}}Handler 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}}
|
|
// @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"},
|
|
}
|
|
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}}
|
|
// @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) {
|
|
id := c.Param("id")
|
|
response := models.{{.Name}}GetByIDResponse{
|
|
ID: id,
|
|
Message: "{{.Name}} details",
|
|
}
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
{{end}}
|
|
{{if .HasPost}}
|
|
// Create{{.Name}} godoc
|
|
// @Summary Create {{.NameLower}}
|
|
// @Description Creates a new {{.NameLower}}
|
|
// @Tags {{.NameLower}}
|
|
// @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
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
response := models.{{.Name}}CreateResponse{
|
|
ID: uuid.NewString(),
|
|
Message: "{{.Name}} 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}}
|
|
// @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) {
|
|
id := c.Param("id")
|
|
var req models.{{.Name}}UpdateRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
response := models.{{.Name}}UpdateResponse{
|
|
ID: id,
|
|
Message: "{{.Name}} 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}}
|
|
// @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) {
|
|
id := c.Param("id")
|
|
response := models.{{.Name}}DeleteResponse{
|
|
ID: id,
|
|
Message: "{{.Name}} deleted successfully",
|
|
}
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
{{end}}
|
|
`
|
|
|
|
writeFile("internal/handlers/"+data.NameLower+".go", handlerTemplate, data)
|
|
}
|
|
|
|
func generateModelFile(data HandlerData) {
|
|
modelTemplate := `package models
|
|
|
|
{{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}}
|
|
}
|
|
{{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}}
|
|
}
|
|
{{end}}
|
|
{{if .HasPost}}
|
|
// {{.Name}}CreateRequest represents the request for creating {{.NameLower}}
|
|
type {{.Name}}CreateRequest struct {
|
|
Name string {{.Backtick}}json:"name" binding:"required"{{.Backtick}}
|
|
// 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}}
|
|
}
|
|
{{end}}
|
|
{{if .HasPut}}
|
|
// {{.Name}}UpdateRequest represents the request for updating {{.NameLower}}
|
|
type {{.Name}}UpdateRequest struct {
|
|
Name string {{.Backtick}}json:"name" binding:"required"{{.Backtick}}
|
|
// 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}}
|
|
}
|
|
{{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}}
|
|
|
|
// ErrorResponse represents an error response
|
|
type ErrorResponse struct {
|
|
Error string {{.Backtick}}json:"error"{{.Backtick}}
|
|
}
|
|
`
|
|
|
|
// Replace backtick with actual backtick
|
|
modelTemplate = strings.ReplaceAll(modelTemplate, "{{.Backtick}}", "`")
|
|
writeFile("internal/models/"+data.NameLower+".go", modelTemplate, data)
|
|
}
|
|
|
|
func updateRoutesFile(data HandlerData) {
|
|
routesFile := "internal/routes/v1/routes.go"
|
|
|
|
// Read existing routes file
|
|
content, err := os.ReadFile(routesFile)
|
|
if err != nil {
|
|
fmt.Printf("Error reading routes file: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Convert to string
|
|
routesContent := string(content)
|
|
|
|
// Find the place to insert new routes
|
|
insertMarker := "\t\t// Example endpoints"
|
|
|
|
// Generate new routes
|
|
newRoutes := fmt.Sprintf("\t\t// %s endpoints\n", 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)
|
|
}
|
|
|
|
if data.HasPut {
|
|
newRoutes += fmt.Sprintf("\t\tv1.PUT(\"/%s/:id\", %sHandler.Update%s)\n", data.NamePlural, data.NameLower, data.Name)
|
|
}
|
|
|
|
if data.HasDelete {
|
|
newRoutes += fmt.Sprintf("\t\tv1.DELETE(\"/%s/:id\", %sHandler.Delete%s)\n", data.NamePlural, data.NameLower, data.Name)
|
|
}
|
|
|
|
newRoutes += "\n"
|
|
|
|
// Insert new routes after the marker
|
|
newContent := strings.Replace(routesContent, insertMarker, insertMarker+"\n"+newRoutes, 1)
|
|
|
|
// Write back to file
|
|
err = os.WriteFile(routesFile, []byte(newContent), 0644)
|
|
if err != nil {
|
|
fmt.Printf("Error writing routes file: %v\n", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
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)
|
|
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)
|
|
}
|