Compare commits

...

7 Commits

Author SHA1 Message Date
ljluestc
fc178c9fa0
Merge 92006a551229eced677ce6dc07e450d4ad64e7ef into 5f4f9643258dc2a65e684b63f12c8d543c936c67 2026-05-15 04:09:34 +08:00
dependabot[bot]
5f4f964325
chore(deps): bump the actions group across 1 directory with 2 updates (#4640)
Bumps the actions group with 2 updates in the / directory: [codecov/codecov-action](https://github.com/codecov/codecov-action) and [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action).


Updates `codecov/codecov-action` from 5 to 6
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5...v6)

Updates `aquasecurity/trivy-action` from 0.35.0 to 0.36.0
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.35.0...v0.36.0)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: aquasecurity/trivy-action
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-09 10:20:32 +08:00
ljluestc
92006a5512 fix CI 2026-01-24 09:40:30 -08:00
ljluestc
8ca6e308c6 docs: remove emojis from PR description 2026-01-24 09:37:32 -08:00
ljluestc
7ae74c5272 docs: update PR description 2026-01-24 09:36:23 -08:00
ljluestc
9a76687101 feat: improve json-iterator example and fix tests 2026-01-24 09:27:47 -08:00
ljluestc
e0109c70d9 docs: add json-iterator example 2026-01-24 00:45:32 -08:00
8 changed files with 152 additions and 9 deletions

View File

@ -78,6 +78,6 @@ jobs:
run: make test run: make test
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v6
with: with:
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }} flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}

View File

@ -27,7 +27,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Run Trivy vulnerability scanner (source code) - name: Run Trivy vulnerability scanner (source code)
uses: aquasecurity/trivy-action@0.35.0 uses: aquasecurity/trivy-action@v0.36.0
with: with:
scan-type: "fs" scan-type: "fs"
scan-ref: "." scan-ref: "."
@ -44,7 +44,7 @@ jobs:
sarif_file: "trivy-results.sarif" sarif_file: "trivy-results.sarif"
- name: Run Trivy scanner (table output for logs) - name: Run Trivy scanner (table output for logs)
uses: aquasecurity/trivy-action@0.35.0 uses: aquasecurity/trivy-action@v0.36.0
if: always() if: always()
with: with:
scan-type: "fs" scan-type: "fs"

View File

@ -830,7 +830,11 @@ func TestUriBinding(t *testing.T) {
} }
var not NotSupportStruct var not NotSupportStruct
require.Error(t, b.BindUri(m, &not)) require.Error(t, b.BindUri(m, &not))
assert.Equal(t, map[string]any(nil), not.Name) require.Error(t, b.BindUri(m, &not))
// Check that if the map is not nil, it is empty (json-iterator may allocate map before error)
if not.Name != nil {
assert.Empty(t, not.Name)
}
} }
func TestUriInnerBinding(t *testing.T) { func TestUriInnerBinding(t *testing.T) {

View File

@ -2138,7 +2138,7 @@ func TestContextBindRequestTooLarge(t *testing.T) {
// https://github.com/goccy/go-json/issues/485 // https://github.com/goccy/go-json/issues/485
var expectedCode int var expectedCode int
switch json.Package { switch json.Package {
case "github.com/goccy/go-json": case "github.com/goccy/go-json", "github.com/json-iterator/go":
expectedCode = http.StatusBadRequest expectedCode = http.StatusBadRequest
default: default:
expectedCode = http.StatusRequestEntityTooLarge expectedCode = http.StatusRequestEntityTooLarge

View File

@ -0,0 +1,26 @@
# JSON Iterator Example
This example demonstrates how to integrate [json-iterator/go](https://github.com/json-iterator/go) with Gin to replace the default encoding/json for better performance.
## How it works
Gin supports custom JSON serialization and deserialization logic via the `json.API` variable. By implementing the `json.Core` interface (which includes `Marshal`, `Unmarshal`, `NewEncoder`, `NewDecoder` etc.), we can swap out the underlying JSON engine.
## Usage
1. Define your custom configuration using `jsoniter.Config`.
2. Implement the `json.Core` interface wrappers.
3. Assign your custom implementation to `json.API` before creating the Gin engine.
## Run the example
```bash
go run main.go
```
Test it:
```bash
curl http://localhost:8080/ping
# Output: {"message":"pong"}
```

View File

@ -0,0 +1,45 @@
package main
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
ginjson "github.com/gin-gonic/gin/codec/json"
"github.com/stretchr/testify/assert"
)
func TestJsonIterator(t *testing.T) {
// Restore default json api after test
originalAPI := ginjson.API
defer func() {
ginjson.API = originalAPI
}()
// Use custom json api
ginjson.API = customJsonApi{}
gin.SetMode(gin.TestMode)
r := gin.New()
r.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"hello": "world",
"foo": "bar",
})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/test", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
// Verify JSON response
var response map[string]string
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.Equal(t, "world", response["hello"])
assert.Equal(t, "bar", response["foo"])
}

View File

@ -0,0 +1,55 @@
package main
import (
"io"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/codec/json"
jsoniter "github.com/json-iterator/go"
)
var customConfig = jsoniter.Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
}.Froze()
// customJsonApi implement api.JsonApi
type customJsonApi struct {
}
func (j customJsonApi) Marshal(v any) ([]byte, error) {
return customConfig.Marshal(v)
}
func (j customJsonApi) Unmarshal(data []byte, v any) error {
return customConfig.Unmarshal(data, v)
}
func (j customJsonApi) MarshalIndent(v any, prefix, indent string) ([]byte, error) {
return customConfig.MarshalIndent(v, prefix, indent)
}
func (j customJsonApi) NewEncoder(writer io.Writer) json.Encoder {
return customConfig.NewEncoder(writer)
}
func (j customJsonApi) NewDecoder(reader io.Reader) json.Decoder {
return customConfig.NewDecoder(reader)
}
func main() {
// Replace the default json api with json-iterator
json.API = customJsonApi{}
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
r.Run(":8080")
}

View File

@ -64,7 +64,20 @@ func testRequest(t *testing.T, params ...string) {
} }
func TestRunEmpty(t *testing.T) { func TestRunEmpty(t *testing.T) {
os.Setenv("PORT", "") // Listen on a random available port to avoid conflicts
l, err := net.Listen("tcp", "localhost:0")
require.NoError(t, err)
defer l.Close()
addr := l.Addr().String()
_, port, err := net.SplitHostPort(addr)
require.NoError(t, err)
// Close the listener so router.Run() can bind to it (there's a small race here, but better than hardcoded 8080)
// Actually, router.Run() calls http.ListenAndServe which creates its own listener.
// If we close 'l', 'router.Run' can pick it up.
l.Close()
os.Setenv("PORT", port)
router := New() router := New()
go func() { go func() {
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
@ -72,11 +85,11 @@ func TestRunEmpty(t *testing.T) {
}() }()
// Wait for server to be ready with exponential backoff // Wait for server to be ready with exponential backoff
err := waitForServerReady("http://localhost:8080/example", 10) err = waitForServerReady("http://"+addr+"/example", 10)
require.NoError(t, err, "server should start successfully") require.NoError(t, err, "server should start successfully")
require.Error(t, router.Run(":8080")) require.Error(t, router.Run(":"+port))
testRequest(t, "http://localhost:8080/example") testRequest(t, "http://"+addr+"/example")
} }
func TestBadTrustedCIDRs(t *testing.T) { func TestBadTrustedCIDRs(t *testing.T) {