RESTful API 的最佳返回方式应该是怎样的?

在应用开发过程中,接口的开发肯定是少不了的。但是如何开发接口才能算是较优的方案呢?
换个问法:如何按需返回 API 数据

工作了两年了,也做过很多(小型)前后端分离的应用,写过很多接口。但是,越做就越迷惑,应该怎么写一个接口才合适?
这里想讨论的不是接口的返回数据结构,而是一个接口处理完相关业务后如何返回结果。
比如:

  • 直接返回:
    $resource=Model::first();
    return $resource;
  • 通过JsonResponse
    return response()->json(["data"=>["foo"=>"bar"]]);
  • 通过API资源返回
    return new UserResponse(User::first());

问题在于,并不是每次请求都要获取资源的全部信息,有些接口还需要返回一些嵌套信息,有些则需要根据请求接口的认证用户的不同而显示或隐藏等等。所以,应该如何设计返回资源的方式以尽量满足各种各样的微小差异?

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 13

jsonapi.org 可以参考下这个(小心前端抱怨,解析不好骂后端)

(建议科上学网,没找到较新较全面的中文站)

通过 include 加载关联,在 relationships 中返回

通过 fields 限制仅返回需要的字段

通过 filter 传递筛选条件

通过 page 获取指定范围数据

3年前 评论
ResponseFactory::macro('succJson', function ($data, $status=200) {
            return Response::json([
                'code' => $status,
                'message' => 'success',
                'data' =>  $data,
            ], $status);
        });
// use
return response()->succJson(...);
3年前 评论
{
    "code": 200,
    "message": "success",
    "data":[]
}
3年前 评论
giao哥

只要大致的方向是对的,我觉得没有必要纠结这个吧。不同公司接口返回都大同小异,满足业务即可。

3年前 评论
porygonCN (楼主) 3年前
giao哥 (作者) 3年前
porygonCN (楼主) 3年前

GraphQL :relaxed:

3年前 评论

有关结构:链接

{
   "data": [{ ... }, { ... }],
   "message": "You have a lot todo!",
   "errors": [],
   "status": 1,
}

我们是在BaseController写了方法sendSuccess, sendError, sendResponse

关于内容,由于我司没有采用前后端分离开发,故Resource只用于API接口,也并不是所有API接口都用到Resource。对后台管理系统,是直接传整个变量过去。

关联的数据可以在各自的Controller方法里去load或用with获取即可。

有些公司的做法是多加一层Representer层专门处理如何展示数据。

3年前 评论
skys215 (作者) 3年前
porygonCN (楼主) 3年前
porygonCN (楼主) 3年前

我们是Controller -> Result -> Service -> Model 结构去写了应用
Controller : 只有注入相应Request和Return语句
Result : 处理了返回数据结构,楼主说的返回Resource或者return view()或者 return response()->json()都写在了这里
Service :基本上所有的非数据库逻辑写在了这里
Model : 数据库逻辑(ORM, Query Builder) 写在了这里

返回的数据是
{
“code”: “0000”,
“message”: “Success”,
“description”: “return XXX”,
“data”: {}
}

公司内部也有人提出分层太多,但还在继续磨合当中,参考参考就行了

3年前 评论
porygonCN (楼主) 3年前
songxue77 (作者) 3年前
pzwwzp 3年前
porygonCN (楼主) 3年前
songxue77 (作者) 3年前
songxue77 (作者) 3年前
pzwwzp 3年前
Epona

我个人的话,用 resource 来返回

3年前 评论
Epona (作者) 3年前
porygonCN (楼主) 3年前
Epona (作者) 3年前
porygonCN (楼主) 3年前

这种东西公司统一了就行

3年前 评论

github.com/weiwenhao/tree-ql 这是当时我的想法,无非就是类似 graphql 一样, 客户端带参数微调就行了。

3年前 评论

file

file

3年前 评论
porygonCN (楼主) 3年前

@gema 是的。但是可以复用,就不用可以复用的数据结构每次都再写一遍。如果配合 swagge。就很方便

file

file

file 每一个 resource 对应 swagge 的 model

3年前 评论

if (!function_exists('apiSuccess')) {
    function apiSuccess($data = [], $msg = '成功', $headers = []): \Illuminate\Http\JsonResponse
    {
        return apiResponse($msg, 0, $data, $headers);
    }
}

if (!function_exists('apiError')) {
    function apiError($msg = '失败', $code = -1, $data = [], $headers = []): \Illuminate\Http\JsonResponse
    {
        return apiResponse($msg, $code, $data, $headers);
    }
}

if (!function_exists('apiResponse')) {
    function apiResponse($msg, $code, $data, $headers): \Illuminate\Http\JsonResponse
    {
        $response = [
            'code' => $code,
            'msg'  => $msg,
            'data' => $data,
        ];

        return response()
            ->json($response)
            ->withHeaders($headers)
            ->withCallback(request('callback'));
    }
}

result

{
    "code": 0,
    "msg": "success",
    "data": []
}
{
    "code": -1,
    "msg": "testtst",
    "data": []
}
3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!