how to make openapi platform path parameters appear in interface - api-platform.com

I am not able to create a collection route containing path parameters in a route like
/api/myEntity/{var1}/{var2}
I created annotations in my entity like below
collectionOperations={
* "get"={
* "method"="GET",
* "path"="/smyEntity/{var1}/{var2}",
* "controller"=CustomController::class,
* "pagination_enabled"=false,
* "read"=false,
* "openapi_context"= {
* "parameters" = {
* {
* "name" = "var1",
* "in" = "path",
* "type" = "string",
* },
* {
* "name" = "var2",
* "in" = "path",
* "type" = "string"
* }
* }
* }
* }
I have create my custom controller but the paths parameters do not appear in api admin interface

this works for v2.5.9 but not since 2.6.0
i will stick to 2.5.9 for now

Related

how to wrap Laravel resource with swagger

I am learning how to use laravel with swagger, and I have this issue:
I have the user controller:
UserController.php
class UserController extends Controller
{
/**
* Shows authenticated user information
*
* #OA\Get(
* tags={"Authorize"},
* path="/user",
* summary="get user detail",
* security={{ "AuthBearer":{} }},
* #OA\Response(
* response="200",
* description="success",
* #OA\JsonContent(
* ref="#/components/schemas/UserResource"
* )
* ),
* #OA\Response(response="401", description="Unauthenticated")
* )
*
* #return \Illuminate\Http\Response
*/
public function user()
{
return new UserResource(auth()->user());
}
}
UserResource.php
/**
* Class UserResource
*
* #OA\Schema(
* #OA\Xml(name="UserResource")
* )
*/
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #OA\Property(format="int64", title="ID", default=1, description="ID", property="id"),
* #OA\Property(format="string", title="name", default="Demo", description="Name", property="name"),
* #OA\Property(format="string", title="username", default="demo", description="Username", property="username"),
* #OA\Property(format="string", title="avatar_path", default="https://via.placeholder.com/640x480.png/0000bb?text=avatar", description="Avatar Path", property="avatar_path")
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'username' => $this->username,
'avatar_path' => $this->avatar_path
];
}
}
this is working fine, but in the swagger docs, the example value for this route is this:
{
"id": 1,
"name": "demo",
"username": "demo",
"avatar_path": "https://via.placeholder.com/640x480.png/0000bb?text=avatar"
}
But when I execute the route in swagger, it returns this:
{
"data": {
"id": 1,
"name": "demo",
"username": "demo",
"avatar_path": "https://via.placeholder.com/640x480.png/0000bb?text=avatar"
}
}
This is wrapped inside a data property, I would like that the example has the same format, how could achieve that? thanks.
You can write in UserResource.php:
/**
* #OA\Schema(
* #OA\Xml(name="UserResource"),
* #OA\Property(property="data", type="array",
* #OA\Items(ref="#/components/schemas/User"))
* ),
* )
*/
And in model User.php
/**
* #OA\Schema(
* #OA\Xml(name="User"),
* #OA\Property(format="int64", title="ID", default=1, description="ID", property="id"),
* #OA\Property(format="string", title="name", default="Demo", description="Name", property="name"),
* #OA\Property(format="string", title="username", default="demo", description="Username", property="username"),
* #OA\Property(format="string", title="avatar_path", default="https://via.placeholder.com/640x480.png/0000bb?text=avatar", description="Avatar Path", property="avatar_path")
* )
*/

Action / GET with limited properties

Certainly already asked but...
Having this entity
/**
* A form
*
* #ORM\Entity(repositoryClass=FormRepository::class)
*
* #ORM\Table(
* name="forms",
* options={"comment":"Table of the forms"},
* indexes={
* #ORM\Index(name="forms_idx_dofc", columns={"dateofcreation"}),
* #ORM\Index(name="forms_idx_dofu", columns={"dateofupdate"}),
* #ORM\Index(name="forms_idx_dofs", columns={"dateofsubmission"})
* }
* )
*
* #ApiResource(
* routePrefix="/",
* shortName="Forms",
* description="API Access : form Entity",
* collectionOperations={"GET"},
* itemOperations={"GET"},
* attributes={
* "normalization_context"={
* "groups"={
* "GET:FORM"
* }
* },
* "order"={
* "dateofsubmission",
* "dateofupdate",
* "dateofcreation"
* }
* }
* )
*
*/
class Form
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer", options={"comment":"Primary Key, Auto generated"})
*/
private $id;
/**
* #var datetime Date of creation of the form.
*
* #ORM\Column(type="datetime", options={"comment":"date of creation of the form"})
*
* #Assert\NotBlank(message="The date time when was created the form should not be blank")
* #Assert\DateTime(message="The data time when was created the form should be the type DateTime")
*
* #Groups({"GET:FORM"})
*
* #ApiFilter(OrderFilter::class, strategy="ASC")
*/
private $dateofcreation;
/**
* #var datetime Date of update of the form.
*
* #ORM\Column(type="datetime", options={"comment":"date of update of the form"})
*
* #Assert\NotBlank(message="The date time when was updated the form should not be blank")
* #Assert\DateTime(message="The data time when was updated the form should be the type DateTime")
*
* #Groups({"GET:FORM"})
*
* #ApiFilter(OrderFilter::class, strategy="ASC")
*/
private $dateofupdate;
/**
* #var person Person that has created the form.
*
* #ORM\ManyToOne(targetEntity=Person::class, inversedBy="forms")
* #ORM\JoinColumn(nullable=false)
*
* #Groups({"GET:FORM"})
*
* #ApiFilter(SearchFilter::class, properties={"createdBy.id":"exact","createdBy.givenname":"ipartial", "createdBy.familyname":"ipartial"})
* #ApiFilter(OrderFilter::class, strategy="ASC")
*/
private $createdBy;
...
I would like to have the possibility of having :
A base collectionOperations "GET" would return all the properties that have the #GROUP=GET:FORM
A alternate collectionOperations "GETDATES" would return all properties that have a #GROUP=GET:DATES
The operations being accessible (ideally) with different routes.
GET => # http://api/forms?createdBy.id=25 => All properties
GETDATES => http://api/formsLimited?createdBy.id=25 => only the dates
ps: I hope this is better for the readability.
Thanks to Grégoire Hébert(https://stackoverflow.com/users/4887997/gr%C3%A9goire-hebert) for the support (on Slack).
The solution is quite simple.
Create in the ApiResource() a collection operation with:
Method = GET
path (that will become a route)
the normalization context for the group to be applied to the wanted properties
It gives:
collectionOperations={"GET","GETLIMITED"={"method"="GET","path"="formslist","normalization_context"={"groups"="GET:LIMITED"}}},

How to validate PUT input in ApiPlatform?

suppose I have an ApiResource like this:
class MyResource {
const STATUS_A = 'A';
const STATUS_B = 'B';
const STATUS_C = 'C';
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
* #Assert\Choice(
* choices = {MyResource::STATUS_A, MyResource::STATUS_B, MyResource::STATUS_C}
* )
* #Assert\NotNull()
*/
private $status;
/**
* #ORM\Column(type="integer")
* #Assert\NotNull()
*/
private $counter;
...
}
As you can see, I setup validation constraints so the status value can be STATUS_A, STATUS_B or STATUS_C.
Now, I'd like to also validate the data provided in PUT requests, so that status can only be set to STATUS_A.
For example, the following PUT payload should be accepted:
{
"status": "A"
}
{
"status": "A",
"counter: 5
}
{
"counter": 5
}
Instead, the following one should NOT be accepted:
{
"status": "B"
}
{
"status": "C",
"counter": 5
}
What is the best point to perform validation against data provided by the API client?
I know that I could use validation inside DTOs DataTransformers, but I'm not using DTOs this time.
Thank you. Any advice would be really appreciated.

'Not setting the "method" attribute' deprecations

How do I get rid of messages like this?
[2019-10-28 18:18:55] php.INFO: User Deprecated: Not setting the "method" attribute is deprecated and will not be supported anymore in API Platform 3.0, set it for the item operation "api_admin_azvr_users_get_item" of the class "App\API\DTO\AdminAzvrUser". {"exception":"[object] (ErrorException(code: 0): User Deprecated: Not setting the \"method\" attribute is deprecated and will not be supported anymore in API Platform 3.0, set it for the item operation \"api_admin_azvr_users_get_item\" of the class \"App\API\DTO\AdminAzvrUser\". at /home/avrsites/websites/mydomain.com/symfony/vendor/api-platform/core/src/Bridge/Symfony/Routing/ApiLoader.php:206)"} []
Here are the annotations of the referenced DTO class:
* #ApiResource(
* itemOperations={
* "get"={
* "path"="/admin_azvr_user/{id}",
* },
* "api_admin_azvr_users_get_item"={
* "swagger_context"={
* "operationId"="getAdminAzvrUserItem",
* "summary"="Retrieves details on a user (msg_azvr_user table)",
* "parameters"= {
* {
* "name"="id",
* "description"="Inquiry ID",
* "default"="520",
* "in"="path",
* "required"=true,
* "type"="string"
* }
* },
* "responses"={
* "200"={
* "description"="Results retrieved"
* },
* "400"={
* "description"="Invalid input"
* },
* "404"={
* "description"="User not found"
* }
* }
* }
* }
* },
* collectionOperations={}
* )
Where am I supposed to set the "method" attribute? I tried setting "method"="GET" inside the api_admin_azvr_users_get_item section, but it did not fix the problem.
My log is full of these messages and I can't find any relevant documentation on how to fix things.
It needs to be placed on the mentioned item operation, in this case: api_admin_azvr_users_get_item which results in:
* #ApiResource(
* itemOperations={
* "api_admin_azvr_users_get_item"={
* "method"="GET",
* "path"="/admin_azvr_user/{id}",
* "swagger_context"={
* "operationId"="getAdminAzvrUserItem",
* "summary"="Retrieves details on a user (msg_azvr_user table)",
* "parameters"= {
* {
* "name"="id",
* "description"="Inquiry ID",
* "default"="520",
* "in"="path",
* "required"=true,
* "type"="string"
* }
* },
* "responses"={
* "200"={
* "description"="Results retrieved"
* },
* "400"={
* "description"="Invalid input"
* },
* "404"={
* "description"="User not found"
* }
* }
* }
* }
* },
* collectionOperations={}
* )
If the deprecation note remains try clearing the cache bin/console cache:clear

Symfony API Entity Validation

I have a class with annotations for the validation.
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serialize;
use Symfony\Component\Validator\Constraints as Assert;
use AppBundle\Annotation\Link;
/**
* #Serialize\ExclusionPolicy("all")
* #Serialize\AccessType(type="public_method")
* #Serialize\AccessorOrder("custom", custom = {"id", "name", "awardType", "nominations"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\AwardRepository")
* #ORM\Table(name="awards")
* #Link("self", route = "api_awards_show", params = { "id": "object.getId()" })
*/
class Award extends Entity
{
/**
* #Serialize\Expose()
* #Serialize\Type(name="string")
* #Assert\Type(type="string")
* #Assert\NotBlank(message="Please enter a name for the Award")
* #Assert\Length(min="3", max="255")
* #ORM\Column(type="string")
*/
private $name;
/**
* #Serialize\Expose()
* #Serialize\Type(name="AppBundle\Entity\AwardType")
* #Serialize\MaxDepth(depth=2)
* #Assert\Valid()
* #ORM\ManyToOne(
* targetEntity="AppBundle\Entity\AwardType",
* inversedBy="awards"
* )
*/
private $awardType;
/**
* #Serialize\Expose()
* #Serialize\Type(name="ArrayCollection<AppBundle\Entity\Nomination>")
* #Serialize\MaxDepth(depth=2)
* #ORM\OneToMany(
* targetEntity="AppBundle\Entity\Nomination",
* mappedBy="award"
* )
*/
private $nominations;
}
I then validate that entity with the following:
$validator = $this->get('validator');
$errors = $validator->validate($entity);
if (count($errors) > 0) {
$apiProblem = new ApiProblem(
400,
ApiProblem::TYPE_VALIDATION_ERROR
);
$apiProblem->set('errors', ['testing', 'array']);
throw new ApiProblemException($apiProblem);
}
$this->save($entity);
This works fine the problem is that i cant get the information on which fields have errors and their error message. $errors in this case seems to be of an unknown type which i cant seem to get the error messages for any fields.
How do i get the error messages of that object?
You can get the exact messages of the errors like this:
$errors = $validator->validate($entity);
if (count($errors) > 0) {
$formattedErrors = [];
foreach ($errors as $error) {
$formattedErrors[$error->getPropertyPath()] = [
'message' => sprintf('The property "%s" with value "%s" violated a requirement (%s)', $error->getPropertyPath(), $error->getInvalidValue(), $error->getMessage());
];
}
return new \Symfony\Component\HttpFoundation\JsonResponse($formattedErrors, 400);
}
For example, that could output:
[
'field1' => 'The property "field1" with value "" violated a requirement (Cannot be null)',
// ...
]

Resources