2016-12-08 21 views
3

我正在使用Slim3製作一個相當大的JSON API。我的控制器/行動目前充斥着如下:Slim3 /幹 - 如何正確處理錯誤/異常,無需重複代碼?

return $response->withJson([ 
    'status' => 'error', 
    'data' => null, 
    'message' => 'Username or password was incorrect' 
]); 

在應用程序中的任何特定點可能出錯,響應需要是適當的。但有一點很常見,錯誤響應總是相同的。 status總是errordata是可選的(在表單驗證錯誤的情況下,data將包含這些),並且message被設置爲向API的用戶或消費者指示出了什麼問題。

我聞到代碼重複。我怎樣才能減少代碼重複?

從我的頭頂,我所能想到做的是創造一個自定義異常,像App\Exceptions\AppException這需要選擇datamessage將獲得形式$e->getMessage()

<?php 

namespace App\Exceptions; 

class AppException extends Exception 
{ 
    private $data; 

    public function __construct($message, $data = null, $code = 0, $previous = null) 
    { 
     $this->data = $data; 
     parent::__construct($message, $code, $previous); 
    } 

    public function getData() 
    { 
     return $this->data; 
    } 
} 

此之後創建的中間件調用$next包裹在一個try/catch:

$app->add(function($request, $response, $next) { 

    try { 
    return $next($request, $response); 
    } 
    catch(\App\Exceptions\AppException $e) 
    { 
    $container->Logger->addCritical('Application Error: ' . $e->getMessage()); 
    return $response->withJson([ 
     'status' => 'error', 
     'data' => $e->getData(), 
     'message' => $e->getMessage() 
    ]); 
    } 
    catch(\Exception $e) 
    { 
    $container->Logger->addCritical('Unhandled Exception: ' . $e->getMessage()); 
    $container->SMSService->send(getenv('ADMIN_MOBILE'), "Shit has hit the fan! Run to your computer and check the error logs. Beep. Boop."); 
    return $response->withJson([ 
     'status' => 'error', 
     'data' => null, 
     'message' => 'It is not possible to perform this action right now' 
    ]); 
    } 
}); 

現在我需要在點做的代碼是throw new \App\Exceptions\AppException("Username or password incorrect", null)

我唯一的問題就是我覺得我使用異常的原因是錯誤的,它可能會使調試更加困難。

有關減少重複項和清除錯誤響應的任何建議?

+0

你正在使用例外,就像你應該在Slim中一樣。我用Slim構建了很多API,並且使用了完全相同的方法 - 我想要停止請求處理時拋出的特定AppException,並讓它在Slim的exceptionHandler中被捕獲。這是我找到的最乾淨,必須脫鉤的方式。只需使用@Mika Tuupola方法。 –

回答

3

您可以通過創建輸出JSON的錯誤處理程序來實現類似的結果。

namespace Slim\Handlers; 

use Psr\Http\Message\ServerRequestInterface as Request; 
use Psr\Http\Message\ResponseInterface as Response; 

final class ApiError extends \Slim\Handlers\Error 
{ 
    public function __invoke(Request $request, Response $response, \Exception $exception) 
    { 
     $status = $exception->getCode() ?: 500; 
     $data = [ 
      "status" => "error", 
      "message" => $exception->getMessage(), 
     ]; 
     $body = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); 
     return $response 
        ->withStatus($status) 
        ->withHeader("Content-type", "application/json") 
        ->write($body); 
    } 
} 

您還必須配置Slim以使用您的自定義錯誤處理程序。

$container = $app->getContainer(); 

$container["errorHandler"] = function ($container) { 
    return new Slim\Handlers\ApiError; 
}; 

檢查Slim API Skeleton例如實施。

+0

嘿邁克。我遇到的一個問題是,有時用戶需要查看錯誤消息(表單驗證,不正確的登錄等),但是與數據庫問題有關的任何異常或者因爲任何原因未被捕獲的異常希望顯示給用戶,而不是通用消息。這就是爲什麼我想分開例外。這仍然可以這樣做嗎?我猜測它可能會與錯誤代碼也許完成。 – BugHunterUK

+2

您可以像發佈的中間件一樣執行相同的操作。當\ App \ Exceptions \ AppException顯示詳細錯誤時。當別的東西這麼不詳細的錯誤。 –

+0

@BugHunterUK你可以使用Mika的答案就好了,只需使用if($ exception instanceOf AppException)檢查異常實例是否爲'AppException',如果是的話,發送異常JSON,否則發送一個通用的'錯誤發生'JSON。 –