hirschen/rest

Installs: 153

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Forks: 0

Type:symfony-bundle

dev-master 2020-10-30 11:34 UTC

This package is not auto-updated.

Last update: 2024-04-23 14:24:14 UTC


README

This package provides functionality for Authentification(JWT), Serialization, Validation, Parameter Conversion etc. Additionally several constants, helper-classes and services are defined to support building a standardized Rest API. Exceptions are catched via a listener and serialized into a json response.

Configure Symfony Bundle

https://symfony.com/doc/current/bundles/best_practices.html

Learn more about Friends of Symfony

FOS User
https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/index.rst
FOS REST
https://symfony.com/doc/current/bundles/FOSRestBundle/index.html

Learn more about Lexik (JWT Management)

https://github.com/markitosgv/JWTRefreshTokenBundle

Installation

composer require hirschen/rest

Add bundle to bundles.php

<?php

return [
    ...
    Hirschen\Rest\HirschenRestBundle::class => ['all' => true],
    ...
];

Create private and public key and reference them in your .env

###> lexik/jwt-authentication-bundle ###
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Add refresh route to routes.yml

gesdinet_jwt_refresh_token:
  path:       /api/auth/refresh
  controller: gesdinet.jwtrefreshtoken::refresh

Add Hirschen/Rest serialization service to services.yml

    Hirschen\Rest\Service\ParamConverter\SerializerService:
        autowire: false
        public: true
        arguments:
            - "@fos_rest.serializer"
            - "@fos_rest.validator"
            - "validationErrors"
            - "@doctrine_mongodb.odm.document_manager"
            - '@Hirschen\Rest\Service\User\UserService'

In config/packages

In gesdinet_jwt_refresh_token.yaml

    gesdinet_jwt_refresh_token:
        user_provider: fos_user.user_provider.username_email
        object_manager: doctrine_mongodb.odm.document_manager
        ttl_update: true
        manager_type: mongodb
In lexik_jwt_authentication.yaml (Link env vars)
    lexik_jwt_authentication:
      secret_key:       '%env(resolve:JWT_SECRET_KEY)%' # required for token creation
      public_key:       '%env(resolve:JWT_PUBLIC_KEY)%'  # required for token verification
      pass_phrase:      '%env(resolve:JWT_PASSPHRASE)%' # required for token creation, usage of an environment variable is recommended
      token_ttl:        5184000 # 60 days
      user_identity_field: email

In the security.yaml

  • Add Encoders and Providers
  • Add guard for routes that need to be guarded
  • Add Login Route
security:
  encoders:
    FOS\UserBundle\Model\UserInterface: bcrypt

  providers:
    fos_userbundle:
      id: fos_user.user_provider.username_email

    ...
    ...

    api:
      pattern:   ^/api
      stateless: true
      provider: fos_userbundle
      guard:
        authenticators:
          - lexik_jwt_authentication.jwt_token_authenticator

    ...
    ...

    login:
      pattern: ^/api/login
      stateless: true
      anonymous: true
      logout: true
      provider: fos_userbundle
      form_login:
        check_path:               /api/login
        success_handler:          user.authentication_success_handler
        failure_handler:          lexik_jwt_authentication.handler.authentication_failure
        require_previous_session: false
        username_parameter: email
        password_parameter: password

Add exception controller in fos_rest.yaml

# Read the documentation: https://symfony.com/doc/master/bundles/FOSRestBundle/index.html
fos_rest:
  body_listener: true
  body_converter:
    enabled: true
    validate: true
    validation_errors_argument: validationErrors
  format_listener:
    rules:
      - { path: '^/', priorities: ['json'], fallback_format: json, prefer_extension: false }
  param_fetcher_listener: true
  exception:
    enabled: true
    exception_controller: 'Hirschen\Rest\Controller\ExceptionController::showAction'
  view:
    view_response_listener: 'force'
    formats:
      json: true

Validated Serialization and Paramconversion

Summary (How does it work)

  1. Json request is serialized into a PHP object
  2. The object is validated https://symfony.com/doc/current/validation.html#constraint-configuration
  3. If the object is an Document (ODM) and a primary key is set (id in most cases) proceed to 4. otherwise skip to 5.
  4. Fetch existing document from DB and sync it with given input. Pass the fetched (updated) document to 5.
  5. Add object to the arguments of the controller action

Following Annotations triggers the functionality above

use Hirschen\Rest\Annotation\Parameter;
...

class UserController extends BaseController
{

/**
 * @Rest\Post("/create", name="admin_user_create")
 * @Parameter("user", {"Group 1","Group 2"})
 */
 public function x(User $user...): Response
...

The first argument of the Parameter Annotation is required in order to map it to the arguments of the controller function. In this case, "user" is mapped to $user. The second argument is a string array containing the Groups necessary to determine the scope of the serialization and validation done by this package. By type-hinting the argument in the controller action the serializer recognizes the object type.

When the controller action starts, the json is already serialized and validated ($user). If $user is a new document, it is ready to be persisted. If it is an exisiting document, the old document was already fetched, updated and set to $user.

By tagging the atrributes of the objects or documents with groups, the Parameter Annotation can determine the right scope for serialization and custom validation.

    /**
     * @Assert\NotBlank(groups={"Group 2", "Group 3"})
     * @Groups({"Group 1","Group 2", "Group 3","Group 4" })
     * @Serializer\Type("string")
     */
    protected $attribute;