Como criar uma API RESTful na plataforma Symfony 5 + API para um projeto MODX


Nesta lição, você aprenderá como criar rapidamente uma API RESTful para qualquer site em qualquer CMS, MODX é apenas um exemplo.


Para criar a API, usarei:



O resultado está aqui:
https://github.com/andchir/modx2-api


Fiz tudo descrito no Linux, mas acho que no Windows a diferença de comandos não será grande. Eu pré-instalei o Composer e o utilitário Symfony .


Criando um projeto e classes de usuário


Eu crio um projeto:


composer create-project symfony/skeleton modx2-api 

Instale os pacotes necessários para criar a API:


 cd modx2-api composer req api composer req migrations composer req form composer req maker --dev 

Eu inicio o servidor local.
Se o utilitário Symfony estiver instalado:


 symfony server:start 

ou mais:


 php -S 127.0.0.1:8000 -t public 

Abro o endereço no navegador para verificar se tudo funciona:
http://127.0.0.1:8000/


Abro o arquivo .env e edito a cadeia de conexão no banco de dados do projeto no MODX :


 DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name 

Agora você precisa criar um usuário e configurar o sistema de autorização por login e senha.


Instale pacotes adicionais:


 composer req jwt-auth composer req orm-fixtures --dev composer req profiler --dev 

Novas opções de pacote .jvt-authentication-bundle apareceram no arquivo .env .


Eu crio as classes de entidade e repositório (Doctrine ORM) do usuário:


 php bin/console make:user 

Dois arquivos apareceram:


 src/Entity/User.php src/Repository/UserRepository.php 

Eu crio a tabela "user" no banco de dados:


 bin/console doctrine:schema:create 

Eu configuro a autorização do usuário de acordo com as instruções:



Código do Controlador App \ Controller \ SecurityController
 <?php namespace App\Controller; use App\Entity\User; use App\Form\Type\LoginType; use App\Form\Type\UpdateProfileType; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; use Symfony\Component\Validator\Validator\ValidatorInterface; class SecurityController extends AbstractController { /** * @Route("/login", name="app_login") * @param AuthenticationUtils $authenticationUtils * @return Response */ public function loginAction(AuthenticationUtils $authenticationUtils): Response { if ($this->getUser()) { return $this->redirectToRoute('api_entrypoint'); } $form = $this->createForm(LoginType::class); $error = $authenticationUtils->getLastAuthenticationError(); $lastUsername = $authenticationUtils->getLastUsername(); return $this->render('security/login.html.twig', [ 'form' => $form->createView(), 'last_username' => $lastUsername, 'error' => $error ]); } } 

Eu gero uma classe para criar usuários:


 php bin/console make:fixtures 

Mais detalhes aqui: https://symfony.com/doc/current/security.html#a-create-your-user-class


Código de classe App \ DataFixtures \ UserFixtures
 <?php namespace App\DataFixtures; use App\Entity\User; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; class UserFixtures extends Fixture { private $passwordEncoder; public function __construct(UserPasswordEncoderInterface $passwordEncoder) { $this->passwordEncoder = $passwordEncoder; } public function load(ObjectManager $manager) { $user = new User(); $user ->setEmail('admin@admin.com') ->setRoles(['ROLE_USER', 'ROLE_ADMIN']); $user->setPassword($this->passwordEncoder->encodePassword( $user, 'admin'//  )); $manager->persist($user); $manager->flush(); } } 

Eu crio um administrador com o endereço de email "admin@admin.com" e a senha "admin" :


 php bin/console doctrine:fixtures:load --append --group=UserFixtures 

Mais tarde, esses dados podem ser alterados.


Eu gero as chaves na pasta config / jwt / :


 jwt_passhrase=$(grep ''^JWT_PASSPHRASE='' .env | cut -f 2 -d ''='') echo "$jwt_passhrase" | openssl genpkey -out config/jwt/private.pem -pass stdin -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096 echo "$jwt_passhrase" | openssl pkey -in config/jwt/private.pem -passin stdin -out config/jwt/public.pem -pubout setfacl -R -mu:www-data:rX -mu:"$(whoami)":rwX config/jwt setfacl -dR -mu:www-data:rX -mu:"$(whoami)":rwX config/jwt 

Verificando a criação do token:


 curl -X POST -H "Content-Type: application/json" http://localhost:8000/authentication_token -d '{"email":"admin@admin.com","password":"admin"}' 

Eu crio uma migração:


 php bin/console make:migration 

Agora a parte divertida.


API e geração de documentação


Eu gero classes de entidade para todas as tabelas do banco de dados:


 php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity 


Eu gero getters e setters para classes:


 php bin/console make:entity --regenerate App 

Abro o código de uma classe, por exemplo, src / Entity / ModxSiteContent.php . Adicione a anotação @ApiResource :


A API para ModxSiteContent está pronta.


Abro a página http: // localhost: 8000 / api



Pego o token, clique no botão "Autorizar", insira a linha com o token:


 Bearer MY_TOKEN 


Clico no botão "Experimente" e depois no botão "Executar" . Eu recebo este resultado:


Relacionamentos de tabela


Não descreverei como os filtros são criados para não duplicar a documentação , mas darei um exemplo de como você pode criar relacionamentos para tabelas, porque é um pouco mais complicado.


No caso do MODX, os dados do usuário são armazenados em uma tabela separada "user_attributes" . Por exemplo, preciso adicionar o email, nome, número de telefone etc. a uma amostra de usuários por solicitação GET. Abro o código de classe App \ Entity \ ModxUsers , adiciono a propriedade privada $attributes e descrevo a conexão com a classe App \ Entity \ ModxUserAttributes na anotação "@ORM \ OneToOne":


 /** * @var ModxUserAttributes * * @ORM\OneToOne(targetEntity="ModxUserAttributes", mappedBy="user") * @Groups({"read", "attributes"}) */ private $attributes; 

Novamente, adiciono os getters e setters ausentes:


 php bin/console make:entity --regenerate App\\Entity\\ModxUsers 

Observe que eu adicionei o grupo "atributos" à anotação @ApiResource


Imagem


Abro o código da classe App \ Entity \ ModxUserAttributes , adiciono a anotação @ApiResource e a conexão com a classe App\Entity\ModxUsers :


 /** * @var ModxUsers * * @ORM\OneToOne(targetEntity="ModxUsers", mappedBy="attributes") * @ORM\JoinColumn(name="internalKey", referencedColumnName="id") */ private $user; 

Para todas as propriedades que precisam ser adicionadas à seleção, insiro a anotação @Groups({"attributes"}) .


Imagem


Resultado:


Como resultado, para autorização no seu aplicativo, primeiro é necessário enviar um login (email) e uma senha para o URL "/ authentication_token" , obter um token e depois enviar esse token em cada solicitação no cabeçalho "Authorization" :


Se o projeto https://github.com/andchir/modx2-api for interessante para os usuários, ele será desenvolvido. Eu também estou esperando PR de todos que querem ajudar.

Source: https://habr.com/ru/post/pt479168/


All Articles