withJson and JSONP

You have provided a nice convenience function, withJson, for the response object but it seems to overlook the jsonp needs of some API. Or maybe I’ve missed something. It is relatively straight forward to roll my own but it might be a nice feature in future releases. Or maybe I should endeavor to help with the project.

You can send a PR to the https://github.com/slimphp/Slim and we will consider it. I don’t know enough about JSONP to deal with this myself.

I previously implemented this as middleware, which wraps the json with a javascript function call.

Note this is NOT tested, but just to give you an idea.

class JsonpMiddleware
{
    /**
     * @var string
     */
    protected $callbackKey;

    /**
     * @var string|null
     */
    protected $callbackName;

    /**
     * Create JsonpMiddleware.
     *
     * @param string $callbackKey
     */
    public function __construct($callbackKey = 'callback')
    {
        $this->callbackKey = $callbackKey;
    }

    /**
     * Build Response with the callback.
     *
     * @param Response $response
     *
     * @return Response
     */
    protected function buildJsonpResponse(Response $response)
    {
        $content = (string) $response->getBody();
        $contentType = $response->getHeaderLine('Content-Type');

        if (strpos($contentType, 'application/json') === false) {
            $content = '"' . $content . '"';
        }

        $callback = "{$this->callbackName}({$content}));";

        $newResponse = new Response(200);
        $newResponse->getBody()->write($callback);

        return $newResponse
                ->withHeader('Content-Type', 'application/javascript');
    }

    /**
     * Invoke EnvelopeMiddleware.
     *
     * @param Request  $request
     * @param Response $response
     * @param callable $next
     *
     * @return Response
     */
    public function __invoke(Request $request, Response $response, callable $next)
    {
        $param = $request->getQueryParam($this->callbackKey);

        if (is_string($param) && !empty($param)) {
            $this->callbackName = $param;
        }

        /* @var $newResponse Response */
        $newResponse = $next($request, $response);

        if ($this->callbackName) {
            $newResponse = $this->buildJsonpResponse($newResponse);
        }

        return $newResponse;
    }
}
1 Like