Swagger doctrine/zircote bearer Authorization code - php

i'm trying to use swagger zircote to create the swagger ui json.
for my application i use JWT and i need the following swagger code in my json:
"securityDefinitions": {
"Bearer": {
"in": "header",
"type": "accessToken",
"name": "Authorization"
}
},
But i dont know how i create that code with swaggers zircote. I've tried the following code:
* #SWG\Swagger(
* schemes={"https"},
* #SWG\SecurityDefinitions(
* bearer={
* type="apiKey",
* name="Authorization",
* in="header"
* }
* ),
but this results in the following error:
The annotation "#Swagger\Annotations\SecurityDefinitions" in
.\index.php on line 2 does not exist, or could not be auto-loaded.
Can someone help me, i cant find any good documentation about this, maybe its to specific, but i hope someone can help me.
Thanks!
Issued this also on the github... https://github.com/zircote/swagger-php/issues/366

Use #SWG\SecurityScheme instead of #SWG\SecurityDefinitions.
* #SWG\Swagger(
* schemes={"https"},
* #SWG\SecurityScheme(
* securityDefinition="Bearer",
* type="apiKey",
* name="Authorization",
* in="header"
* ),
A list of available annotations can be found list in vendor/zircote/swagger-php/src/Annotations

In my case worked as follows:
In the src dir a following class (some general settings):
#[OA\Info(version: "0.1", title: "My First API")]
#[OA\Server(url: 'http://localhost:8080/api')]
#[OA\SecurityScheme(
securityScheme: 'bearerAuth',
type: 'http',
in: 'header',
scheme: 'bearer',
)]
class OpenApi
{
}
and endpoint:
#[OA\Get(
path: '/someUrl',
summary: 'some description',
security: [['bearerAuth' => []]],
tags: ['some tag'],
)
]
#[OA\Response(response: '200', description: 'The data 1')]
#[OA\Response(response: '401', description: 'Unauthorized')]
public function getSomeData($request, $response, $args)

Related

Api Platform: how to test file upload with ApiTestCase

I have an endpoint, that allows file upload, everything works fine.
Next thing is to cover the endpoint with proper functional test.
And here's the problem - I can't pass the file to the client making the request.
My test class extends \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase.
static::createClient() method creates an instance of ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client and these Client does not support file uploads.
Beacuse of implementing the Symfony\Contracts\HttpClient\HttpClientInterface which defines public function request(string $method, string $url, array $options = []): ResponseInterface; there's no place for passing files argument.
The allowed options in Client does not support files array.
Internaly it looks like this:
ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client::request passes to the internal kernelBrowser an empty array in place of files params (2nd array): $this->kernelBrowser->request($method, $resolvedUrl, [], [], $server, $options['body'] ?? null)
How do you test endpoints with file upload by extending Base class for functional API tests which is ApiTestCase?
Here's some code, to help you visualize the problem:
ApiResource definition in entity:
/**
* #ApiResource(
* collectionOperations={
* "file_upload"={
* "method"="post",
* "controller"=FileUpload::class,
* "path"="/api/file-upload-endpoint",
* "deserialize"=false,
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* },
* },
* )
*/
Test class (don't mind the instance of UploadedFile, it's just there, to show you, that it cannot be passed anywhere):
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
And here is what i'm looking for:
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
[
'file'=>$file
]
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
When modyfing the vendor itself and passing the files to the Client::request and then to the kernelBrowser in place of 2nd empty array, everything works fine (I'm aware of breaking the contract, that's not the issue here ;)).
I'm thinking if there's missing feature of uploading files in ApiTestCase or I just can't find the solution.
Pls halp!
Api Platform version: 2.5.6
PS: I know i can use different client - test.client
$client = static::$kernel->getContainer()->get('test.client');
which is an instance of Symfony\Bundle\FrameworkBundle\KernelBrowser, the same that is used internally by the Api Platform's Client and that supports files array, but that's not the point of my question. I'd like to know how to do file upload with ApiTestCase.
Since the current latest release of api-platform/core (2.5.8) we are able to pass more parameters to kernelBrowser->request via the extra key. This also now includes files!
Here is a very basic example of testing an image upload (implemented based on the official API Platform documentation):
$file = new UploadedFile(
'path/to/images/my_image.png',
'my_image.png',
'image/png',
);
$response = static::createClient()->request('POST', '/upload_image',
[
'headers' => ['Content-Type' => 'multipart/form-data'],
'extra' => [
'files' => [
'file' => $file,
],
],
],
);

How to add accept application/json header for swagger-php OpenApi

I'm use L5-Swagger 5.7.* package (wrapper of Swagger-php) and tried describe Laravel REST API. So, my code like this:
/**
* #OA\Post(path="/subscribers",
* #OA\RequestBody(
* #OA\MediaType(
* mediaType="application/json",
* #OA\Schema(
* type="object",
* #OA\Property(property="email", type="string")
* )
* )
* ),
* #OA\Response(response=201,description="Successful created"),
* #OA\Response(response=422, description="Error: Unprocessable Entity")
* )
*/
public function publicStore(SaveSubscriber $request)
{
$subscriber = Subscriber::create($request->all());
return new SubscriberResource($subscriber);
}
But when I try send request via swagger panel I get code:
curl -X POST "https://examile.com/api/subscribers" -H "accept: */*" -H "Content-Type: application/json" -H "X-CSRF-TOKEN: " -d "{\"email\":\"bademail\"}"
As you can see, accept is not application/json and Laravel doesn't identify this as an AJAX request. So, when I send wrong data and expect to get 422 with errors in real I get 200 code with errors in "session". Request (XHR) through the swagger panel is also processed incorrectly, CURL code just for clarity.
Also, I found that in the previous version was used something like:
* #SWG\Post(
* ...
* consumes={"multipart/form-data"},
* produces={"text/plain, application/json"},
* ...)
But now it's already out of date.
So, how get 422 code without redirect if validation fails? Or maybe add 'XMLHttpRequest' header? What is the best thing to do here?
The response(s) didn't specify a mimetype.
#OA\Response(response=201, description="Successful created"),
If you specify a json response, swagger-ui will send an Accept: application/json header.
PS. Because json is so common swagger-php has a #OA\JsonContent shorthand, this works for the response:
#OA\Response(response=201, description="Successful created", #OA\JsonContent()),
and the requestbody:
#OA\RequestBody(
#OA\JsonContent(
type="object",
#OA\Property(property="email", type="string")
)
),
you can use this, i use Request class,
on the file Request
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
public function rules()
{
return [
'currentPassword' => 'required',
'newPassword' => 'required|same:confirmPassword',
'confirmPassword' => 'required'
];
}
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json([
'errors' => $validator->errors(),
'status' => true
], 422));
}

Swagger-php with Swagger-ui not working with Basic Authentication

I use swagger-ui and swagger-json generated with swagger-php. I m not able to do a basic auth to use my endpoint. I m able to get the swagger json file from my application but not to use exposed endpoint. I don't see what i m misunderstanding. If someone could show me a full example with basic auth in swagger 2.0 ?
CORS is enabled and totally working. Swagger-ui is running on localhost:3000 with nodejs and my application is running php with nginx on localhost:80.
I use swagger-ui-dist 3.14.1 that is compatible with swagger 2.0 (swagger-php is 2.0)
3.14.1 | 2018-05-04 | 2.0, 3.0 | tag v3.14.1
I m using theses SWG comments in my controllers to use basicAuth, (server-side)
/**
* #SWG\SecurityScheme(
* securityDefinition="basicAuth",
* name="authorization",
* type="basic",
* scheme="http"
* )
*/
and this comments
/**
* #SWG\Get(
* description="Get all catalog",
* path="/ott/catalogs",
* produces={"application/json"},
* security = {"basicAuth"},
* #SWG\Response(response="200", description="Get all catalogs"),
* #SWG\Response(response="401",description="You are not authorized")
* )
* )
*/
Here is my client-side code:
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://ott/ott/tools/swagger",
host: 'ott',
basePath: 'ott/',
schemes: 'http',
enableCORS: true,
dom_id: '#swagger-ui',
deepLinking: true,
validatorUrl:null,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
requestInterceptor: (req) => {
if (req.loadSpec) {
let hash = btoa("*******" + ":" + "********");
req.headers.Authorization = "Basic " + hash;
}
return req
},
onComplete : () => {
ui.preauthorizeBasic("basicAuth","*******","*******")
}
});
window.ui = ui
When i click to the lock, i have the first error in my console and then when i try to get my catalogs i get a 401 - not authorized because the Basic Authentication header is not sent.
Annotations do not look right. Change #SWG\SecurityScheme to:
/**
* #SWG\SecurityScheme(
* securityDefinition="basicAuth",
* type="basic"
* )
*/
(without the name and scheme attributes), and change the security in #SWG\Get as follows:
/**
* #SWG\Get(
* ...
* security = {{"basicAuth": {}}},
* ...

Bad Request: `url` is required but missing

Hi Restler/Swagger friends,
I'm facing a problem when i trying to post a url (ex. /home/ahmad/) as follow:
{
"error": {
"code": 400,
"message": "Bad Request: `url` is required but missing."
},
"debug": {
"source": "Validator.php:26 at validate stage",
"stages": {
"success": [
"get",
"route",
"negotiate"
],
"failure": [
"validate",
"message"
]
}
}
}
my code for test is:
/**
* POST url
*
* #param string $url {#from url} url for test
*
* #return string
*/
function post_url($url) {
return $url;
}
I tried debugging the problem and discovered that url value is received as NULL before the Validator is applied
How i can solve such this problem?
I can see few problems with your approach
First, if you want to map a parameter to url you have to use {#from path} not {#from url}
Then if your variable is going to contain slashes they should ideally be mapped to query string or body as the slashes in the url path will be understood as many parameters by Restler
If you must accept it part of the url, you can use the wildcard routing as shown below
/**
* POST url
*
* #return string
*
* #url POST url/*
*/
function postUrl() {
return implode(',', func_get_args());
}

Symfony2 FOS RestBundle Test

I`m trying to write some functional tests for a REST API, created using FOS Rest Bundle.
The problem is that when I use the Symfony\Component\BrowserKit, symfony throws me the following error:
{"message":"Unable to find template \"AccountBundle:Account:list.html.twig\". .. }
The code that I run is:
$client = static::createClient();
$client->request('GET','/account');
When I run the request from the browser, it works fine.
Here is the controller:
/**
* Get channel by ID
* #Secure(roles="ROLE_USER")
* #RestView()
* #ApiDoc(
* resource=true,
* description="Get channel by id",
* section="Channel",
* output="Channel"
* )
*/
public function getAction(Channel $channel)
{
return array('channel' => $channel);
}
So when in test scenario, instead of returning the JSON tries to load the template.
You should use the $server parameter of the $client-request() method to set the Accept header to application/json. FOSRestBundle has a listener that returns JSON only if the corresponding Accept header is received, otherwise it will search for the template corresponding to the controller.
$client->request('GET', '/account', array(), array(), array('HTTP_ACCEPT' => 'application/json'));

Categories