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

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

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

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

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

gema
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《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周前 评论
gema (楼主) 3周前
giao哥 (作者) 3周前
gema (楼主) 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周前
gema (楼主) 3周前
gema (楼主) 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周前 评论
gema (楼主) 3周前
songxue77 (作者) 3周前
pzwwzp 3周前
gema (楼主) 3周前
songxue77 (作者) 2周前
songxue77 (作者) 2周前
pzwwzp 2周前
Epona

我个人的话,用 resource 来返回

3周前 评论
Epona (作者) 3周前
gema (楼主) 3周前
Epona (作者) 3周前
gema (楼主) 3周前

这种东西公司统一了就行

3周前 评论

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

3周前 评论

file

file

2周前 评论
gema (楼主) 2周前

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

file

file

file 每一个 resource 对应 swagge 的 model

2周前 评论

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": []
}
2周前 评论

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