I have an API endpoint in my Symfony 4 application, that I want to document with NelmioApiDocBundle and Swagger. The endpoint takes JSON as a request data and also returns some custom JSON as the response. How can I add examples of them to the documentation, using annotations? I can't see any of the examples on the documentation page, only the description.
/**
* #Route("/order/import", methods={"POST"}, name="order_import")
* #OA\RequestBody (
* request="order",
* description="Order data in JSON format",
* #OA\Schema(
* type="object",
* example={"hello": "world"}
* )
* )
* #OA\Response(
* response=200,
* description="Returns the JSON data after import",
* #OA\Schema(
* type="object",
* example={"foo": "bar"}
* )
* )
* #OA\Tag(name="import")
For NelmioApiDocBundle v4 you can do like this
use OpenApi\Annotations as OA;
/**
* #OA\Parameter(
* name="body",
* in="path",
* required=true,
* #OA\JsonContent(
* type="object",
* #OA\Property(property="property1", type="number"),
* #OA\Property(property="property2", type="number"),
* ),
* )
*
* #OA\Response(
* response=200,
* description="",
* #OA\JsonContent(
* type="object",
* #OA\Property(property="property1", type="number"),
* #OA\Property(property="property2", type="number"),
* )
* )
*/
For v3
use Swagger\Annotations as SWG;
/**
* #SWG\Parameter(
* name="body",
* in="body",
* required=true,
* #SWG\Schema(
* #SWG\Property(property="test1", type="string"),
* #SWG\Property(property="test2", type="string"),
* ),
* )
*
* #SWG\Response(
* description="",
* response=200,
* #SWG\Schema(
* #SWG\Property(property="test1", type="string"),
* #SWG\Property(property="test2", type="string"),
* ),
* )
*/
But better to do it via #Model annotation, as described in the doc if you have DTO or entity.
Related
With Api Platform, we can order by association.
Documentation :
use ApiPlatform\Core\Annotation\ApiResource;
/**
* #ApiResource(attributes={"order"={"author.username"}})
*/
class Book
{
...
But I want to order on an entity cascade.
For the example below I tested this with this error :
* #ApiResource(
* attributes={
* "order"={"exercises.repetitions.id":"asc"}
* }
* )
[Semantical Error] line 0, col 422 near 'id ASC, rests_a6.id': Error: Class App\Entity\TrainingSerieExercise has no field or association named repetitions.id
TrainingSerie entity :
* #ApiResource(
...
* attributes={
* "order"={"exercises.repetitions.id":"asc"}
* }
* )
*/
class TrainingSerie
{
...
/**
* #var TrainingSerieExercise[]|ArrayCollection
*
* #ORM\OneToMany(
* targetEntity="App\Entity\TrainingSerieExercise",
* mappedBy="serie",
* cascade={"persist"}
* )
* #Groups({
* "trainings_read",
* "training_series_read",
* "training_series_write",
* })
*/
private $exercises;
...
TrainingSerieExercise entity :
...
class TrainingSerieExercise
{
...
/**
* #var TrainingSerieRepetition[]|ArrayCollection
*
* #ORM\OneToMany(
* targetEntity="App\Entity\TrainingSerieExerciseRepetition",
* mappedBy="exercise",
* cascade={"persist"},
* )
* #Groups({
* "training_series_read",
* "training_series_write",
* "training_serie_exercices_write",
* })
*/
private $repetitions;
...
TrainingSerieExerciseRepetition entity :
class TrainingSerieExerciseRepetition
{
...
/**
* #var integer
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #Groups({
* "training_series_read",
* })
*/
private $id;
...
Following this Doctrine doc this will order TrainingSerieExercise::$repetitions by id:
class TrainingSerieExercise
{
...
/**
* #var TrainingSerieRepetition[]|ArrayCollection
*
* #ORM\OneToMany(
* targetEntity="App\Entity\TrainingSerieExerciseRepetition",
* mappedBy="exercise",
* cascade={"persist"},
* )
* #ORM\OrderBy({"id" = "ASC"})
* #Groups({
* "training_series_read",
* "training_series_write",
* "training_serie_exercices_write",
* })
*/
private $repetitions;
...
I am trying to declare a subresource in my symfony app. I followed the api-platform doc about it: https://api-platform.com/docs/core/subresources/
The subresource does appear in the routes, but not under its parent resource.
The routes I currently have:
api_files_get_collection GET ANY ANY /api/files.{_format}
api_files_post_collection POST ANY ANY /api/files.{_format}
api_files_get_item GET ANY ANY /api/files/{id}.{_format}
api_files_patch_item PATCH ANY ANY /api/files/{id}.{_format}
api_files_put_item PUT ANY ANY /api/files/{id}.{_format}
api_external_subscription_requests_get_collection GET ANY ANY /api/external_subscription_requests.{_format}
api_external_subscription_requests_post_publication_collection POST ANY ANY /api/subscribe
api_external_subscription_requests_get_item GET ANY ANY /api/external_subscription_requests/{id}.{_format}
The routes I would like to have:
api_files_get_collection GET ANY ANY /api/files.{_format}
api_files_post_collection POST ANY ANY /api/files.{_format}
api_files_get_item GET ANY ANY /api/files/{id}.{_format}
api_files_patch_item PATCH ANY ANY /api/files/{id}.{_format}
api_files_put_item PUT ANY ANY /api/files/{id}.{_format}
api_files_external_subscription_requests_get_collection GET ANY ANY /api/files/{id}/external_subscription_requests.{_format}
api_files_external_subscription_requests_post_publication_collection POST ANY ANY /api/files/{id}/subscribe
api_files_external_subscription_requests_get_item GET ANY ANY /api/files/{id}/external_subscription_requests/{id}.{_format}
Code in App\Entity\File.php:
/**
* #ORM\Entity
* #ApiResource(
* attributes={"order"={"createdAt": "DESC"}},
* collectionOperations={
* "get"={
* "normalization_context"={"groups"={"model:timestampable", "file:collection:read"}},
* },
* "post",
* },
* itemOperations={
* "get"={
* "normalization_context"={"groups"={"model:timestampable", "file:item:read"}},
* },
* "patch",
* "put"
* },
* )
*/
class File
{
// ...
/**
* #ORM\OneToMany(targetEntity="App\Entity\ExternalSubscriptionRequest", cascade={"all"}, mappedBy="file")
* #Groups({
* "file:collection:read",
* "file:item:read"
* })
* #ApiSubresource()
*/
private $external_subscription_requests;
// ...
}
Code in App\Entity\ExternalSubscriptionRequest.php:
/**
* #ORM\Entity
* #ApiResource(
* collectionOperations={
* "get",
* "post_publication"={
* "method"="POST",
* "path"="/subscribe",
* "controller"=SubscribeToConso::class,
* }
* },
* itemOperations={
* "get",
* },
* )
*/
class ExternalSubscriptionRequest
{
// ...
/**
* #var File the file this request was made for
*
* #ORM\ManyToOne(targetEntity="App\Entity\File", inversedBy="external_subscription_requests")
* #ORM\JoinColumn(referencedColumnName="id", nullable=false)
*
* #Groups({
* "external_subscription_request:collection:read",
* "external_subscription_request:item:read"
* })
*/
public $file;
// ...
}
I'm stuck with something with API Platform and Vich Uploader for a PUT request, the POST is working juste fine.
Here is my header for MediaObject entity :
/**
* #ORM\Entity
* #ApiResource(
* iri="http://schema.org/MediaObject",
* normalizationContext={
* "groups"={"media_object_read"}
* },
* collectionOperations={
* "post"={
* "controller"=CreateMediaObjectAction::class,
* "deserialize"=false,
* "security"="is_granted('ROLE_USER')",
* "validation_groups"={"Default", "media_object_create"},
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* },
* "get",
* },
* itemOperations={
* "get",
* "put"={"controller"=UpdateMediaObjectAction::class,
* "deserialize"=false,
* "security"="is_granted('ROLE_USER')",
* "validation_groups"={"Default", "media_object_update"},
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }},
* "delete"={
* "security"="is_granted('ROLE_USER')"
* }
* }
* )
* #Vich\Uploadable
*/
class MediaObject
{...}
In swagger it throws an error because the file is not attached to the request. It strange because I have exactly the same file input field, with just an ID parameter added.
Someone has manage to do that ?
Found solution by myself !
Finally, the problem is that PHP does'nt handle well file in FormData on PUT, but well on POST.
So if you got the same issue change to "method"="POST" in the "put" part from itemOperations.
I am looking for a way to add multiple response types to swagger-ui implemented through NelmioAPiDoc
I would like the option for image/jpeg as a response type I have the code to work in the controller to set the body to the image even if the response type still say's application/json but my goal is if 'application/json' is selected it returns the url of image in json format, but if 'image/jpeg' is selected it returns the image to the body. Any help greatly appreciated.
/**
* #Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* #Route("/api/airs/renderframe", name="get_airs_frame", methods={"GET"})
*
* #SWG\Response(
* response=200,
* description="Returns json image url from paramaters",
* )
* #SWG\Parameter(
* name="imageHost",
* in="query",
* type="string",
* description="image host"
* )
* #SWG\Parameter(
* name="imagePath",
* in="query",
* type="string",
* description="image path"
* )
*
I have also tried adding this to the top of my class but still have the one drop down option
/**
* #SWG\Swagger(
* schemes={"http"},
* produces={"image/jpeg","application/json"},
* consumes={"application/json"}
* )
*/
got it working by putting the produces{} inside the #SWG\Get() but the response type is not in the request as a parameter need to figure out how to access the value now
/**
* #Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* #Route("/api/airs/renderframe", name="get_airs_frame", methods={"GET"})
*
* #SWG\Get(
* produces={"application/xml", "application/json"},
* #SWG\Parameter(
* name="imageHost",
* in="query",
* type="string",
* description="image host"
* ),
* #SWG\Parameter(
* name="imagePath",
* in="query",
* type="string",
* description="image path"
* ),
* #SWG\Parameter(
* name="resource",
* in="query",
* type="string",
* default="renderframe/serveframe",
* description="Render picture in frame"
* ),
* #SWG\Parameter(
* name="maxSize",
* in="query",
* type="integer",
* description="image max Size"
* ),
* #SWG\Parameter(
* name="inchesWidth",
* in="query",
* type="integer",
* description="image inches WIdth"
* ),
* #SWG\Parameter(
* name="inchesHeight",
* in="query",
* type="integer",
* description="image inches Height"
* ),
* #SWG\Response(
* response=200,
* description="Returns json image url from paramaters",
* ),
* #SWG\Tag(name="Render picture in frame")
* )
I am using nelmioapidocbundle in order to documents my Rest API built on the top of symfony-2.x.
I can't found the right annotation to use to show each Entity's property description on the return section (Please see bellow attached image).
My Entity :
/**
* Checkins
*
* #ORM\Table(name="CheckIns")
* #ORM\Entity(repositoryClass="Project1\ApiBundle\Entity\CheckinsRepository")
*
* #ExclusionPolicy("none")
*/
class Checkins
{
/**
* #var integer
*
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #Groups({"checkin"})
* #
*/
private $id;
My Controller :
class CheckinController extends BaseRestController
{
/**
* #ApiDoc(
* resource=true,
* description="Find checkin by ID",
*
* parameters={
* {"name"="categoryId", "dataType"="integer", "required"=true, "description"="checkin id"}
* }
*
* output={
* "class"="Project1\ApiBundle\Entity\Checkins",
* "groups"={"checkin"}
* },
* statusCodes={
* 200="Checkin found",
* 400="ID is required",
* 404="Checkin not found"
* }
* )
*
* #Rest\View()
*/
public function getAction(Request $request)
{}
Result ( Description column is empty ) :
There's a description in doc section of the bundle:
For classes parsed with JMS metadata, description will be taken from the properties doc comment, if available.
For Form Types, you can add an extra option named description on each
field
Please visit the following link for more instructions(info at the bottom of the section):
https://github.com/nelmio/NelmioApiDocBundle/blob/master/Resources/doc/index.md#the-apidoc-annotation