Fix: Use WriteHeader in json method for consistent status handling by raju-mechatronics · Pull Request #2866 · labstack/echo

Hi @aldas,

Thank you very much for taking the time to review and for the clear explanation — I really appreciate your insight!

I proposed this change because c.JSON() currently allows multiple calls in the same handler without any warning, unlike most other response methods (XML(), Blob(), etc.) that use WriteHeader() and correctly log "response already committed".

Minimal example showing the difference:

// /multiple-json → no warnings
	e.GET("/multiple", func(c echo.Context) error {
		responses := []Response{
			{ID: 1, Name: "first"},
			{ID: 2, Name: "second"},
			{ID: 3, Name: "third"},
		}
		c.JSON(200, responses[0])
		c.JSON(200, responses[1])
		c.JSON(200, responses[2])
		return nil
	})

// /multiple-xml → warns twice
	e.GET("/multiple_xml", func(c echo.Context) error {
		responses := []Response{
			{ID: 1, Name: "first"},
			{ID: 2, Name: "second"},
			{ID: 3, Name: "third"},
		}

		c.XML(200, responses[0])
		c.XML(200, responses[1])
		c.XML(200, responses[2])

		return nil
	})

the logs:

⇨ http server started on [::]:8080
method=GET, uri=/multiple, status=200
{"time":"2026-01-21T18:05:17.741384+06:00","level":"WARN","prefix":"echo","file":"response.go","line":"59","message":"response already committed"}
{"time":"2026-01-21T18:05:17.741707+06:00","level":"WARN","prefix":"echo","file":"response.go","line":"59","message":"response already committed"}
method=GET, uri=/multiple_xml, status=200

I thought aligning JSON() with the other methods would help catch accidental multiple-response mistakes more consistently.