I just started with php and Slim framework. My main goal is to generate a RESTful API where I have a /swagger route where I show the API documentation using swagger ui.
This are the steps I followed:
Install last version php
Install composer
Install required dependecies:
composer require slim/slim:"4.*"
composer require zircote/swagger-php
Create API project (composer create-project slim/slim-skeleton testAPI)
Anotate involved elements in my API
Generate swagger file (.\vendor\bin\openapi -output .\swagger.json .\src)
Add new route to my API:
use OpenApi\Generator as OpenApiGenerator;
/**
* #OA\Get(
* path="/openapi",
* tags={"documentation"},
* summary="OpenAPI JSON File that describes the API",
* #OA\Response(response="200", description="OpenAPI Description File"),
* )
*/
$app->get('/swagger', function ($request, $response, $args) {
$swagger = OpenApiGenerator::scan(['../swagger.json']);
$response->getBody()->write(json_encode($swagger));
return $response->withHeader('Content-Type', 'application/json');
});};
But when I go and run the api and check /swagger route this is what I get:
{
"statusCode": 500,
"error": {
"type": "SERVER_ERROR",
"description": "WARNING: Required #OA\\PathItem() not found"
}
}
Have I missed something? Or my OpenApiGenerator::scan(['../swagger.json']) does not make sense? I have seen people doing OpenApiGenerator::scan(['.']) but that gives me the exact same output.
Solved it by making my /swagger route returning the swaggerUI html. For that, it is necessary to have this folder in the project.
Related
In symfony you can use the command make:crud. That works excellent with forms and twig in symfony. But is there also a way to do it with api's? That I will send an POST to the route of the annotation.
Like in python;
url = 'https://127.0.0.1:8000/players/new'
myobj = {
'postName': 'postData',
}
This python code is used when i want to test a POST.
This is a piece of a make:crud what i used, only showing the New function of the CRUD. This only works with forms. I cant send directly a POST(ex, python) to it.
/**
* #Route("/players/new", name="players_new", methods={"GET","POST"})
*/
public function new(Request $request): Response
{
$player = new Players();
$form = $this->createForm(PlayersType::class, $player);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($player);
$entityManager->flush();
return $this->redirectToRoute('players_index');
}
return $this->render('players/new.html.twig', [
'player' => $player,
'form' => $form->createView(),
]);
}
I changed your endpoint slightly to make it more API friendly. In all the public facing APIs that I've built they all return JSON. That just eases the burdens for implementation. I always use a status 201 for creation, and 400 for bad requests. This serves a traditional role for RESTful API paradigms and implementations.
/**
* #Route("/players/{player}", name="get_player", methods={"GET"})
*/
public function getPlayer(Player $player): Response {
// You might need to tweak based on your Entity name
return new JsonResponse($player);
}
/**
* #Route("/players/new", name="players_new", methods={"POST"})
*/
public function newPlayer(Request $request): Response
{
$player = new Players();
$form = $this->createForm(PlayersType::class, $player);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
try {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($player);
$entityManager->flush();
} catch (\Exception $e) {
// Probably a better exception to catch here, log it somewhere
throw $e;
}
return new JsonResponse('', Response::HTTP_CREATED);
}
return new JsonResponse(
'Invalid data provided to API, please refer to documentation',
Response::HTTP_BAD_REQUEST
);
}
Changing the method from new to newPlayer was done because a method named new is confusing down the road. One thing I would also like to point out is that with Doctrine it's best to have your entities singular. Example: Player instead of Players. You can have the relationship be players within the Entity.
The Entity Game could have $players which is a relationship to OneToMany Player Entities.
Catching the exception on flush is good standard practice there. You should return a meaningful JsonResponse as well after you've logged it.
As per the official documentation, API platform is a “powerful but easy to use full-stack framework dedicated to API driven projects”. API platform helps developers significantly speed up their development process, building complex and high performance, hypermedia-driven APIs.
It ships with Symfony 4, the Doctrine ORM, a dynamic Javascript admin created with React, and React Admin, Varnish Cache server, Helm Chart to help deploy the API in a Kubernetes cluster and a Progressive Web Application skeleton. It also includes a Docker setup for providing Nginx servers to run the API and JavaScript apps. Most inspiring is the ability of API platform to natively generate project documentation with support of OpenAPI!
In this tutorial, I will take you through how to create a simple bucket list API with CRUD operations.
Prerequisites
PHP - Version 7.0 or higher.
Docker
Postgres
Getting Started
Follow the instructions below to setup your development environment:
$ mkdir demo-app
$ cd demo-app
Download the latest compressed .tar.gz distribution. Then extract it inside of our working directory and run the commands below:
$ cd api-platform-2.4.5
$ docker-compose pull
$ docker-compose up -d
The docker-compose pull command downloads all images specified in the docker-compose.yml file. In order to start the containers, run docker-compose up -d. The -d flag runs the containers in detached mode, meaning they run in the background. In order to view the container logs, you can run this command docker-compose logs -f in a separate terminal.
Every time php artisan down is turned on, Laravel displays 503 page.
OK. I can customise it by creating new file called 503.blade.php inside resources/views/errors.
The point is that I don't consider Maintenance Mode as error at any point despite of the fact that it makes website unavailable for a client.
The 503 Service Unavailable error is a server-side error, meaning the
problem is usually with the website's server. ... Even though the 503
Service Unavailable error means that there's an error on another
computer, the issue is probably only temporary.
How can I define my own blade template (let's say maintenance_mode.blade.php) to customize what users see during the app down and leave 503 intact?
My efforts: I investigated the middleware itself inside the vendor but it only throws the exception, I assume the exception is being caught somewhere with and handles response with a corresponding view? Can someone point me on how to achieve what I need?
Thanks
One way could be to change render method in Exception's Handler. Something like:
// app_path('Exceptions/Handler.php');
/**
* Render an exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #param \Exception $exception
* #return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if ($exception instanceof \Illuminate\Foundation\Http\Exceptions\MaintenanceModeException) {
return response()
->view('maintenance.down', [
'message' => 'Come back later.'
], 200)
->header('Content-Type', 'text/html; charset=utf-8');
}
// in Laravel 8.x MaintenanceModeException is deprecated and one should rely on
// #throws \Symfony\Component\HttpKernel\Exception\HttpException
// or
// \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException
if ($exception instanceof \Symfony\Component\HttpKernel\Exception\HttpException ) {
return response()
->view('maintenance.down', [
'message' => 'Come back later.'
], 200)
->header('Content-Type', 'text/html; charset=utf-8');
}
return parent::render($request, $exception);
}
Thanks to #Ifnot 's input, answer is updated to comply Laravel 8.x
If You want to display custom message in server maintanence(503.blade.php)
Laravel Has the out of box customization
php artisan down --message="We are Upgrading look and feel"
now We are Upgrading look and feel will be displayed in page while user visiting the page
If You want More customization kindly Look up the package
https://github.com/MisterPhilip/maintenance-mode
If this answer is irrelevnt or not fixed your problem kindly comment below so that i can fix that
Hope it helps
Edited
Ok then run the command in your terminal
php artisan vendor:publish and choose 0 so that it will publish all the views and configs
now open your view folder there will be a errors
folder and you can see the list of error files provided by laravel now change as per your customization and run php artisan opt:clear it will clear all the cache views ,configs and now try it
by Customising your 503.blade.php its works fine form me now
you can just view the tutorial of customising 404.blade.php and customize as per the requirement
Customize 404 in laravel
So thanks to Matteo (phpunit in symfony2 - No tests executed) I can now test my functional tests.
Now I got the following error when running phpunit -c app:
You must change the main Request object in the front controller (app.php)
in order to use the `host_with_path` strategy.
so I did change it in the app.php, from:
$request = RequestFactory::createFromGlobals('host_with_path');
to:
$request = Request::createFromGlobals();
I also updated my swiftmailer-bundle from version 2.3 to 5.4.0.
Unfortunately This did not fix my error.
and this is my ../app/config_test.yml
swiftmailer:
disable_delivery: true
Am I missing something here?
I cannot seem to find this error anywhere on the web. Does someone know how I should fix this error?
After some searching I noticed that the app.php wasn't the problem. It was the DefaultControllerTest.php. The error could be fixed by removing the following lines from the DefaultControllerTest:
$crawler = $client->request('GET', '/hello/Fabien');
$this->assertTrue($crawler->filter('html:contains("Hello Fabien")')->count() > 0);
Due to recent developments our development team decided to stop using Sonata. As a side effect this bug got fixed. So I won't have a solution for this problem.
The problem here is, that the Client object is using neither app.php nor app_dev.php.
The client creates the request internally. So it won't be the request you need.
The only solution I can see is to override the method Symfony\Bundle\FrameworkBundle\Test\WebTestCase::createClient to return your own client. This client is than responsible for creating the actual request object. The following is the current behavior.
namespace Symfony\Component\HttpKernel;
use Symfony\Component\BrowserKit\Client as BaseClient;
class Client extends BaseClient
{
...
/**
* Converts the BrowserKit request to a HttpKernel request.
*
* #param DomRequest $request A DomRequest instance
*
* #return Request A Request instance
*/
protected function filterRequest(DomRequest $request)
{
$httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent());
foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) {
$httpRequest->files->set($key, $value);
}
return $httpRequest;
}
...
}
You have to override method filterRequest to return kind of a request you want.
I am trying to make the Restful API documentation in PHP swagger, what I did before is that I changed the JSON to work out, now I know we can make the JSON by making PHP files and using swagger notation. I did check the Pet.php example and I get the code but I don't know how to execute the file to get the JSON API documentation which I can link with my Swagger UI. I read the documentation but it is so confusing and I don't know how to get through this problem can anyone help, please? Here is the link I study but to no worth.
https://github.com/zircote/swagger-php
Swagger-PHP for generating JSON file for Swagger-UI
Can anyone tell me step-by-step how to generate the API documentation in JSON? I will be very thankful to him thanks.
There are two way to achieve this in swagger-php 2.0.
I.
The first solution is to create a controller or script which will generate the documentation on each request. This is a good solution in a development environment where you want to see quickly the outcome of your changes.
Here is an example of a controller which does this.
<?php
namespace Controllers;
use Swagger\Annotations as SWG;
use Swagger;
/**
* #SWG\Swagger(
* basePath="/path/to/opration/",
* produces={"application/json"},
* swagger="2.0",
* #SWG\Info(
* version="1.0.0",
* title="My API"
* )
* )
*
*/
class Documentation {
const API_PATH = "path/to/my/documented/files/";
public function show(){
$swagger = Swagger\scan(self::API_PATH);
return json_enconde($swagger); //you can echo this in the calling script.
}
}
Note: The example above assumes you installed Swagger-php with Composer and that the calling script include the composer generated autoload file (usually called: vendor/autoload.php).
II.
The first solution consisting of generating a static json API documentation is described here: https://stackoverflow.com/a/21380432/2853903
This solution recommended for production deployment, where you would not want to regenerate the documentation on every request.
I am new to this stuff but I love it. I made a little REST Api using the Slim Framework. Now I would like to have an ongoing documentation about it. I think swagger is the right choice but I have not found out yet how to integrate it ?
Cheers & thanks for your patience :)
I think you are looking for this project: zircote/swagger-php
Here you'll find how to generate the doc on user request to a URL.
Basically you have to annotate your code with the Swagger Annotations, then create another route in Slim with a code similar to this:
<?php
use Swagger\Swagger;
$swagger = new Swagger('/project/root/top_level');
header("Content-Type: application/json")
echo $swagger->getResource('/pet', array('output' => 'json'));
And it will generate the Swagger API docs on the fly for you.
A short update to the answer of adosaiguas:
When using Slim Framework 4.0 and zircote/swagger-php
one can provide an api endpoint providing the swagger / OpenAPI 3.0 json description using the following code:
use function OpenApi\scan;
/**
* #OA\Get(
* path="/openapi",
* tags={"documentation"},
* summary="OpenAPI JSON File that describes the API",
* #OA\Response(response="200", description="OpenAPI Description File"),
* )
*/
$app->get('/openapi', function ($request, $response, $args) {
$swagger = scan('--PATH TO PROJECT ROOT--');
$response->getBody()->write(json_encode($swagger));
return $response->withHeader('Content-Type', 'application/json');
});