craftcms / element-api

Create a JSON API/Feed for your elements in Craft.
MIT License
498 stars 56 forks source link

http OPTIONS request returns full result with data in body #128

Closed judos closed 2 years ago

judos commented 4 years ago

In our application we have a jwt header which gets sent to the cms. Naturally thus the browser does a preflight request before sending the actual request and it just realized that element-api returns already a full response with data in the preflight request "OPTIONS /endpoint" as well as then in the "GET /endpoint". Shouldn't element api only serve GET requests? Is there a way to configure this?

The element-api.php looks like this:

return [
    'defaults' => [
        'elementType' => Entry::class,
        'resourceKey' => 'elements',
        'pretty' => Craft::$app->getConfig()->general->devMode,
        'paginate' => false,
        'cache' => ApiHelper::enableCache(300),
    ],
    'endpoints' => [
        'pages/<slug:{slug}>' => function($slug) {
            return [
                'one' => true,
                'criteria' => [
                    'section' => 'pages',
                    'slug' => $slug,
                ],
                'transformer' => new PageTransformer()
            ];
        },
    }
]

The header that is added in angular is just this:

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (this.jwt) {
      req = req.clone({
        headers: req.headers.set('Authorization', 'Bearer ' + this.jwt)
      });
    }
    return next.handle(req);
  }

I didn't find anything in the documentation.

Thanks for your help!

judos commented 4 years ago

Found a small workaround: In element-api instead of returning criterias to form a query you can return a NullResource which is then directly serialized as empty brackets. So I solved as follows:

'pages'` => function() {
    if ($response = ApiHelper::assumeGet()) {
        return $response;
    }
    return [
        'criteria' => [
            'section' => 'pages',
        ],
        'transformer' => new PageTransformer()
    ];
},

And my ApiHelper:

class ApiHelper {

    /**
     * @throws BadRequestHttpException
     */
    public static function assumeGet() {
        $request = Craft::$app->getRequest();
        if ($request->getIsOptions()) {
            return new NullResource();
        }
        if (!Craft::$app->getRequest()->getIsGet()) {
            throw new BadRequestHttpException('Get request required');
        }
    }
}
pathei commented 3 years ago

👍

brandonkelly commented 2 years ago

Just released Element API 2.8.0, which now checks if the endpoint request is an OPTIONS request, and returns an empty response in that case.