Repository: labstack/echo
Pull request #2568 (2023-12-28 07:22:02)

Remove default charset from 'application/json' Content-Type header
Using application/json; charset=UTF-8 in response header is a common misuse. I think it is better to remove `; charset=UTF-8` from default json response Content-Type header to prevent the misconception.

See: https://github.com/labstack/echo/issues/2567

doortts: @aldas Thank you for the comment. 

- I recovered `echo.MIMEApplicationJSONCharsetUTF8` and added 'Deprecated: ' comment. Just let let me know if this is not what you intended.  https://github.com/labstack/echo/pull/2568/files?diff=unified#diff-aba8ba313c6b989153f1f96e641a8e0e75313485d2e13d64378e70858d5a4669R173
- I added a reference link what you mentioned to the issue documentation.
   - [Related RFC note link](https://www.rfc-editor.org/rfc/rfc8259#:~:text=Note%3A%20%20No%20%22charset%22%20parameter%20is%20defined%20for%20this%20registration.%0A%20%20%20%20%20%20Adding%20one%20really%20has%20no%20effect%20on%20compliant%20recipients.)
   - [Related RFC 8.1 Chapter Link](https://www.rfc-editor.org/rfc/rfc8259#section-8.1:~:text=JSON%20text%20exchanged%20between%20systems%20that%20are%20not%20part%20of%20a%20closed%0A%20%20%20ecosystem%20MUST%20be%20encoded%20using%20UTF%2D8)

Patch:
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 440f0ec..fbd6d95 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -21,10 +21,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Set up Go ${{ matrix.go }}
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
           go-version: ${{ env.LATEST_GO_VERSION }}
           check-latest: true
diff --git a/.github/workflows/echo.yml b/.github/workflows/echo.yml
index c240dd0..5722dcb 100644
--- a/.github/workflows/echo.yml
+++ b/.github/workflows/echo.yml
@@ -30,10 +30,10 @@ jobs:
     runs-on: ${{ matrix.os }}
     steps:
       - name: Checkout Code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Set up Go ${{ matrix.go }}
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
           go-version: ${{ matrix.go }}
 
@@ -53,18 +53,18 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Code (Previous)
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           ref: ${{ github.base_ref }}
           path: previous
 
       - name: Checkout Code (New)
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           path: new
 
       - name: Set up Go ${{ matrix.go }}
-        uses: actions/setup-go@v4
+        uses: actions/setup-go@v5
         with:
           go-version: ${{ env.LATEST_GO_VERSION }}
 
diff --git a/README.md b/README.md
index 18accea..351ba3c 100644
--- a/README.md
+++ b/README.md
@@ -9,20 +9,18 @@
 [![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
 [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
 
-## Supported Go versions
+## Echo
 
-Latest version of Echo supports last four Go major [releases](https://go.dev/doc/devel/release) and might work with
-older versions.
+High performance, extensible, minimalist Go web framework.
 
-As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
-Therefore a Go version capable of understanding /vN suffixed imports is required:
+* [Official website](https://echo.labstack.com)
+* [Quick start](https://echo.labstack.com/docs/quick-start)
+* [Middlewares](https://echo.labstack.com/docs/category/middleware)
 
-Any of these versions will allow you to import Echo as `github.com/labstack/echo/v4` which is the recommended
-way of using Echo going forward.
+Help and questions: [Github Discussions](https://github.com/labstack/echo/discussions)
 
-For older versions, please use the latest v3 tag.
 
-## Feature Overview
+### Feature Overview
 
 - Optimized HTTP router which smartly prioritize routes
 - Build robust and scalable RESTful APIs
@@ -38,6 +36,18 @@ For older versions, please use the latest v3 tag.
 - Automatic TLS via Let’s Encrypt
 - HTTP/2 support
 
+## Sponsors
+
+<div>
+  <a href="https://encore.dev" style="display: inline-flex; align-items: center; gap: 10px">
+    <img src="https://user-images.githubusercontent.com/78424526/214602214-52e0483a-b5fc-4d4c-b03e-0b7b23e012df.svg" height="28px" alt="encore icon"></img>
+  <b>Encore – the platform for building Go-based cloud backends</b>
+    </a>
+</div>
+<br/>
+
+Click [here](https://github.com/sponsors/labstack) for more information on sponsorship.
+
 ## Benchmarks
 
 Date: 2020/11/11<br>
@@ -57,6 +67,7 @@ The benchmarks above were run on an Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
 // go get github.com/labstack/echo/{version}
 go get github.com/labstack/echo/v4
 ```
+Latest version of Echo supports last four Go major [releases](https://go.dev/doc/devel/release) and might work with older versions.
 
 ### Example
 
@@ -117,10 +128,6 @@ of middlewares in this list.
 
 Please send a PR to add your own library here.
 
-## Help
-
-- [Forum](https://github.com/labstack/echo/discussions)
-
 ## Contribute
 
 **Use issues for everything**
diff --git a/context.go b/context.go
index 6a18116..d4cba84 100644
--- a/context.go
+++ b/context.go
@@ -489,7 +489,7 @@ func (c *context) jsonPBlob(code int, callback string, i interface{}) (err error
 }
 
 func (c *context) json(code int, i interface{}, indent string) error {
-	c.writeContentType(MIMEApplicationJSONCharsetUTF8)
+	c.writeContentType(MIMEApplicationJSON)
 	c.response.Status = code
 	return c.echo.JSONSerializer.Serialize(c, i, indent)
 }
@@ -507,7 +507,7 @@ func (c *context) JSONPretty(code int, i interface{}, indent string) (err error)
 }
 
 func (c *context) JSONBlob(code int, b []byte) (err error) {
-	return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
+	return c.Blob(code, MIMEApplicationJSON, b)
 }
 
 func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
diff --git a/echo.go b/echo.go
index 9924ac8..7b6a090 100644
--- a/echo.go
+++ b/echo.go
@@ -169,7 +169,12 @@ const (
 
 // MIME types
 const (
-	MIMEApplicationJSON                  = "application/json"
+	// MIMEApplicationJSON JavaScript Object Notation (JSON) https://www.rfc-editor.org/rfc/rfc8259
+	MIMEApplicationJSON = "application/json"
+	// Deprecated: Please use MIMEApplicationJSON instead. JSON should be encoded using UTF-8 by default.
+	// No "charset" parameter is defined for this registration.
+	// Adding one really has no effect on compliant recipients.
+	// See RFC 8259, section 8.1. https://datatracker.ietf.org/doc/html/rfc8259#section-8.1
 	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + charsetUTF8
 	MIMEApplicationJavaScript            = "application/javascript"
 	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8


Test patch:
diff --git a/context_test.go b/context_test.go
index 01a8784..4ca2cc8 100644
--- a/context_test.go
+++ b/context_test.go
@@ -154,7 +154,7 @@ func TestContextJSON(t *testing.T) {
 	err := c.JSON(http.StatusOK, user{1, "Jon Snow"})
 	if assert.NoError(t, err) {
 		assert.Equal(t, http.StatusOK, rec.Code)
-		assert.Equal(t, MIMEApplicationJSONCharsetUTF8, rec.Header().Get(HeaderContentType))
+		assert.Equal(t, MIMEApplicationJSON, rec.Header().Get(HeaderContentType))
 		assert.Equal(t, userJSON+"\n", rec.Body.String())
 	}
 }
@@ -178,7 +178,7 @@ func TestContextJSONPrettyURL(t *testing.T) {
 	err := c.JSON(http.StatusOK, user{1, "Jon Snow"})
 	if assert.NoError(t, err) {
 		assert.Equal(t, http.StatusOK, rec.Code)
-		assert.Equal(t, MIMEApplicationJSONCharsetUTF8, rec.Header().Get(HeaderContentType))
+		assert.Equal(t, MIMEApplicationJSON, rec.Header().Get(HeaderContentType))
 		assert.Equal(t, userJSONPretty+"\n", rec.Body.String())
 	}
 }
@@ -192,7 +192,7 @@ func TestContextJSONPretty(t *testing.T) {
 	err := c.JSONPretty(http.StatusOK, user{1, "Jon Snow"}, "  ")
 	if assert.NoError(t, err) {
 		assert.Equal(t, http.StatusOK, rec.Code)
-		assert.Equal(t, MIMEApplicationJSONCharsetUTF8, rec.Header().Get(HeaderContentType))
+		assert.Equal(t, MIMEApplicationJSON, rec.Header().Get(HeaderContentType))
 		assert.Equal(t, userJSONPretty+"\n", rec.Body.String())
 	}
 }
@@ -213,7 +213,7 @@ func TestContextJSONWithEmptyIntent(t *testing.T) {
 	err := c.json(http.StatusOK, user{1, "Jon Snow"}, emptyIndent)
 	if assert.NoError(t, err) {
 		assert.Equal(t, http.StatusOK, rec.Code)
-		assert.Equal(t, MIMEApplicationJSONCharsetUTF8, rec.Header().Get(HeaderContentType))
+		assert.Equal(t, MIMEApplicationJSON, rec.Header().Get(HeaderContentType))
 		assert.Equal(t, buf.String(), rec.Body.String())
 	}
 }
@@ -244,7 +244,7 @@ func TestContextJSONBlob(t *testing.T) {
 	err = c.JSONBlob(http.StatusOK, data)
 	if assert.NoError(t, err) {
 		assert.Equal(t, http.StatusOK, rec.Code)
-		assert.Equal(t, MIMEApplicationJSONCharsetUTF8, rec.Header().Get(HeaderContentType))
+		assert.Equal(t, MIMEApplicationJSON, rec.Header().Get(HeaderContentType))
 		assert.Equal(t, userJSON, rec.Body.String())
 	}
 }
@@ -533,7 +533,7 @@ func TestContext_JSON_CommitsCustomResponseCode(t *testing.T) {
 
 	if assert.NoError(t, err) {
 		assert.Equal(t, http.StatusCreated, rec.Code)
-		assert.Equal(t, MIMEApplicationJSONCharsetUTF8, rec.Header().Get(HeaderContentType))
+		assert.Equal(t, MIMEApplicationJSON, rec.Header().Get(HeaderContentType))
 		assert.Equal(t, userJSON+"\n", rec.Body.String())
 	}
 }
diff --git a/middleware/decompress_test.go b/middleware/decompress_test.go
index 2e73ba8..351e0e7 100644
--- a/middleware/decompress_test.go
+++ b/middleware/decompress_test.go
@@ -131,7 +131,7 @@ func TestDecompressSkipper(t *testing.T) {
 	rec := httptest.NewRecorder()
 	c := e.NewContext(req, rec)
 	e.ServeHTTP(rec, req)
-	assert.Equal(t, rec.Header().Get(echo.HeaderContentType), echo.MIMEApplicationJSONCharsetUTF8)
+	assert.Equal(t, rec.Header().Get(echo.HeaderContentType), echo.MIMEApplicationJSON)
 	reqBody, err := io.ReadAll(c.Request().Body)
 	assert.NoError(t, err)
 	assert.Equal(t, body, string(reqBody))