All skills
gogf avatar

/goframe-v2

@911705d
by GoFramegogf/skills81 stars
3

GoFrame v2 development skill. Use only when the target Go project uses or is explicitly adopting GoFrame v2: the nearest go.mod requires github.com/gogf/gf/v2, existing Go files import github.com/gogf/gf/v2 or any github.com/gogf/gf/v2/... component package, or the user asks to scaffold, migrate, or build with GoFrame. Trigger for GoFrame-backed Go work such as APIs/controllers/services, middleware, routing/config, ORM/DAO/DO/entity/database operations, gf CLI/codegen, HTTP/gRPC services, and microservice conventions. Do not trigger for generic Go projects without GoFrame evidence, frontend-only work, shell scripts, or unrelated infrastructure tasks.

Use this Skill: https://skilld.dev/gh/gogf/skills/goframe-v2

This session only. Nothing lands on disk.

references核心组件命令管理命令管理-结构化参数.md

命令行管理痛点

前面我们介绍的命令行管理,都是通过回调函数的 parser 对象获取解析的参数及选项数据,在使用的时候存在以下痛点:

  • 需要手动传入硬编码的参数索引或者选项名称信息来获取数据
  • 难以定义参数/选项的说明介绍
  • 难以定义参数/选项的数据类型
  • 难以对参数/选项进行通用性的数据校验
  • 对于需要管理大量命令行的项目是个灾难

对象化管理命令

我们来一个最简单的结构化管理参数示例。我们将前面介绍过的 Command 示例改造为结构化管理:

package main

import (
    "context"
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/os/gcmd"
    "github.com/gogf/gf/v2/os/gctx"
)

type cMain struct {
    g.Meta `name:"main"`
}

type cMainHttpInput struct {
    g.Meta `name:"http" brief:"start http server"`
}
type cMainHttpOutput struct{}

type cMainGrpcInput struct {
    g.Meta `name:"grpc" brief:"start grpc server"`
}
type cMainGrpcOutput struct{}

func (c *cMain) Http(ctx context.Context, in cMainHttpInput) (out *cMainHttpOutput, err error) {
    fmt.Println("start http server")
    return
}

func (c *cMain) Grpc(ctx context.Context, in cMainGrpcInput) (out *cMainGrpcOutput, err error) {
    fmt.Println("start grpc server")
    return
}

func main() {
    cmd, err := gcmd.NewFromObject(cMain{})
    if err != nil {
        panic(err)
    }
    cmd.Run(gctx.New())
}

可以看到,我们通过对象的形式来管理父级命令,通过方法的形式来管理其下一层级的子级命令,并通过规范化的 Input 输入参数对象来定义子级命令的描述/参数/选项。大部分场景下,大家可以忽略 Output 返回对象的使用,但为规范化及扩展性需要保留,如果未用到,该返回参数直接返回 nil 即可。关于其中的结构体标签,后续会有介绍。

我们将示例代码编译后,执行查看效果:

$ main
USAGE
    main COMMAND [OPTION]

COMMAND
    http    start http server
    grpc    start grpc server

DESCRIPTION
    this is the command entry for starting your process

使用 HTTP 命令:

$ main http
start http server

使用 grpc 命令:

$ main grpc
start grpc server

效果和前面介绍的示例一致。

结构化管理入参

既然命令行通过对象化管理,我们仔细看看参数/选项是如何通过结构化管理。

我们将上面的实例简化一下,来个简单的例子,实现通过 http 命令开启 HTTP 服务:

package main

import (
    "context"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/net/ghttp"
    "github.com/gogf/gf/v2/os/gcmd"
    "github.com/gogf/gf/v2/os/gctx"
)

type cMain struct {
    g.Meta `name:"main" brief:"start http server"`
}

type cMainHttpInput struct {
    g.Meta `name:"http" brief:"start http server"`
    Name   string `v:"required" name:"NAME" arg:"true" brief:"server name"`
    Port   int    `v:"required" short:"p" name:"port"  brief:"port of http server"`
}
type cMainHttpOutput struct{}

func (c *cMain) Http(ctx context.Context, in cMainHttpInput) (out *cMainHttpOutput, err error) {
    s := g.Server(in.Name)
    s.BindHandler("/", func(r *ghttp.Request) {
        r.Response.Write("Hello world")
    })
    s.SetPort(in.Port)
    s.Run()
    return
}

func main() {
    cmd, err := gcmd.NewFromObject(cMain{})
    if err != nil {
        panic(err)
    }
    cmd.Run(gctx.New())
}

我们为 http 命令定义了两个输入参数:

  • NAME 服务的名称,通过参数输入。这里使用了大写形式,方便展示在自动生成的帮助信息中
  • port 服务的端口,通过 p/port 选项输入

并且我们通过v:"required"校验标签为这两个参数都绑定的必需的校验规则。是的,在GoFrame框架中,只要涉及到校验的地方都使用了统一的校验组件,具体请参考章节:数据校验

我们编译后执行看看效果:

$ main http
arguments validation failed for command "http": The Name field is required
1. arguments validation failed for command "http"
   1).  github.com/gogf/gf/v2/os/gcmd.newCommandFromMethod.func1
        /Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_object.go:290
   2).  github.com/gogf/gf/v2/os/gcmd.(*Command).doRun
        /Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:120
   3).  github.com/gogf/gf/v2/os/gcmd.(*Command).RunWithValueError
        /Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:77
   4).  github.com/gogf/gf/v2/os/gcmd.(*Command).RunWithValue
        /Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:32
   5).  github.com/gogf/gf/v2/os/gcmd.(*Command).Run
        /Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/os/gcmd/gcmd_command_run.go:26
   6).  main.main
        /Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.test/test.go:38
2. The Name field is required

执行后,报错了,这个错误来自于数据校验,表示必须参数( Name/Port)必须传递。 :::tip 这里的报错打印了堆栈信息,因为 GoFrame 框架采用了全错误堆栈设计,所有组件错误都会带有自底向上的错误堆栈,以方便错误快速定位。当然我们可以通过 RunWithError 方法获取返回的错误对象关闭堆栈信息。 ::: 我增加参数输入再试试:

$ main http my-http-server -p 8199
2022-01-19 22:52:45.808 [DEBU] openapi specification is disabled

      SERVER     | DOMAIN  | ADDRESS | METHOD | ROUTE |                             HANDLER                             |    MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
  my-http-server | default | :8199   | ALL    | /     | main.(*cMain).Http.func1                                        |
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------
  my-http-server | default | :8199   | ALL    | /*    | github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing | GLOBAL MIDDLEWARE
-----------------|---------|---------|--------|-------|-----------------------------------------------------------------|--------------------

2022-01-19 22:52:45.810 66292: http server started listening on [:8199]

是的,这就对了。

完整使用案例

GoFrame 框架的开发工具广泛使用了对象化、结构化的命令行管理,大家感兴趣可以更进一步查看源码了解:https://github.com/gogf/gf/tree/master/cmd/gf

预定义的标签

在结构化设计中,我们使用了一些结构体标签,大部分来源于 Command 命令的属性,这里我们来介绍一下:

标签 缩写 说明 注意事项
name - 命名名称 如果是输入参数结构体,在未指定 name 时将会自动读取 方法名称 作为 name
short - 命令缩写
usage - 命令使用
brief - 命令描述
arg - 表示该输入参数来源于参数而不是选项 仅用于属性标签
orphan - 表示该选项不带参数 属性通常为 bool 类型
description dc 命令的详细介绍
additional ad 命令的额外描述信息
examples eg 命令的使用示例
root - 指定子级命令名称是父级命令,其他方法是它的子级命令 仅用于 主命令 对象结构体 Meta 标签
strict - 表示该命令严格解析参数/选项,当输入不支持的参数/选项时,返回错误 仅用于对象结构体 Meta 标签
config - 表示该命令的选项数据支持从指定的配置读取,配置来源于默认的全局单例配置对象 仅用于方法输入结构体 Meta 标签
default d 表示该输入参数不传递时使用默认值 仅用于属性标签

高级特性

自动数据转换

结构化的参数输入支持自动的数据类型转换,您只需要定义好数据类型,其他的事情交给框架组件即可。自动数据类型转换出现在框架的很多组件中,特别是 HTTP/gRPC 服务的参数输入中。底层数据转换组件使用的是:类型转换 :::tip 命令行参数的数据转换采用 不区分大小写、且忽略特殊字符 的规则来匹配属性字段。例如,如果入参结构体中存在 Name 字段属性,无论命令行输入 name 还是 NAME 的命名参数,都将能被 Name 字段属性接收。 :::

自动数据校验

同样的,数据校验组件也是使用的统一的组件,具体请参考章节: 数据校验

从配置读取数据

当命令行中没有传递对应的数据时,输入参数的结构体数据支持从配置组件中自动获取,只需要在 Meta 中设置 config 标签即可,配置来源于默认的全局单例配置对象。具体示例可以参考 GoFrame 框架开发工具源码:https://github.com/gogf/gf/tree/master/cmd/gf

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk MEDIUM
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive development guide and code examples for the GoFrame v2 framework. While highly informative for Go developers, it contains several examples with hardcoded placeholder secrets, tokens, and specific local file paths to sensitive configuration files (like Kubernetes credentials). These elements are provided for demonstration purposes but represent insecure practices if used in production without modification.

  • Socket16d

    5 alerts: gptSecurity, gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    227/949 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 911705d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 4 months ago.

Steadyupdated 4 months ago
  • Go
  • Database
  • goframe
  • orm
  • http
  • grpc
  • microservices
  • crud
  • scaffolding
  • middleware

README badge

README badge for gogf/skills

Provides instruction and conventions for developing with GoFrame v2, a modular Go framework for building HTTP and gRPC services, microservices, and database operations using its ORM, CLI tooling, and project scaffolding. Use this skill when the target project has GoFrame v2 as a dependency or when the user requests scaffolding, migrations, or service development with GoFrame conventions.

Generated from the current SKILL.md.

When should I use this skill?
Use this skill only when your Go project uses GoFrame v2, indicated by github.com/gogf/gf/v2 in go.mod or imports. Do not use for generic Go projects, frontend work, or infrastructure tasks unrelated to GoFrame.
Should I manually set created_at and updated_at fields?
No. GoFrame automatically writes created_at on insert and updated_at on insert/update/save. Manually setting these fields is redundant and violates project conventions.
What should I use for database operations instead of g.Map?
Always use DO objects from internal/model/do/. DO struct fields are interface{}, unset fields remain nil and are automatically ignored by the ORM.
How does soft delete work in GoFrame?
Call Delete() on the DAO; GoFrame automatically converts it to UPDATE SET deleted_at = NOW(). Queries automatically filter out soft-deleted rows without requiring manual WhereNull conditions.
Where should I implement business logic?
Implement business logic directly in the service/ directory. Do not use the logic/ directory unless explicitly requested.

Generated from the current SKILL.md. These answers refresh after source changes.