如何在Laravel 5.4中生成API错误响应?

时间:2017-04-06 04:43:13

标签: laravel laravel-5.4

每当我拨打/api/v1/posts/1时,呼叫都会转发到show方法

public function show(Post $post) {
    return $post;
}

PostController.php资源控制器中。如果帖子确实存在,则服务器返回JSON响应。但是,如果帖子存在,则服务器返回纯HTML,尽管请求显然期望JSON作为回报。这是Postman的演示。

enter image description here

问题是API应该返回application/json,而不是text/html。所以,这是我的问题:

1。如果我们使用隐式路由模型绑定时发生异常,Laravel是否内置支持自动返回JSON(如上面的show方法,当我们有404)?

2. 如果是,我该如何启用它? (默认情况下,我得到纯HTML,而不是JSON)

如果它没有在每个 API控制器上复制以下内容的替代方法

public function show($id) {
    $post = Post::find($id); // findOrFail() won't return JSON, only plain HTML
    if (!$post)
        return response()->json([ ... ], 404);
    return $post;
}

3。app\Exceptions\Handler中是否有通用的方法?

4. 标准错误/异常响应包含什么?我用Google搜索了这个,但发现了许多自定义变体。

5. 为什么JSON响应仍然构建在隐式路由模型绑定中?为什么不简化开发人员生活并自动处理这种低级别的麻烦?

修改

在Laravel IRC的人员建议我单独留下错误响应,认为标准HTTP异常在默认情况下呈现为HTML 以及使用API​​的系统之后,我留下了一个难题应该处理404s而不看身体。我希望更多的人加入讨论,我想知道你们会如何回应。

4 个答案:

答案 0 :(得分:6)

我在app/Exceptions/Handler.php中使用此代码,可能您需要进行一些更改

public function render($request, Exception $exception)
{
    $exception = $this->prepareException($exception);

    if ($exception instanceof \Illuminate\Http\Exception\HttpResponseException) {
        return $exception->getResponse();
    }
    if ($exception instanceof \Illuminate\Auth\AuthenticationException) {
        return $this->unauthenticated($request, $exception);
    }
    if ($exception instanceof \Illuminate\Validation\ValidationException) {
        return $this->convertValidationExceptionToResponse($exception, $request);
    }

    $response = [];

    $statusCode = 500;
    if (method_exists($exception, 'getStatusCode')) {
        $statusCode = $exception->getStatusCode();
    }

    switch ($statusCode) {
        case 404:
            $response['error'] = 'Not Found';
            break;

        case 403:
            $response['error'] = 'Forbidden';
            break;

        default:
            $response['error'] = $exception->getMessage();
            break;
    }

    if (config('app.debug')) {
        $response['trace'] = $exception->getTrace();
        $response['code'] = $exception->getCode();
    }

    return response()->json($response, $statusCode);
}

此外,如果您将使用formRequest验证,则需要覆盖方法response,否则您将被重定向,这可能会导致一些错误。

use Illuminate\Http\JsonResponse;

...

public function response(array $errors)
{
    // This will always return JSON object error messages
    return new JsonResponse($errors, 422);
}

答案 1 :(得分:3)

  
      
  1. 是否有在app \ Exceptions \ Handler中使用的通用方法?
  2.   

您可以检查通用异常处理程序中是否需要json。

// app/Exceptions/Handler.php
public function render($request, Exception $exception) {
    if ($request->expectsJson()) {
        return response()->json(["message" => $exception->getMessage()]);
    }
    return parent::render($request, $exception);
}

答案 2 :(得分:-1)

我们通过创建一个负责返回响应部分的基本控制器来处理它的方式。看起来像这样,

class BaseApiController extends Controller
{

    private $responseStatus = [
        'status' => [
            'isSuccess' => true,
            'statusCode' => 200,
            'message' => '',
        ]
    ];

    // Setter method for the response status
    public function setResponseStatus(bool $isSuccess = true, int $statusCode = 200, string $message = '')
    {
        $this->responseStatus['status']['isSuccess'] = $isSuccess;
        $this->responseStatus['status']['statusCode'] = $statusCode;
        $this->responseStatus['status']['message'] = $message;
    }

    // Returns the response with only status key
    public function sendResponseStatus($isSuccess = true, $statusCode = 200, $message = '')
    {

        $this->responseStatus['status']['isSuccess'] = $isSuccess;
        $this->responseStatus['status']['statusCode'] = $statusCode;
        $this->responseStatus['status']['message'] = $message;

        $json = $this->responseStatus;

        return response()->json($json, $this->responseStatus['status']['statusCode']);

    }

    // If you have additional data to send in the response
    public function sendResponseData($data)
    {

        $tdata = $this->dataTransformer($data);

        if(!empty($this->meta)) $tdata['meta'] = $this->meta;

        $json = [
            'status' => $this->responseStatus['status'],
            'data' => $tdata,
        ];


        return response()->json($json, $this->responseStatus['status']['statusCode']);

    }
}

现在您需要在控制器中扩展它

class PostController extends BaseApiController {

    public function show($id) {
        $post = \App\Post::find($id);
        if(!$post) {
            return $this->sendResponseStatus(false, 404, 'Post not found');
        }

        $this->setResponseStatus(true, 200, 'Your post');
        return $this->sendResponseData(['post' => $post]);
    }
}

你会得到这样的回应

{
  "status": {
    "isSuccess": false,
    "statusCode": 404,
    "message": "Post not found"
  }
}

{
  "status": {
    "isSuccess": true,
    "statusCode": 200,
    "message": "Your post"
  },
  "data": {
     "post": {
         //Your post data
      }
  }
}

答案 3 :(得分:-3)

您只需使用use Illuminate\Support\Facades\Response;即可。 那么,回复就是:

public function index(){
    $analysis = Analysis::all();
    if(empty($analysis)) return Response::json(['error'=>'Empty data'], 200);
    return Response::json($analysis, 200, [], JSON_NUMERIC_CHECK);
}

现在你将有一个JSON返回....