英文:
Gin gonic framework: confusing response status codes
问题
我已经进入了一个我不理解的领域。
这是一个使用Golang编写的Gin API路由处理程序的示例。
// src/file1.go
func CreateDataModelAction(c *gin.Context) {
var input inputs.CreateDataModelInput
if err := c.ShouldBindJSON(&input); err != nil {
// 这里我使用一个生成并返回验证错误的API响应的函数。
// 这个函数位于单独的文件中,下面将列出该代码块。
api.RespondWithValidationError(c, outputs.GetValidationErrors(err))
return
}
c.JSON(http.StatusCreated, nil)
}
// src/file2.go
func RespondWithValidationError(c *gin.Context, validationErrors outputs.DataValidationErrorAPIResponse) {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity, validationErrors)
}
在ShouldBindJSON
之后发生验证错误的情况下,我期望这段代码进入if
块,并返回带有验证错误的422
状态码。然而,无论如何,这段代码始终返回状态码200
,尽管这个函数只能返回422
或201
。
但是,如果我删除api.RespondWithValidationError
函数,并直接在路由处理程序中使用AbortWithStatusJSON
函数,我会收到预期的422
状态码。
// 这个示例按预期工作
func CreateDataModelAction(c *gin.Context) {
var input inputs.CreateDataModelInput
if err := c.ShouldBindJSON(&input); err != nil {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity)
return
}
c.JSON(http.StatusCreated, nil)
}
我试图阅读Gin上下文源代码,以了解为什么会发生这种情况,但到目前为止我还没有成功。
请解释一下在这种情况下Gin上下文是如何工作的,以及为什么当我从单独的函数返回422
状态码时,我没有收到422
状态码。
英文:
I've stepped into something I don't understand.
Here is an example of Gin API route handler, written in Golang.
// src/file1.go
func CreateDataModelAction(c *gin.Context) {
var input inputs.CreateDataModelInput
if err := c.ShouldBindJSON(&input); err != nil {
// Here I use a function that generates and returns API responses for validation errors.
// This function is located in separate file and it's going to be listed below this code block.
api.RespondWithValidationError(c, outputs.GetValidationErrors(err))
return
}
c.JSON(http.StatusCreated, nil)
}
// src/file2.go
func RespondWithValidationError(c *gin.Context, validationErrors outputs.DataValidationErrorAPIResponse) {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity, validationErrors)
}
In case of validation errors happening after ShouldBindJSON
I expect this code to enter if
block and to return 422
status code with validation errors. However, this code always returns status code 200
despite the fact thic function can only return 422
or 201
.
But if I remove api.RespondWithValidationError
function and use AbortWithStatusJSON
function directly in route handler, I receive the status code 422
as it is expected.
// This example works as expected
func CreateDataModelAction(c *gin.Context) {
var input inputs.CreateDataModelInput
if err := c.ShouldBindJSON(&input); err != nil {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity)
return
}
c.JSON(http.StatusCreated, nil)
}
I was trying to read Gin context source code in order to understand why this is happening, and I have not succeeded so far.
Please explain to me how exactly Gin context works in this case and why I'm not receiving 422
when I'm returning 422
status code from separate function.
答案1
得分: 1
我根据你的问题代码编写了一个小例子,并猜测了你省略的细节,但相关的代码应该是正确的。为了演示和更简洁,我将所有的代码都放在了一个文件中。
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// HTTP请求提供的输入DTO
type createDataModeInput struct {
Name string `json:"name" binding:"required"`
}
// 发送错误场景下的输出DTO
type DataValidationErrorApiResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
// 构建DataValidationErrorApiResponse实例的函数
func GetValidationErrors(err error) DataValidationErrorApiResponse {
return DataValidationErrorApiResponse{
Code: "VALIDATION_ERR",
Message: err.Error(),
}
}
func RespondWithValidationError(c *gin.Context, validationErrors DataValidationErrorApiResponse) {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity, validationErrors)
}
func CreateDataModeAction(c *gin.Context) {
var input createDataModeInput
if err := c.ShouldBind(&input); err != nil {
RespondWithValidationError(c, GetValidationErrors(err))
return
}
c.JSON(http.StatusCreated, nil)
}
func main() {
gin.SetMode(gin.DebugMode)
r := gin.Default()
r.POST("/demo", CreateDataModeAction)
r.Run(":8000")
}
如你所见,代码与你的代码非常相似。现在,让我们看看如何正确测试它。
CURL测试
为了测试代码,我使用了两个CURL命令:一个必须返回422
状态码,另一个返回201
状态码。后一个命令如下:
curl -X POST http://127.0.0.1:8000/demo -H 'Content-Type: application/json' -d '{"name":"lorem"}'
通过这个命令,你将得到created - 201
状态码。要测试错误场景,你可以使用类似以下的命令:
curl -X POST http://127.0.0.1:8000/demo -H 'Content-Type: application/json' -d '{"name":""}'
使用这个命令,你将得到期望的422
状态码。
抱歉,如果我没有添加太多解释,但代码与你的代码非常相似。如果你仍然遇到问题,请告诉我,我会更新我的回答,谢谢!
英文:
I put together a small example based on the code of your question. I guessed the details you omitted but the relevant code should be good. I put all of the code in a single file just for the sake of the demo and to be more concise.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// input DTO provided by HTTP Request
type createDataModeInput struct {
Name string `json:"name" binding:"required"`
}
// output DTO to send in error scenario
type DataValidationErrorApiResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
// function to build the DataValidationErrorApiResponse instance
func GetValidationErrors(err error) DataValidationErrorApiResponse {
return DataValidationErrorApiResponse{
Code: "VALIDATION_ERR",
Message: err.Error(),
}
}
func RespondWithValidationError(c *gin.Context, validationErrors DataValidationErrorApiResponse) {
c.AbortWithStatusJSON(http.StatusUnprocessableEntity, validationErrors)
}
func CreateDataModeAction(c *gin.Context) {
var input createDataModeInput
if err := c.ShouldBind(&input); err != nil {
RespondWithValidationError(c, GetValidationErrors(err))
return
}
c.JSON(http.StatusCreated, nil)
}
func main() {
gin.SetMode(gin.DebugMode)
r := gin.Default()
r.POST("/demo", CreateDataModeAction)
r.Run((":8000"))
}
As you can see, the code is pretty much similar to yours. Now, let's see how to properly test it.
CURL tests
To test out the code, I used two CURL commands: one that must be resolved with a 422
status code and one with 201
. The latter command is:
curl -X POST http://127.0.0.1:8000/demo -H 'Content-Type: application/json' -d '{"name":"lorem"}'
Thanks to this, you'll get the created - 201
status code. To test the bad scenario, you should use something like:
curl -X POST http://127.0.0.1:8000/demo -H 'Content-Type: application/json' -d '{"name":""}'
With this statement, you'll get the desired 422
status code.
Sorry, if I didn't add too much explanation but the code is really similar to yours. If you still face some issues, just let me know and I'll update my answer, thanks!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论