This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch refactor-with-go
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git
The following commit(s) were added to refs/heads/refactor-with-go by this push:
new ac48a33c add auto generate dubbo admin swagger (#1099)
ac48a33c is described below
commit ac48a33c14219afa5eb9078966e9816efa60ac5a
Author: Jun <[email protected]>
AuthorDate: Sun May 14 11:21:04 2023 +0800
add auto generate dubbo admin swagger (#1099)
---
Makefile | 13 +++
cmd/admin/main.go | 7 ++
hack/swagger/README_ZH.md | 9 ++
hack/swagger/swagger.json | 228 ++++++++++++++++++++++++++++++++++++++++
pkg/admin/handlers/mock_rule.go | 60 +++++++++--
pkg/admin/model/common.go | 26 +++++
pkg/admin/model/mock_rule.go | 5 +
7 files changed, 337 insertions(+), 11 deletions(-)
diff --git a/Makefile b/Makefile
index 5110b55b..eb091d2c 100644
--- a/Makefile
+++ b/Makefile
@@ -58,10 +58,12 @@ $(LOCALBIN):
## Tool Binaries
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
+SWAGGER ?= $(LOCALBIN)/swag
## Tool Versions
KUSTOMIZE_VERSION ?= v3.8.7
CONTROLLER_TOOLS_VERSION ?= v0.10.0
+SWAGGER_VERSION ?= v1.16.1
## docker buildx support platform
PLATFORMS ?= linux/arm64,linux/amd64
@@ -93,6 +95,11 @@ manifests: controller-gen ## Generate WebhookConfiguration,
ClusterRole and Cust
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto,
and DeepCopyObject method implementations.
#$(CONTROLLER_GEN) object:headerFile="./hack/boilerplate.go.txt"
crd:allowDangerousTypes=true paths="./..."
+.PHONY: dubbo-admin-swagger
+dubbo-admin-swagger: swagger-install ## Generate dubbo-admin swagger docs.
+ $(SWAGGER) init -d cmd/admin,pkg/admin -o hack/swagger
+ @rm -f hack/swagger/docs.go hack/swagger/swagger.yaml
+
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...
@@ -214,3 +221,9 @@ controller-gen: $(CONTROLLER_GEN) ## Download
controller-gen locally if necessar
$(CONTROLLER_GEN): $(LOCALBIN)
test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen
--version | grep -q $(CONTROLLER_TOOLS_VERSION) || \
GOBIN=$(LOCALBIN) go install
sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
+
+.PHONY: swagger-install
+swagger-install: $(SWAGGER) ## Download swagger locally if necessary.
+$(SWAGGER): $(LOCALBIN)
+ test -s $(LOCALBIN)/swag || \
+ GOBIN=$(LOCALBIN) go install
github.com/swaggo/swag/cmd/swag@$(SWAGGER_VERSION)
\ No newline at end of file
diff --git a/cmd/admin/main.go b/cmd/admin/main.go
index 72191b6d..0d83716a 100644
--- a/cmd/admin/main.go
+++ b/cmd/admin/main.go
@@ -23,6 +23,13 @@ import (
"github.com/apache/dubbo-admin/pkg/admin/services"
)
+// @title Dubbo-Admin API
+// @version 1.0
+// @description This is a dubbo-admin swagger ui server.
+// @license.name Apache 2.0
+// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
+// @host 127.0.0.1:38080
+// @BasePath /
func main() {
config.LoadConfig()
go services.StartSubscribe(config.RegistryCenter)
diff --git a/hack/swagger/README_ZH.md b/hack/swagger/README_ZH.md
new file mode 100644
index 00000000..f6cb6e7b
--- /dev/null
+++ b/hack/swagger/README_ZH.md
@@ -0,0 +1,9 @@
+# swaggo 使用说明文档
+
+- 文档说明 https://github.com/swaggo/swag/blob/master/README_zh-CN.md
+- 样例代码
https://github.com/swaggo/swag/blob/master/example/celler/controller/examples.go
+
+# 生成 dubbo-admin swagger 文档
+
+在项目根目录下执行 make dubbo-admin-swagger ,在 hack/swagger 目录下生成 swagger.json
+
diff --git a/hack/swagger/swagger.json b/hack/swagger/swagger.json
new file mode 100644
index 00000000..649248f5
--- /dev/null
+++ b/hack/swagger/swagger.json
@@ -0,0 +1,228 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "description": "This is a dubbo-admin swagger ui server.",
+ "title": "Dubbo-Admin API",
+ "contact": {},
+ "license": {
+ "name": "Apache 2.0",
+ "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+ },
+ "version": "1.0"
+ },
+ "host": "127.0.0.1:38080",
+ "basePath": "/",
+ "paths": {
+ "/api/{env}/mock/rule": {
+ "post": {
+ "description": "Create or update MockRule",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "MockRules"
+ ],
+ "summary": "Create or update MockRule",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "description": "MockRule",
+ "name": "mockRule",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.MockRule"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "Delete MockRule by id",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "MockRules"
+ ],
+ "summary": "Delete MockRule by id",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "description": "MockRule",
+ "name": "mockRule",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/model.MockRule"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ },
+ "/api/{env}/mock/rule/list": {
+ "get": {
+ "description": "Get MockRules by page",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "MockRules"
+ ],
+ "summary": "Get MockRules by page",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "dev",
+ "description": "environment",
+ "name": "env",
+ "in": "path"
+ },
+ {
+ "type": "string",
+ "description": "filter condition",
+ "name": "filter",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "page offset",
+ "name": "offset",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "page limit",
+ "name": "limit",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/model.ListMockRulesByPage"
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/model.HTTPError"
+ }
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "model.HTTPError": {
+ "type": "object",
+ "properties": {
+ "error": {
+ "description": "error message",
+ "type": "string"
+ }
+ }
+ },
+ "model.ListMockRulesByPage": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/model.MockRule"
+ }
+ },
+ "total": {
+ "type": "integer"
+ }
+ }
+ },
+ "model.MockRule": {
+ "type": "object",
+ "properties": {
+ "enable": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "methodName": {
+ "type": "string"
+ },
+ "rule": {
+ "type": "string"
+ },
+ "serviceName": {
+ "type": "string"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/pkg/admin/handlers/mock_rule.go b/pkg/admin/handlers/mock_rule.go
index 27ad3a35..f0677e21 100644
--- a/pkg/admin/handlers/mock_rule.go
+++ b/pkg/admin/handlers/mock_rule.go
@@ -33,64 +33,102 @@ var mockRuleService services.MockRuleService =
&services.MockRuleServiceImpl{
Logger: logger.Logger(),
}
+// CreateOrUpdateMockRule godoc
+// @Summary Create or update MockRule
+// @Description Create or update MockRule
+// @Tags MockRules
+// @Accept json
+// @Produce json
+// @Param env path string false "environment"
default(dev)
+// @Param mockRule body model.MockRule true "MockRule"
+// @Success 201 {boolean} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/mock/rule [post]
func CreateOrUpdateMockRule(c *gin.Context) {
var mockRule *model.MockRule
if err := c.ShouldBindJSON(&mockRule); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error:
err.Error()})
return
}
if err := mockRuleService.CreateOrUpdateMockRule(mockRule); err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error":
err.Error()})
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error:
err.Error()})
return
}
c.JSON(http.StatusCreated, true)
}
+// DeleteMockRuleById godoc
+// @Summary Delete MockRule by id
+// @Description Delete MockRule by id
+// @Tags MockRules
+// @Accept json
+// @Produce json
+// @Param env path string false "environment"
default(dev)
+// @Param mockRule body model.MockRule true "MockRule"
+// @Success 200 {boolean} true
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/mock/rule [delete]
func DeleteMockRuleById(c *gin.Context) {
// TODO use c.Param("id") instead of http body
// id, err := strconv.ParseInt(c.Param("id"), 10, 64)
var mockRule *model.MockRule
if err := c.ShouldBindJSON(&mockRule); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error:
err.Error()})
return
}
if mockRule.ID == 0 {
- c.JSON(http.StatusBadRequest, gin.H{"error": "id is required"})
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error: "id is
required"})
return
}
if err := mockRuleService.DeleteMockRuleById(int64(mockRule.ID)); err
!= nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error:
err.Error()})
return
}
c.JSON(http.StatusOK, true)
}
+// ListMockRulesByPage godoc
+// @Summary Get MockRules by page
+// @Description Get MockRules by page
+// @Tags MockRules
+// @Accept json
+// @Produce json
+// @Param env path string false "environment"
default(dev)
+// @Param filter query string false "filter condition"
+// @Param offset query int false "page offset"
+// @Param limit query int false "page limit"
+// @Success 200 {object} model.ListMockRulesByPage
+// @Failure 400 {object} model.HTTPError
+// @Failure 500 {object} model.HTTPError
+// @Router /api/{env}/mock/rule/list [get]
func ListMockRulesByPage(c *gin.Context) {
filter := c.Query("filter")
offset, err := strconv.Atoi(c.DefaultQuery("offset", "0"))
if err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error:
err.Error()})
return
}
limit, err := strconv.Atoi(c.DefaultQuery("limit", "-1"))
if err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ c.JSON(http.StatusBadRequest, model.HTTPError{Error:
err.Error()})
return
}
mockRules, total, err := mockRuleService.ListMockRulesByPage(filter,
offset, limit)
if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error":
err.Error()})
+ c.JSON(http.StatusInternalServerError, model.HTTPError{Error:
err.Error()})
return
}
// FIXME: the response data is not compatible with the frontend
- c.JSON(http.StatusOK, gin.H{
- "total": total,
- "content": mockRules,
+ c.JSON(http.StatusOK, model.ListMockRulesByPage{
+ Total: total,
+ Content: mockRules,
})
}
diff --git a/pkg/admin/model/common.go b/pkg/admin/model/common.go
new file mode 100644
index 00000000..0ea9dc47
--- /dev/null
+++ b/pkg/admin/model/common.go
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package model
+
+type HTTPError struct {
+ // error message
+ Error string `json:"error"`
+}
+
+type ResponseAny struct {
+ Code int `json:"code"`
+ Data any `json:"data"`
+}
diff --git a/pkg/admin/model/mock_rule.go b/pkg/admin/model/mock_rule.go
index eaab05db..e27d0a0c 100644
--- a/pkg/admin/model/mock_rule.go
+++ b/pkg/admin/model/mock_rule.go
@@ -62,3 +62,8 @@ func (m *MockRuleEntity) ToMockRule() *MockRule {
func (m *MockRuleEntity) TableName() string {
return "mock_rule"
}
+
+type ListMockRulesByPage struct {
+ Total int64 `json:"total"`
+ Content []*MockRule `json:"content"`
+}