美文网首页
【Go Web开发】Delete请求处理

【Go Web开发】Delete请求处理

作者: Go语言由浅入深 | 来源:发表于2022-02-10 23:06 被阅读0次

删除Movie接口

本节我们将添加CRUD接口中的最后一个:Delete操作,以便客户端可以从系统中删除特定的电影。

Method URL Handler 动作
GET /v1/healthcheck createMovieHandler 显示应用程序运行状况和版本信息
POST /v1/movies createMovieHandler 添加新的电影
GET /v1/movies/:id showMovieHandler 根据id查询特定电影
PUT /v1/movies/:id updateMovieHandler 更新特定电影
DELETE /v1/movies/:id deleteMovieHandler 删除特定电影

与API中的其他接口相比,Delete要实现的操作非常简单。

  • 如果数据库中存在一个具有URL中提供的id的movie记录,删除相应的记录并向客户端返回一条成功消息。
  • 如果movie id不存在,向客户端返回一个404 Not Found响应。

在数据库中删除记录的SQL查询也很简单:

DELETE FROM movies
WHERE id = $1

在这种情况下,SQL查询不返回任何行,因此我们可以使用Go的Exec()方法来执行它。

Exec()的一个好处是它返回一个sql.Result对象,其中包含受影响的行数信息。在我们的场景中,这是非常有用的信息。

  • 如果受影响的行数是1,那么我们知道要删除的movie存在于表中,并且现在已经被删除了...所以我们可以向客户端发送成功消息。
  • 相反,如果受影响的行数为0,我们知道对应id的movie不存在,向客户端返回404 Not Found响应。

添加Delete接口

让我们继续更新数据库模型中的Delete()方法。本质上,我们希望它执行上面的SQL语句,并在受影响行数为0时返回ErrRecordNotFound错误。像这样:

File:internal/data/movies.go


package data

...

func (m MovieModel) Delete(id int64) error {
    //如果movie ID小于1返回ErrRecordNotFound
    if id < 1 {
        return ErrRecordNotFound
    }
    //构造SQL query删除movie
    query := `
        DELETE FROM movies
        WHERE id = $1`
    //使用Exec()方法执行SQL语句,传入id变量作为占位符参数值。Exec()方法返回sql.Result对象
    result, err := m.DB.Exec(query, id)
    if err != nil {
        return err
    }
    //调用sql.Result对象的RowsAffected()方法,获取查询影响行数
    rowAffected, err := result.RowsAffected()
    if err != nil {
        return err
    }
    //如果没有影响行数,说明数据库不存在对应id的记录,返回ErrRecordNotFound
    if rowAffected == 0 {
        return ErrRecordNotFound
    }
    return nil
}

完成之后,我们转到cmd/api/movies.go文件,添加一个新的deleteMovieHandler方法。在这个过程中,我们需要从请求URL中读取movie ID,调用刚刚创建的Delete()方法,然后根据Delete()的返回值向客户端返回适当的响应。

File: cmd/api/movies.go


package main

...

func (app *application) deleteMovieHandler(w http.ResponseWriter, r *http.Request)  {
    //从URL中提取movie ID
    id, err := app.readIDParam(r)
    if err != nil {
        app.notFoundResponse(w, r)
        return
    }
    //从数据库中删除movie,如果没有对应id的movie就返回404
    err = app.models.Movies.Delete(id)
    if err != nil {
        switch {
        case errors.Is(err, data.ErrRecordNotFound):
            app.notFoundResponse(w, r)
        default:
            app.serverErrorResponse(w, r, err)
        }
        return
    }
    //返回200 Ok以及成功删除
    err = app.writeJSON(w, http.StatusOK, envelope{"message": "movie successfully deleted"}, nil)
    if err != nil {
        app.serverErrorResponse(w, r, err)
    }
}

注意:在这里您可能更喜欢发送一个空响应体和一个204 No Content状态码,而不是一个“电影已成功删除”消息。这取决于你的客户端是谁——如果他们是人,那么发送类似于上面的信息是一个很好的选择;如果它们是机器,那么204 No Content响应可能就足够了。

最后,需要在cmd/api/routes.go文件中添加删除movie的路由。

File:cmd/api/routes.go


package main

import (
    "github.com/julienschmidt/httprouter"
    "net/http"
)

func (app *application) routes() http.Handler {
    router := httprouter.New()

    router.NotFound = http.HandlerFunc(app.notFoundResponse)
    router.MethodNotAllowed = http.HandlerFunc(app.methodNotAllowedResponse)

    router.HandlerFunc(http.MethodGet, "/v1/healthcheck", app.healthcheckHandler)
    router.HandlerFunc(http.MethodPost, "/v1/movies", app.createMovieHandler)
    router.HandlerFunc(http.MethodGet, "/v1/movies/:id", app.showMovieHandler)
    router.HandlerFunc(http.MethodPut, "/v1/movies/:id", app.updateMovieHandler)
    //添加Delete /v1/movies/:id 接口路由
    router.HandlerFunc(http.MethodDelete, "/v1/movies/:id", app.deleteMovieHandler)
    return app.recoverPanic(app.rateLimit(router))
}

好了,重新启动API服务,通过从movie数据库中删除Deadpool来尝试下删除接口(如果您一直跟随本系列文章的操作,它的ID应该是3)。删除操作应该没有任何问题,您应该收到如下的确认消息:

$  curl -X DELETE http://localhost:4000/v1/movies/3
{
        "message": "movie successfully deleted"
}

如果您重复相同的请求来删除已经不存在的movie,应该会得到一个404 Not Found响应和错误消息。类似于:

$ curl -X DELETE http://localhost:4000/v1/movies/3
{
        "error": "the requested  resource could not be found"
}

相关文章

网友评论

      本文标题:【Go Web开发】Delete请求处理

      本文链接:https://www.haomeiwen.com/subject/jpiokrtx.html