Repository: danielgtaylor/huma
Pull request #434 (2024-05-10 03:27:06)

feat: convenience methods with operationHandlers


Patch:
diff --git a/huma.go b/huma.go
index 9a21d86..8d0a0a9 100644
--- a/huma.go
+++ b/huma.go
@@ -1461,14 +1461,24 @@ var GenerateSummary = func(method, path string, response any) string {
 	return strings.ToUpper(phrase[:1]) + phrase[1:]
 }
 
-func convenience[I, O any](api API, method, path string, handler func(context.Context, *I) (*O, error)) {
+func OperationTags(tags ...string) func(o *Operation) {
+	return func(o *Operation) {
+		o.Tags = tags
+	}
+}
+
+func convenience[I, O any](api API, method, path string, handler func(context.Context, *I) (*O, error), operationHandlers ...func(o *Operation)) {
 	var o *O
-	Register(api, Operation{
+	operation := Operation{
 		OperationID: GenerateOperationID(method, path, o),
 		Summary:     GenerateSummary(method, path, o),
 		Method:      method,
 		Path:        path,
-	}, handler)
+	}
+	for _, oh := range operationHandlers {
+		oh(&operation)
+	}
+	Register(api, operation, handler)
 }
 
 // Get HTTP operation handler for an API. The handler must be a function that
@@ -1488,8 +1498,8 @@ func convenience[I, O any](api API, method, path string, handler func(context.Co
 //	})
 //
 // This is a convenience wrapper around `huma.Register`.
-func Get[I, O any](api API, path string, handler func(context.Context, *I) (*O, error)) {
-	convenience(api, http.MethodGet, path, handler)
+func Get[I, O any](api API, path string, handler func(context.Context, *I) (*O, error), operationHandlers ...func(o *Operation)) {
+	convenience(api, http.MethodGet, path, handler, operationHandlers...)
 }
 
 // Post HTTP operation handler for an API. The handler must be a function that
@@ -1509,8 +1519,8 @@ func Get[I, O any](api API, path string, handler func(context.Context, *I) (*O,
 //	})
 //
 // This is a convenience wrapper around `huma.Register`.
-func Post[I, O any](api API, path string, handler func(context.Context, *I) (*O, error)) {
-	convenience(api, http.MethodPost, path, handler)
+func Post[I, O any](api API, path string, handler func(context.Context, *I) (*O, error), operationHandlers ...func(o *Operation)) {
+	convenience(api, http.MethodPost, path, handler, operationHandlers...)
 }
 
 // Put HTTP operation handler for an API. The handler must be a function that
@@ -1530,8 +1540,8 @@ func Post[I, O any](api API, path string, handler func(context.Context, *I) (*O,
 //	})
 //
 // This is a convenience wrapper around `huma.Register`.
-func Put[I, O any](api API, path string, handler func(context.Context, *I) (*O, error)) {
-	convenience(api, http.MethodPut, path, handler)
+func Put[I, O any](api API, path string, handler func(context.Context, *I) (*O, error), operationHandlers ...func(o *Operation)) {
+	convenience(api, http.MethodPut, path, handler, operationHandlers...)
 }
 
 // Patch HTTP operation handler for an API. The handler must be a function that
@@ -1551,8 +1561,8 @@ func Put[I, O any](api API, path string, handler func(context.Context, *I) (*O,
 //	})
 //
 // This is a convenience wrapper around `huma.Register`.
-func Patch[I, O any](api API, path string, handler func(context.Context, *I) (*O, error)) {
-	convenience(api, http.MethodPatch, path, handler)
+func Patch[I, O any](api API, path string, handler func(context.Context, *I) (*O, error), operationHandlers ...func(o *Operation)) {
+	convenience(api, http.MethodPatch, path, handler, operationHandlers...)
 }
 
 // Delete HTTP operation handler for an API. The handler must be a function that
@@ -1570,6 +1580,6 @@ func Patch[I, O any](api API, path string, handler func(context.Context, *I) (*O
 //	})
 //
 // This is a convenience wrapper around `huma.Register`.
-func Delete[I, O any](api API, path string, handler func(context.Context, *I) (*O, error)) {
-	convenience(api, http.MethodDelete, path, handler)
+func Delete[I, O any](api API, path string, handler func(context.Context, *I) (*O, error), operationHandlers ...func(o *Operation)) {
+	convenience(api, http.MethodDelete, path, handler, operationHandlers...)
 }


Test patch:
diff --git a/huma_test.go b/huma_test.go
index 5607e82..15333c7 100644
--- a/huma_test.go
+++ b/huma_test.go
@@ -1729,29 +1729,34 @@ func TestConvenienceMethods(t *testing.T) {
 		Body []struct{}
 	}, error) {
 		return nil, nil
-	})
+	}, huma.OperationTags("Things"))
 	assert.Equal(t, "list-things", api.OpenAPI().Paths[path].Get.OperationID)
+	assert.Equal(t, []string{"Things"}, api.OpenAPI().Paths[path].Get.Tags)
 
 	huma.Post(api, path, func(ctx context.Context, input *Input) (*struct{}, error) {
 		return nil, nil
-	})
+	}, huma.OperationTags("Things"))
 	assert.Equal(t, "post-things", api.OpenAPI().Paths[path].Post.OperationID)
+	assert.Equal(t, []string{"Things"}, api.OpenAPI().Paths[path].Post.Tags)
 
 	path = path + "/{thing-id}"
 	huma.Put(api, path, func(ctx context.Context, input *Input) (*struct{}, error) {
 		return nil, nil
-	})
+	}, huma.OperationTags("Things"))
 	assert.Equal(t, "put-things-by-thing-id", api.OpenAPI().Paths[path].Put.OperationID)
+	assert.Equal(t, []string{"Things"}, api.OpenAPI().Paths[path].Put.Tags)
 
 	huma.Patch(api, path, func(ctx context.Context, input *Input) (*struct{}, error) {
 		return nil, nil
-	})
+	}, huma.OperationTags("Things"))
 	assert.Equal(t, "patch-things-by-thing-id", api.OpenAPI().Paths[path].Patch.OperationID)
+	assert.Equal(t, []string{"Things"}, api.OpenAPI().Paths[path].Patch.Tags)
 
 	huma.Delete(api, path, func(ctx context.Context, input *Input) (*struct{}, error) {
 		return nil, nil
-	})
+	}, huma.OperationTags("Things"))
 	assert.Equal(t, "delete-things-by-thing-id", api.OpenAPI().Paths[path].Delete.OperationID)
+	assert.Equal(t, []string{"Things"}, api.OpenAPI().Paths[path].Delete.Tags)
 }
 
 type EmbeddedWithMethod struct{}