Skip to content

发送数据#

让我们升级我们的 API 并从用户接受一些数据。

API 设计
Request:
POST /reviews
{
	"author": "Daniel",
	"rating": 5,
	"message": "Some custom review message"
}

Response: 201 Created

发布评论#

为我们的 API 添加一个新操作,允许用户提交我们产品的评论。

main.go
package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/danielgtaylor/huma/v2"
	"github.com/danielgtaylor/huma/v2/adapters/humachi"
	"github.com/danielgtaylor/huma/v2/humacli"
	"github.com/go-chi/chi/v5"

	_ "github.com/danielgtaylor/huma/v2/formats/cbor"
)

// CLI 的选项。
type Options struct {
	Port int `help:"监听端口" short:"p" default:"8888"`
}

// GreetingOutput 表示问候操作响应。
type GreetingOutput struct {
	Body struct {
		Message string `json:"message" example:"Hello, world!" doc:"问候消息"`
	}
}

// ReviewInput 表示评论操作请求。
type ReviewInput struct {
	Body struct {
		Author  string `json:"author" maxLength:"10" doc:"评论作者"`
		Rating  int    `json:"rating" minimum:"1" maximum:"5" doc:"1 到 5 的评分"`
		Message string `json:"message,omitempty" maxLength:"100" doc:"评论消息"`
	}
}

func main() {
	// 创建一个 CLI 应用,它接受端口选项。
	cli := humacli.New(func(hooks humacli.Hooks, options *Options) {
		// 创建一个新的路由器和 API
		router := chi.NewMux()
		api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0"))

		// 注册 GET /greeting/{name}
		huma.Register(api, huma.Operation{
			OperationID: "get-greeting",
			Method:      http.MethodGet,
			Path:        "/greeting/{name}",
			Summary:     "获取问候语",
			Description: "通过姓名获取一个人的问候语。",
			Tags:        []string{"Greetings"},
		}, func(ctx context.Context, input *struct{
			Name string `path:"name" maxLength:"30" example:"world" doc:"要问候的姓名"`
		}) (*GreetingOutput, error) {
			resp := &GreetingOutput{}
			resp.Body.Message = fmt.Sprintf("Hello, %s!", input.Name)
			return resp, nil
		})

		// 注册 POST /reviews
		huma.Register(api, huma.Operation{
			OperationID:   "post-review",
			Method:        http.MethodPost,
			Path:          "/reviews",
			Summary:       "发布评论",
			Tags:          []string{"Reviews"},
			DefaultStatus: http.StatusCreated,
		}, func(ctx context.Context, i *ReviewInput) (*struct{}, error) {
			// TODO: 在数据存储中保存评论。
			return nil, nil
		})

		// 告诉 CLI 如何启动你的服务器。
		hooks.OnStart(func() {
			fmt.Printf("Starting server on port %d...\n", options.Port)
			http.ListenAndServe(fmt.Sprintf(":%d", options.Port), router)
		})
	})

	// 运行 CLI。当传递无命令时,它启动服务器。
	cli.Run()
}

调用 API#

向 API 发送请求:

你也可以尝试发送无效数据,并查看你的 API 如何返回详尽的错误。将 body 字段中的 author 省略,并使用超出有效值范围的评分:

回顾#

恭喜!你刚刚学到了:

  • 如何为你的 API 添加新操作
  • 如何为操作设置默认状态码
  • 如何从用户接受数据
  • 内置验证如何向用户返回错误
  • 如何使用 omitempty 结构体标签使字段可选

深入了解#

想了解更多关于发送数据的工作原理吗?接下来查看这些: