agentleFS
weedboxweedbox/skills/crud-api-dev/SKILL.md

crud-api-dev

Skill1 starsChanged 4 months agoApache-2.0View on GitHub

Priority: HIGH — Self-contained reference. This file and its reference docs contain ALL necessary patterns for CRUD API development. DO NOT fetch source code from GitHub. Complete CRUD API and business logic development guide with API layer, business logic layer, data models, query mechanism (using queryhelper), error handling, and dependency injection. Use when: building REST APIs, implementing CRUD operations, creating manager modules, designing data models with GORM, handling pagination/search/filtering with queryhelper. Keywords: CRUD, REST API, Gin, GORM, queryhelper, pagination, filtering, HTTP handler, REST endpoint, API handler, list API, create API, update API, delete API, Swagger, request binding.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Always prefix index names with table name:

    line 136

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

CRUD API Development Guide

Source of Truth: This file and its reference docs (references/*.md) are the complete reference for CRUD API development patterns. DO NOT browse GitHub to look up source code.

This guide explains how to develop complete CRUD (Create, Read, Update, Delete) functionality, covering both API layer and business logic layer implementation patterns.

Directory Structure

A complete CRUD feature requires two modules:

pkg/
├── myresource/                    # Business logic layer (Manager)
│   ├── module.go                  # Module definition and FX setup
│   ├── manager.go                 # Core CRUD business logic
│   ├── codec.go                   # Internal data structures and config
│   ├── errors.go                  # Error definitions
│   └── models/
│       └── myresource.go          # GORM database model
│
└── myresource_apis/               # API layer
    ├── module.go                  # Module definition and route registration
    ├── apis.go                    # HTTP Handler implementation
    └── codec.go                   # Request/Response structures

Layer Overview

Business Logic Layer (Manager)

Handles core business logic, database operations, and data validation.

Key Components:

  • Database models with GORM tags
  • Error definitions
  • CRUD operations (Create, Get, Update, Delete, List)
  • QueryHelper integration for pagination/search/filtering

For complete implementation details, see ./references/LOGIC_LAYER.md.

API Layer

Handles HTTP routing, request binding, and response formatting.

Key Components:

  • Request structs separated into URI/Body/Query
  • Response structs
  • HTTP handlers with Swagger annotations
  • Gin binding with proper order

For complete implementation details, see ./references/API_LAYER.md.


Quick Reference

Request Binding Pattern

Separate request structs to avoid Gin binding conflicts:

type CreateRequestURI struct {
    WorkspaceID string `uri:"workspace_id" binding:"required"`
}

type CreateRequestBody struct {
    Name   string `json:"name" binding:"required"`
    Status string `json:"status" binding:"omitempty,oneof=active inactive"`
}

type CreateRequest struct {
    URI  CreateRequestURI
    Body CreateRequestBody
}

Binding order: URI → Query → Body

func (m *MyAPIs) create(c *gin.Context) {
    var req CreateRequest

    if err := c.ShouldBindUri(&req.URI); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    if err := c.ShouldBindJSON(&req.Body); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    // Use req.URI.WorkspaceID, req.Body.Name, etc.
}

Module Pattern (Method 2)

See ../module-dev/SKILL.md for the module creation methods.

type Params struct {
    weedbox.Params
    HTTPServer *http_server.HTTPServer
    MyResource *myresource.MyResourceManager `name:"myresource"`
}

type MyResourceAPIs struct {
    weedbox.Module[*Params]
}

func Module(scope string) fx.Option {
    m := new(MyResourceAPIs)
    return fx.Module(scope,
        fx.Supply(fx.Annotated{Name: scope, Target: m}),
        fx.Invoke(func(p Params) { weedbox.InitModule(scope, &p, m) }),
    )
}

Index Naming Convention

Always prefix index names with table name:

type MyResource struct {
    Name   string `gorm:"uniqueIndex:idx_myresource_name"`
    Status string `gorm:"index:idx_myresource_status"`
}

QueryHelper Usage

Basic Setup

qh := queryhelper.NewQueryHelper(
    queryhelper.WithPage(1),
    queryhelper.WithPageSize(10),
    queryhelper.WithSearchText("keyword"),
    queryhelper.WithSearchFields([]string{"name", "description"}),
    queryhelper.WithOrderBy([]string{"created_at"}),
    queryhelper.WithSortFactor(-1),  // 1=asc, -1=desc
    queryhelper.WithFilters(filters),
)

Security Settings

var DefaultQuerySettings_ListResources = &queryhelper.QuerySettings{
    AllowedOrderBy: []string{"created_at", "updated_at", "name"},
    AllowedSearch:  []string{"name", "description"},
    AllowedFilters: map[string][]string{
        "status": {"=", "!=", "IN"},
        "name":   {"=", "LIKE"},
    },
}

Supported Operators

OperatorPurposeExample
=Equalstatus = "active"
!=Not equalstatus != "deleted"
>, <, >=, <=Numeric comparisonprice >= 100
BETWEENRange querycreated_at BETWEEN ...
INList membershipstatus IN ["active", "pending"]
LIKEPattern matchingname LIKE "%test%"

Best Practices

Naming Conventions

ItemConventionExample
Module namelowercase_underscoremyresource, myresource_apis
Table namelowercase_underscore_pluralmy_resources
API path (list)Plural form/resources
API path (CRUD)Singular form/resource, /resource/:id
Index nameidx_<table>_<column>idx_myresource_status
Request struct<Action>Request{URI,Body,Query}CreateRequestURI

HTTP Status Codes

OperationSuccessCommon Errors
Create201 Created400, 409, 500
Get200 OK404, 500
Update200 OK400, 404, 500
Delete200 OK404, 500
List200 OK400, 500

Time Format

API responses should use RFC3339 format (UTC):

CreatedAt: r.CreatedAt.UTC().Format(time.RFC3339)
// Output: 2024-01-15T08:30:00Z

Module Registration

// modules.go
func loadModules() ([]fx.Option, error) {
    modules := []fx.Option{
        // Business logic layer
        myresource.Module("myresource"),

        // API layer
        myresource_apis.Module("myresource_apis"),
    }
    return modules, nil
}

Development Checklist

Business Logic Layer

  • Create pkg/myresource/ directory
  • Define database model models/myresource.go
  • Define errors errors.go
  • Define internal structures codec.go
  • Implement module definition module.go
  • Implement CRUD methods manager.go
  • Configure QuerySettings
  • Register module in modules.go

API Layer

  • Create pkg/myresource_apis/ directory
  • Define request structures with URI/Body/Query separation codec.go
  • Define response structures and ErrorResponse codec.go
  • Implement module definition (Method 2) module.go
  • Implement HTTP handlers with proper binding order apis.go
  • Add Swagger annotations (tab-indented format)
  • Register module in modules.go
  • Run swag init --parseDependency --parseDependencyLevel 3 to update docs

Related Documentation

  • ./references/LOGIC_LAYER.md - Business logic layer details
  • ./references/API_LAYER.md - API layer details

References

  • QueryHelper package: github.com/weedbox/queryhelper

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.