-->

Custom Symfony Action with API Platform bundle

2019-05-10 12:10发布

问题:

I try to build an API with the Symfony bundle API-Platform.

Api resource offer automatic CRUD action with the HTTP verbs POST, GET, PUT, DELETE.

What I want is adding an endpoint to handle a custom POST action, with a custom payload/body, not depending on any resource.

Where I block it is to add this endpoint to the automatic API-Platform documentation.

When looking for this kind of issue on GitHub, I found that the API-Platform v2 should be able to do it.

See Issue #385 : Custom action + ApiDoc

It looks like some people find the way to use NelmioApiDoc @ApiDoc annotation.

See Issue #17 : Documentation for custom operation

回答1:

Using the @ApiDoc annotation is a no go, support for NelmioApiDoc will be removed in API Platform 3 in favor of the builtin Swagger/Hydra support.

If you use a custom API Platform action, the action should automatically be documented in Swagger and Hydra docs.

Anyway, you can always customize the Swagger (and Hydra) docs to add custom endpoints or anything else: https://github.com/api-platform/docs/blob/master/core/swagger.md#override-swagger-documentation (this documentation will be available on the website soon).



回答2:

You can document your own route with the @ApiResource() annotation:

/**
 * @ORM\Entity
 * @ApiResource(
 *     itemOperations={
 *         "get"={"method"="GET"},
 *         "put"={"method"="PUT"},
 *         "delete"={"method"="DELETE"},
 *         "send_reset_password_token"={
 *             "route_name"="user_send_reset_password_token",
 *              "swagger_context" = {
 *                 "parameters" = {
 *                     {
 *                         "name" = "email",
 *                         "in" = "path",
 *                         "required" = "true",
 *                         "type" = "string"
 *                     }
 *                 },
 *                 "responses" = {
 *                     "201" = {
 *                         "description" = "email with reset token has been sent",
 *                         "schema" =  {
 *                             "type" = "object",
 *                             "required" = {
 *                                 "email"
 *                             },
 *                             "properties" = {
 *                                  "email" = {
 *                                     "type" = "string"
 *                                  },
 *                                  "fullname" = {
 *                                     "type" = "string"
 *                                  }
 *                             }
 *                         }
 *                     },
 *                     "400" = {
 *                         "description" = "Invalid input"
 *                     },
 *                     "404" = {
 *                         "description" = "resource not found"
 *                     }
 *                 },
 *                 "summary" = "Send email with token to reset password",
 *                 "consumes" = {
 *                     "application/json",
 *                     "text/html",
 *                  },
 *                 "produces" = {
 *                     "application/json"
 *                  }
 *             }
 *         }
 *     },
 *     attributes={
 *         "normalization_context"={"groups"={"user", "user-read"}},
 *         "denormalization_context"={"groups"={"user", "user-write"}}
 *     }
 * )
 */

Source: https://github.com/api-platform/docs/issues/143#issuecomment-260221717



回答3:

I ran into the same situation because I tried to put the POST method into itemOperations, although it can only reside in collectionOperations. In the latter in can successfully define my custom path.

/**
 * @ApiResource(
 *     collectionOperations={
 *       "get"={
 *           "path"="/name_your_route",
 *       },
 *       "post"={
 *           "path"="/name_your_route",
 *       },
 *     },
 *     itemOperations={
 *       "get"={
 *           "path"="/name_your_route/group/{groupId}/user/{userId}",
 *           "requirements"={"groupId"="\d+", "userId"="\d+"},
 *       },
 *       "delete"={
 *           "path"="/name_your_route/group/{groupId}/user/{userId}",
 *       },
 *       "put"={
 *           "path"="/name_your_route/group/{groupId}/user/{userId}",
 *       }
 * })

Hopefully helpful for others that stumble upon this question.

And here is the paragraph from the great documentation about it:

Collection operations act on a collection of resources. By default two routes are implemented: POST and GET. Item operations act on an individual resource. 3 default routes are defined GET, PUT and DELETE



回答4:

You can create custom post action like this. Map resources configuration to yaml.

# config/packages/api_platform.yaml
api_platform:
enable_swagger_ui: false
mapping:
    paths: ['%kernel.project_dir%/config/api_platform']

Create resources.yaml

# config/api_platform/resources.yaml
resources:
App\Entity\User:
  itemOperations: []
  collectionOperations:
    post:
        method: 'POST'
        path: '/auth'
        controller: App\Controller\AuthController
        swagger_context:
            summary: your desc
            description: your desc

Then in App\Entity\User add public properties

class User {
   public $login
   public $password
}

It is all, now in swagger ui u will see method POST /api/auth with login and pass parameters.

In u controller override _invoke for execute your logic.

class AuthController {
   public function __invoke()
   {
      return ['your custom answer'];
   }
}