基于url的细长且不同的响应类型

时间:2017-02-27 05:52:58

标签: json rest slim file-type

所以我想允许用户在向服务器运行rest API请求时请求.xml或.json响应。 (很像推特)

但我不相信以下方式是最好的方法,因为它意味着重复的代码,肯定有更好的方法来允许.xml或.json响应。

 $app->get('/books/:id.xml', function ($id) use ($app) {
        $app->render('/xml/books.xml', array('id' => $id));
    });

 $app->get('/books/:id.json', function ($id) use ($app) {
        $app->render('json/books.json', array('id' => $id));
    });

OR

// Define app routes
$app->get('/hello/{name}.{type}', function ($request, $response, $args) {
    //return $response->write("Hello " . $args['name']);
    if($args['type'] == 'xml')
    {
      return 'this is xml';
    }
    var_dump(parse_url($_SERVER['REQUEST_URI']));

});

如果有人知道怎么做,那就太好了。

1 个答案:

答案 0 :(得分:0)

考虑在URI的末尾使用Accept请求的HTTP标头的值而不是文件扩展名。

我认为使用标头更可靠,更“正确”的方式来确定应该返回数据的格式。 URI应该用于指向特定资源。客户端应发送Accept标头,告诉您应该返回数据的格式。 除了作为实现RESTful服务的标准方法之外,它还消除了改变路由的麻烦(如第二个例子)。

如果您同意此类实施,则需要excellent library来解决您的问题。

它有很多用途,这是一个用例的例子:

<?php
use Negotiation\Negotiator;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;

class YourController
{
    public function __construct(Negotiator $negotiator, DataProvider $someDataProvider)
    {
        $this->negotiator = $negotiator;
        $this->someDataProvider = $someDataProvider;
    }

    /**
     * Processing request.
     * 
     * We get data, then we use Negotiator to detect what format the requestor prefers.
     * Then we return data in requested format or in case format is not supported,
     * fall back to JSON.
     * 
     * 
     * @param Request $request 
     * @param Response $response 
     * @return Response
     */
    public function __invoke(Request $request, Response $response)
    {
        $data = $this->someDataProvider->getSomeData();

        $mediaType = $this->determineMediaType($request);

        switch ($mediaType) {
            case 'application/json':
            default:
        // $data = $data->asJson();
                // transform data to JSON...
                break;
            case 'application/xml':
        $data = $data->asXml();
                // transform data to XML...
                break;
        }

        // Write data to body of response
        $response->getBody()->write($data);

        // Set appropriate response header
        return $response->withHeader('Content-Type', $mediaType);
    }

    /**
     * Find preferred data format from Accept header.
     * 
     * Uses Negotiator to determine whether JSON or XML should be returned.
     *
     * @param Request $request
     * @return string
     */
    private function determineMediaType(Request $request)
    {
        $acceptHeader = $this->extractAcceptHeader($request);
        // Set list of "known" formats, i.e. formats that your service supports
        $known = ['application/json', 'application/xml'];
        // Let negotiator determine what format should be used
        $mediaType = $this->negotiator->getBest($acceptHeader, $known);
        if ($mediaType) {
            return $mediaType->getValue();
        } else {
            return 'application/json'; # if request has unexpected value of accept header, default to JSON
        }
    }

    /**
     * Extract Accept header value from Request object
     * @param Request $request
     * @return string
     */
    private function extractAcceptHeader(Request $request)
    {
        return $request->getHeaderLine('Accept');
    }
}

此类是路由回调的示例。这样的实现允许您轻松扩展支持的格式列表,而不会篡改路由。