Skip to content

Commit 384e746

Browse files
authored
api: support get json format for config by setting Accept header (#484)
1 parent 5d2dfc2 commit 384e746

File tree

6 files changed

+68
-27
lines changed

6 files changed

+68
-27
lines changed

pkg/server/api/config.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package api
66
import (
77
"io"
88
"net/http"
9+
"strings"
910

1011
"github.com/gin-gonic/gin"
1112
"github.com/pingcap/tiproxy/lib/util/errors"
@@ -35,10 +36,11 @@ func (h *Server) ConfigSet(c *gin.Context) {
3536
}
3637

3738
func (h *Server) ConfigGet(c *gin.Context) {
38-
switch c.Query("format") {
39-
case "json":
39+
// TiDB cluster_config uses format=json, while tiproxyctl expects toml (both PUT and GET) by default.
40+
// Users can choose the format on TiDB-Dashboard.
41+
if strings.EqualFold(c.Query("format"), "json") || c.GetHeader("Accept") == "application/json" {
4042
c.JSON(http.StatusOK, h.mgr.cfg.GetConfig())
41-
default:
43+
} else {
4244
c.TOML(http.StatusOK, h.mgr.cfg.GetConfig())
4345
}
4446
}

pkg/server/api/config_test.go

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44
package api
55

66
import (
7+
"encoding/json"
78
"io"
89
"net/http"
910
"regexp"
1011
"strings"
1112
"testing"
1213

14+
"github.com/BurntSushi/toml"
15+
"github.com/pingcap/tiproxy/lib/config"
1316
"github.com/stretchr/testify/require"
1417
)
1518

1619
func TestConfig(t *testing.T) {
1720
_, doHTTP := createServer(t, nil)
1821

19-
doHTTP(t, http.MethodGet, "/api/admin/config", nil, func(t *testing.T, r *http.Response) {
22+
doHTTP(t, http.MethodGet, "/api/admin/config", nil, nil, func(t *testing.T, r *http.Response) {
2023
all, err := io.ReadAll(r.Body)
2124
require.NoError(t, err)
2225
require.Equal(t, `
@@ -72,42 +75,75 @@ max-backups = 3
7275
`, string(regexp.MustCompile("workdir = '.+'\n").ReplaceAll(all, nil)))
7376
require.Equal(t, http.StatusOK, r.StatusCode)
7477
})
75-
doHTTP(t, http.MethodGet, "/api/admin/config?format=json", nil, func(t *testing.T, r *http.Response) {
78+
doHTTP(t, http.MethodGet, "/api/admin/config?format=json", nil, nil, func(t *testing.T, r *http.Response) {
7679
all, err := io.ReadAll(r.Body)
7780
require.NoError(t, err)
7881
require.Equal(t, `{"proxy":{"addr":"0.0.0.0:6000","pd-addrs":"127.0.0.1:2379","frontend-keepalive":{"enabled":true},"backend-healthy-keepalive":{"enabled":true,"idle":60000000000,"cnt":5,"intvl":3000000000,"timeout":15000000000},"backend-unhealthy-keepalive":{"enabled":true,"idle":10000000000,"cnt":5,"intvl":1000000000,"timeout":5000000000},"graceful-close-conn-timeout":15},"api":{"addr":"0.0.0.0:3080"},"advance":{"ignore-wrong-namespace":true},"security":{"server-tls":{"min-tls-version":"1.2"},"server-http-tls":{"min-tls-version":"1.2"},"cluster-tls":{"min-tls-version":"1.2"},"sql-tls":{"min-tls-version":"1.2"}},"log":{"encoder":"tidb","level":"info","log-file":{"max-size":300,"max-days":3,"max-backups":3}}}`,
7982
string(regexp.MustCompile(`"workdir":"[^"]+",`).ReplaceAll(all, nil)))
8083
require.Equal(t, http.StatusOK, r.StatusCode)
8184
})
8285

83-
doHTTP(t, http.MethodPut, "/api/admin/config", strings.NewReader("security.require-backend-tls = true"), func(t *testing.T, r *http.Response) {
86+
doHTTP(t, http.MethodPut, "/api/admin/config", strings.NewReader("security.require-backend-tls = true"), nil, func(t *testing.T, r *http.Response) {
8487
require.Equal(t, http.StatusOK, r.StatusCode)
8588
})
8689
sum := ""
8790
sumreg := regexp.MustCompile(`{"config_checksum":(.+)}`)
88-
doHTTP(t, http.MethodGet, "/api/debug/health", nil, func(t *testing.T, r *http.Response) {
91+
doHTTP(t, http.MethodGet, "/api/debug/health", nil, nil, func(t *testing.T, r *http.Response) {
8992
all, err := io.ReadAll(r.Body)
9093
require.NoError(t, err)
9194
sum = string(sumreg.Find(all))
9295
require.Equal(t, http.StatusOK, r.StatusCode)
9396
})
94-
doHTTP(t, http.MethodPut, "/api/admin/config", strings.NewReader("proxy.require-back = false"), func(t *testing.T, r *http.Response) {
97+
doHTTP(t, http.MethodPut, "/api/admin/config", strings.NewReader("proxy.require-back = false"), nil, func(t *testing.T, r *http.Response) {
9598
// no error
9699
require.Equal(t, http.StatusOK, r.StatusCode)
97100
})
98-
doHTTP(t, http.MethodGet, "/api/debug/health", nil, func(t *testing.T, r *http.Response) {
101+
doHTTP(t, http.MethodGet, "/api/debug/health", nil, nil, func(t *testing.T, r *http.Response) {
99102
all, err := io.ReadAll(r.Body)
100103
require.NoError(t, err)
101104
require.Equal(t, sum, string(sumreg.Find(all)))
102105
require.Equal(t, http.StatusOK, r.StatusCode)
103106
})
104-
doHTTP(t, http.MethodPut, "/api/admin/config", strings.NewReader("security.require-backend-tls = false"), func(t *testing.T, r *http.Response) {
107+
doHTTP(t, http.MethodPut, "/api/admin/config", strings.NewReader("security.require-backend-tls = false"), nil, func(t *testing.T, r *http.Response) {
105108
require.Equal(t, http.StatusOK, r.StatusCode)
106109
})
107-
doHTTP(t, http.MethodGet, "/api/debug/health", nil, func(t *testing.T, r *http.Response) {
110+
doHTTP(t, http.MethodGet, "/api/debug/health", nil, nil, func(t *testing.T, r *http.Response) {
108111
all, err := io.ReadAll(r.Body)
109112
require.NoError(t, err)
110113
require.NotEqual(t, sum, string(sumreg.Find(all)))
111114
require.Equal(t, http.StatusOK, r.StatusCode)
112115
})
113116
}
117+
118+
func TestAcceptType(t *testing.T) {
119+
_, doHTTP := createServer(t, nil)
120+
checkRespContentType := func(expectedType string, r *http.Response) {
121+
require.Equal(t, http.StatusOK, r.StatusCode)
122+
data, err := io.ReadAll(r.Body)
123+
require.NoError(t, err)
124+
var cfg config.Config
125+
switch expectedType {
126+
case "json":
127+
require.Contains(t, r.Header.Get("Content-Type"), "application/json")
128+
require.NoError(t, json.Unmarshal(data, &cfg))
129+
default:
130+
require.Contains(t, r.Header.Get("Content-Type"), "application/toml")
131+
require.NoError(t, toml.Unmarshal(data, &cfg))
132+
}
133+
}
134+
doHTTP(t, http.MethodGet, "/api/admin/config", nil, nil, func(t *testing.T, r *http.Response) {
135+
checkRespContentType("toml", r)
136+
})
137+
doHTTP(t, http.MethodGet, "/api/admin/config", nil, map[string]string{"Accept": "application/json"}, func(t *testing.T, r *http.Response) {
138+
checkRespContentType("json", r)
139+
})
140+
doHTTP(t, http.MethodGet, "/api/admin/config", nil, map[string]string{"Accept": "application/toml"}, func(t *testing.T, r *http.Response) {
141+
checkRespContentType("toml", r)
142+
})
143+
doHTTP(t, http.MethodGet, "/api/admin/config?format=json", nil, nil, func(t *testing.T, r *http.Response) {
144+
checkRespContentType("json", r)
145+
})
146+
doHTTP(t, http.MethodGet, "/api/admin/config?format=JSON", nil, nil, func(t *testing.T, r *http.Response) {
147+
checkRespContentType("json", r)
148+
})
149+
}

pkg/server/api/debug_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ func TestDebug(t *testing.T) {
1414
closing := true
1515
_, doHTTP := createServer(t, &closing)
1616

17-
doHTTP(t, http.MethodGet, "/api/debug/health", nil, func(t *testing.T, r *http.Response) {
17+
doHTTP(t, http.MethodGet, "/api/debug/health", nil, nil, func(t *testing.T, r *http.Response) {
1818
require.Equal(t, http.StatusBadGateway, r.StatusCode)
1919
})
2020

2121
closing = false
22-
doHTTP(t, http.MethodGet, "/api/debug/health", nil, func(t *testing.T, r *http.Response) {
22+
doHTTP(t, http.MethodGet, "/api/debug/health", nil, nil, func(t *testing.T, r *http.Response) {
2323
require.Equal(t, http.StatusOK, r.StatusCode)
2424
})
2525

26-
doHTTP(t, http.MethodPost, "/api/debug/redirect", nil, func(t *testing.T, r *http.Response) {
26+
doHTTP(t, http.MethodPost, "/api/debug/redirect", nil, nil, func(t *testing.T, r *http.Response) {
2727
require.Equal(t, http.StatusOK, r.StatusCode)
2828
})
29-
doHTTP(t, http.MethodGet, "/api/debug/redirect", nil, func(t *testing.T, r *http.Response) {
29+
doHTTP(t, http.MethodGet, "/api/debug/redirect", nil, nil, func(t *testing.T, r *http.Response) {
3030
require.Equal(t, http.StatusNotFound, r.StatusCode)
3131
})
3232

33-
doHTTP(t, http.MethodGet, "/api/debug/pprof", nil, func(t *testing.T, r *http.Response) {
33+
doHTTP(t, http.MethodGet, "/api/debug/pprof", nil, nil, func(t *testing.T, r *http.Response) {
3434
require.Equal(t, http.StatusOK, r.StatusCode)
3535
})
3636
}

pkg/server/api/metrics_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
func TestMetrics(t *testing.T) {
1414
_, doHTTP := createServer(t, nil)
1515

16-
doHTTP(t, http.MethodGet, "/api/metrics", nil, func(t *testing.T, r *http.Response) {
16+
doHTTP(t, http.MethodGet, "/api/metrics", nil, nil, func(t *testing.T, r *http.Response) {
1717
require.Equal(t, http.StatusOK, r.StatusCode)
1818
})
1919
}

pkg/server/api/namespace_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,42 @@ func TestNamespace(t *testing.T) {
1616
_, doHTTP := createServer(t, nil)
1717

1818
// test list
19-
doHTTP(t, http.MethodGet, "/api/admin/namespace", nil, func(t *testing.T, r *http.Response) {
19+
doHTTP(t, http.MethodGet, "/api/admin/namespace", nil, nil, func(t *testing.T, r *http.Response) {
2020
all, err := io.ReadAll(r.Body)
2121
require.NoError(t, err)
2222
require.Equal(t, `""`, string(all))
2323
require.Equal(t, http.StatusOK, r.StatusCode)
2424
})
2525

2626
// test set
27-
doHTTP(t, http.MethodPut, "/api/admin/namespace/gg", strings.NewReader(`{}`), func(t *testing.T, r *http.Response) {
27+
doHTTP(t, http.MethodPut, "/api/admin/namespace/gg", strings.NewReader(`{}`), nil, func(t *testing.T, r *http.Response) {
2828
require.Equal(t, http.StatusOK, r.StatusCode)
2929
})
30-
doHTTP(t, http.MethodPut, "/api/admin/namespace", strings.NewReader(`{"namespace": "dge"}`), func(t *testing.T, r *http.Response) {
30+
doHTTP(t, http.MethodPut, "/api/admin/namespace", strings.NewReader(`{"namespace": "dge"}`), nil, func(t *testing.T, r *http.Response) {
3131
require.Equal(t, http.StatusOK, r.StatusCode)
3232
})
3333

3434
// test get
35-
doHTTP(t, http.MethodGet, "/api/admin/namespace/dge", nil, func(t *testing.T, r *http.Response) {
35+
doHTTP(t, http.MethodGet, "/api/admin/namespace/dge", nil, nil, func(t *testing.T, r *http.Response) {
3636
all, err := io.ReadAll(r.Body)
3737
require.NoError(t, err)
3838
require.Equal(t, `{"namespace":"dge","frontend":{"user":"","security":{}},"backend":{"instances":null,"security":{}}}`, string(all))
3939
require.Equal(t, http.StatusOK, r.StatusCode)
4040
})
4141

4242
// test remove
43-
doHTTP(t, http.MethodDelete, "/api/admin/namespace/dge", nil, func(t *testing.T, r *http.Response) {
43+
doHTTP(t, http.MethodDelete, "/api/admin/namespace/dge", nil, nil, func(t *testing.T, r *http.Response) {
4444
require.Equal(t, http.StatusOK, r.StatusCode)
4545
})
46-
doHTTP(t, http.MethodGet, "/api/admin/namespace/dge", nil, func(t *testing.T, r *http.Response) {
46+
doHTTP(t, http.MethodGet, "/api/admin/namespace/dge", nil, nil, func(t *testing.T, r *http.Response) {
4747
require.Equal(t, http.StatusInternalServerError, r.StatusCode)
4848
})
4949

5050
// test commit
51-
doHTTP(t, http.MethodPost, "/api/admin/namespace/commit?namespace=xx", nil, func(t *testing.T, r *http.Response) {
51+
doHTTP(t, http.MethodPost, "/api/admin/namespace/commit?namespace=xx", nil, nil, func(t *testing.T, r *http.Response) {
5252
require.Equal(t, http.StatusInternalServerError, r.StatusCode)
5353
})
54-
doHTTP(t, http.MethodPost, "/api/admin/namespace/commit", nil, func(t *testing.T, r *http.Response) {
54+
doHTTP(t, http.MethodPost, "/api/admin/namespace/commit", nil, nil, func(t *testing.T, r *http.Response) {
5555
require.Equal(t, http.StatusInternalServerError, r.StatusCode)
5656
})
5757
}

pkg/server/api/server_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
"google.golang.org/grpc/credentials/insecure"
2222
)
2323

24-
func createServer(t *testing.T, closing *bool) (*Server, func(t *testing.T, method string, path string, rd io.Reader, f func(*testing.T, *http.Response))) {
24+
func createServer(t *testing.T, closing *bool) (*Server, func(t *testing.T, method string, path string, rd io.Reader, header map[string]string, f func(*testing.T, *http.Response))) {
2525
lg, _ := logger.CreateLoggerForTest(t)
2626
ready := atomic.NewBool(true)
2727
cfgmgr := mgrcfg.NewConfigManager()
@@ -43,12 +43,15 @@ func createServer(t *testing.T, closing *bool) (*Server, func(t *testing.T, meth
4343
})
4444

4545
addr := fmt.Sprintf("http://%s", srv.listener.Addr().String())
46-
return srv, func(t *testing.T, method, pa string, rd io.Reader, f func(*testing.T, *http.Response)) {
46+
return srv, func(t *testing.T, method, pa string, rd io.Reader, header map[string]string, f func(*testing.T, *http.Response)) {
4747
if pa[0] != '/' {
4848
pa = "/" + pa
4949
}
5050
req, err := http.NewRequest(method, fmt.Sprintf("%s%s", addr, pa), rd)
5151
require.NoError(t, err)
52+
for key, value := range header {
53+
req.Header.Set(key, value)
54+
}
5255
resp, err := http.DefaultClient.Do(req)
5356
require.NoError(t, err)
5457
f(t, resp)

0 commit comments

Comments
 (0)