API REST Magento 2 utilisant un module simple comme exemple

Je vous souhaite la bienvenue, chers Habravites! Depuis que je développe sur la plate-forme de commerce électronique Magento depuis 2013, ayant acquis du courage et croyant que dans ce domaine je peux m'appeler, au moins, un développeur confiant, j'ai décidé d'écrire mon premier article sur le hub à propos de ce système. Et je vais commencer par l'implémentation de l'API REST dans Magento 2. Ici, hors de la boîte il y a des fonctionnalités pour le traitement des demandes et je vais essayer de le démontrer en utilisant un exemple d'un module simple. Cet article est plus destiné à ceux qui ont déjà travaillé avec Magenta. Et donc, qui sont intéressés, s'il vous plaît, sous le chat.

Cravate


Mon imagination est très mauvaise, j'ai donc donné l'exemple suivant: imaginez que nous devons mettre en place un blog, seuls les utilisateurs du panneau d'administration peuvent écrire des articles. De temps en temps, certains CRM nous frappent et téléchargent ces articles à eux-mêmes (pourquoi ce n'est pas clair, mais c'est ainsi que nous justifierons l'utilisation de l'API REST). Pour simplifier le module, j'ai spécifiquement omis l'implémentation de l'affichage des articles sur le frontend et dans le panneau d'administration (vous pouvez l'implémenter vous-même, je recommande un bon article sur les grilles). Seule la fonctionnalité de traitement des requêtes sera affectée ici.

Développement d'actions


Tout d'abord, créez la structure du module, appelons-le AlexPoletaev_Blog (le manque d'imagination n'a pas disparu). Nous plaçons le module dans le répertoire app / code .

AlexPoletaev / Blog / etc / module.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="AlexPoletaev_Blog" setup_version="1.0.0"/> </config> 


AlexPoletaev / Blog / registration.php
 <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'AlexPoletaev_Blog', __DIR__ ); 


Ces deux fichiers sont le minimum requis pour le module.

Si tout est fait en Feng Shui, alors nous devons créer des contrats de service (ce que c'est dans le Magenta et comment cela fonctionne, vous pouvez lire ici et ici ), ce que nous ferons:

AlexPoletaev / Blog / Api / Data / PostInterface.php
 <?php namespace AlexPoletaev\Blog\Api\Data; /** * Interface PostInterface * @package AlexPoletaev\Api\Data * @api */ interface PostInterface { /**#@+ * Constants * @var string */ const ID = 'id'; const AUTHOR_ID = 'author_id'; const TITLE = 'title'; const CONTENT = 'content'; const CREATED_AT = 'created_at'; const UPDATED_AT = 'updated_at'; /**#@-*/ /** * @return int */ public function getId(); /** * @param int $id * @return $this */ public function setId($id); /** * @return int */ public function getAuthorId(); /** * @param int $authorId * @return $this */ public function setAuthorId($authorId); /** * @return string */ public function getTitle(); /** * @param string $title * @return $this */ public function setTitle(string $title); /** * @return string */ public function getContent(); /** * @param string $content * @return $this */ public function setContent(string $content); /** * @return string */ public function getCreatedAt(); /** * @param string $createdAt * @return $this */ public function setCreatedAt(string $createdAt); /** * @return string */ public function getUpdatedAt(); /** * @param string $updatedAt * @return $this */ public function setUpdatedAt(string $updatedAt); } 


AlexPoletaev / Blog / Api / PostRepositoryInterface.php
 <?php namespace AlexPoletaev\Blog\Api; use AlexPoletaev\Blog\Api\Data\PostInterface; use Magento\Framework\Api\SearchCriteriaInterface; /** * Interface PostRepositoryInterface * @package AlexPoletaev\Api * @api */ interface PostRepositoryInterface { /** * @param int $id * @return \AlexPoletaev\Blog\Api\Data\PostInterface */ public function get(int $id); /** * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria * @return \AlexPoletaev\Blog\Api\Data\PostSearchResultInterface */ public function getList(SearchCriteriaInterface $searchCriteria); /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return \AlexPoletaev\Blog\Api\Data\PostInterface */ public function save(PostInterface $post); /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return bool */ public function delete(PostInterface $post); /** * @param int $id * @return bool */ public function deleteById(int $id); } 


Analysons ces deux interfaces plus en détail. L'interface PostInterface affiche un tableau avec des articles de notre blog. Créez un tableau ci-dessous. Chaque colonne de la base de données doit avoir son propre getter et setter dans cette interface, nous verrons pourquoi cela est important plus tard. L'interface PostRepositoryInterface fournit un ensemble standard de méthodes pour interagir avec la base de données et stocker les entités chargées dans le cache. Les mêmes méthodes sont utilisées pour l'API. Autre remarque importante, la présence de PHPDocs corrects dans ces interfaces est requise , car Magenta, lors du traitement d'une demande REST, utilise la réflexion pour déterminer les paramètres d'entrée et renvoyer des valeurs dans les méthodes.

À l'aide du script d'installation, créez un tableau où seront stockées les publications du blog:

AlexPoletaev / Blog / Setup / InstallSchema.php
 <?php namespace AlexPoletaev\Blog\Setup; use AlexPoletaev\Blog\Api\Data\PostInterface; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\Setup\InstallSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; use Magento\Security\Setup\InstallSchema as SecurityInstallSchema; /** * Class InstallSchema * @package AlexPoletaev\Blog\Setup */ class InstallSchema implements InstallSchemaInterface { /** * Installs DB schema for a module * * @param SchemaSetupInterface $setup * @param ModuleContextInterface $context * @return void */ public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $table = $setup->getConnection() ->newTable( $setup->getTable(PostResource::TABLE_NAME) ) ->addColumn( PostInterface::ID, Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 'Post ID' ) ->addColumn( PostInterface::AUTHOR_ID, Table::TYPE_INTEGER, null, ['unsigned' => true, 'nullable' => true,], 'Author ID' ) ->addColumn( PostInterface::TITLE, Table::TYPE_TEXT, 255, [], 'Title' ) ->addColumn( PostInterface::CONTENT, Table::TYPE_TEXT, null, [], 'Content' ) ->addColumn( 'created_at', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT], 'Creation Time' ) ->addColumn( 'updated_at', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT_UPDATE], 'Update Time' ) ->addForeignKey( $setup->getFkName( PostResource::TABLE_NAME, PostInterface::AUTHOR_ID, SecurityInstallSchema::ADMIN_USER_DB_TABLE_NAME, 'user_id' ), PostInterface::AUTHOR_ID, $setup->getTable(SecurityInstallSchema::ADMIN_USER_DB_TABLE_NAME), 'user_id', Table::ACTION_SET_NULL ) ->addIndex( $setup->getIdxName( PostResource::TABLE_NAME, [PostInterface::AUTHOR_ID], AdapterInterface::INDEX_TYPE_INDEX ), [PostInterface::AUTHOR_ID], ['type' => AdapterInterface::INDEX_TYPE_INDEX] ) ->setComment('Posts') ; $setup->getConnection()->createTable($table); $setup->endSetup(); } } 


Le tableau aura les colonnes suivantes (n'oubliez pas, nous avons tout aussi simple que possible):

  • id - incrémentation automatique
  • author_id - identifiant utilisateur admin (clé étrangère dans le champ user_id de la table admin_user)
  • titre - titre
  • contenu - texte de l'article
  • created_at - date de création
  • updated_at - modifier la date

Vous devez maintenant créer un ensemble standard de classes Magenta Model , ResourceModel et Collection . Pourquoi je ne peindrai pas ces classes, ce sujet est vaste et dépasse le cadre de cet article, qui sont intéressés, peuvent google par eux-mêmes. En résumé, ces classes sont nécessaires pour manipuler des entités (articles) à partir de la base de données. Je vous conseille de lire sur les modèles de modèle de domaine, de référentiel et de couche de service.

AlexPoletaev / Blog / Modèle / Post.php
 <?php namespace AlexPoletaev\Blog\Model; use AlexPoletaev\Blog\Api\Data\PostInterface; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\Model\AbstractModel; /** * Class Post * @package AlexPoletaev\Blog\Model */ class Post extends AbstractModel implements PostInterface { /** * @var string */ protected $_idFieldName = PostInterface::ID; //@codingStandardsIgnoreLine /** * @inheritdoc */ protected function _construct() //@codingStandardsIgnoreLine { $this->_init(PostResource::class); } /** * @return int */ public function getAuthorId() { return $this->getData(PostInterface::AUTHOR_ID); } /** * @param int $authorId * @return $this */ public function setAuthorId($authorId) { $this->setData(PostInterface::AUTHOR_ID, $authorId); return $this; } /** * @return string */ public function getTitle() { return $this->getData(PostInterface::TITLE); } /** * @param string $title * @return $this */ public function setTitle(string $title) { $this->setData(PostInterface::TITLE, $title); return $this; } /** * @return string */ public function getContent() { return $this->getData(PostInterface::CONTENT); } /** * @param string $content * @return $this */ public function setContent(string $content) { $this->setData(PostInterface::CONTENT, $content); return $this; } /** * @return string */ public function getCreatedAt() { return $this->getData(PostInterface::CREATED_AT); } /** * @param string $createdAt * @return $this */ public function setCreatedAt(string $createdAt) { $this->setData(PostInterface::CREATED_AT, $createdAt); return $this; } /** * @return string */ public function getUpdatedAt() { return $this->getData(PostInterface::UPDATED_AT); } /** * @param string $updatedAt * @return $this */ public function setUpdatedAt(string $updatedAt) { $this->setData(PostInterface::UPDATED_AT, $updatedAt); return $this; } } 


AlexPoletaev / Blog / Modèle / ResourceModel / Post.php
 <?php namespace AlexPoletaev\Blog\Model\ResourceModel; use AlexPoletaev\Blog\Api\Data\PostInterface; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; /** * Class Post * @package AlexPoletaev\Blog\Model\ResourceModel */ class Post extends AbstractDb { /** * @var string */ const TABLE_NAME = 'alex_poletaev_blog_post'; /** * Resource initialization * * @return void */ protected function _construct() //@codingStandardsIgnoreLine { $this->_init(self::TABLE_NAME, PostInterface::ID); } } 


AlexPoletaev / Blog / Model / ResourceModel / Post / Collection.php
 <?php namespace AlexPoletaev\Blog\Model\ResourceModel\Post; use AlexPoletaev\Blog\Model\Post; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; /** * Class Collection * @package AlexPoletaev\Blog\Model\ResourceModel\Post */ class Collection extends AbstractCollection { /** * @inheritdoc */ protected function _construct() //@codingStandardsIgnoreLine { $this->_init(Post::class, PostResource::class); } } 


Un lecteur attentif remarquera que notre modèle implémente l'interface précédemment créée et tous ses getters et setters.

Dans le même temps, nous implémentons le référentiel et ses méthodes:

AlexPoletaev / Blog / Model / PostRepository.php
 <?php namespace AlexPoletaev\Blog\Model; use AlexPoletaev\Blog\Api\Data\PostInterface; use AlexPoletaev\Blog\Api\Data\PostSearchResultInterface; use AlexPoletaev\Blog\Api\Data\PostSearchResultInterfaceFactory; use AlexPoletaev\Blog\Api\PostRepositoryInterface; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use AlexPoletaev\Blog\Model\ResourceModel\Post\Collection as PostCollection; use AlexPoletaev\Blog\Model\ResourceModel\Post\CollectionFactory as PostCollectionFactory; use AlexPoletaev\Blog\Model\PostFactory; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; /** * Class PostRepository * @package AlexPoletaev\Blog\Model */ class PostRepository implements PostRepositoryInterface { /** * @var array */ private $registry = []; /** * @var PostResource */ private $postResource; /** * @var PostFactory */ private $postFactory; /** * @var PostCollectionFactory */ private $postCollectionFactory; /** * @var PostSearchResultInterfaceFactory */ private $postSearchResultFactory; /** * @param PostResource $postResource * @param PostFactory $postFactory * @param PostCollectionFactory $postCollectionFactory * @param PostSearchResultInterfaceFactory $postSearchResultFactory */ public function __construct( PostResource $postResource, PostFactory $postFactory, PostCollectionFactory $postCollectionFactory, PostSearchResultInterfaceFactory $postSearchResultFactory ) { $this->postResource = $postResource; $this->postFactory = $postFactory; $this->postCollectionFactory = $postCollectionFactory; $this->postSearchResultFactory = $postSearchResultFactory; } /** * @param int $id * @return PostInterface * @throws NoSuchEntityException */ public function get(int $id) { if (!array_key_exists($id, $this->registry)) { $post = $this->postFactory->create(); $this->postResource->load($post, $id); if (!$post->getId()) { throw new NoSuchEntityException(__('Requested post does not exist')); } $this->registry[$id] = $post; } return $this->registry[$id]; } /** * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria * @return \AlexPoletaev\Blog\Api\Data\PostSearchResultInterface */ public function getList(SearchCriteriaInterface $searchCriteria) { /** @var PostCollection $collection */ $collection = $this->postCollectionFactory->create(); foreach ($searchCriteria->getFilterGroups() as $filterGroup) { foreach ($filterGroup->getFilters() as $filter) { $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq'; $collection->addFieldToFilter($filter->getField(), [$condition => $filter->getValue()]); } } /** @var PostSearchResultInterface $searchResult */ $searchResult = $this->postSearchResultFactory->create(); $searchResult->setSearchCriteria($searchCriteria); $searchResult->setItems($collection->getItems()); $searchResult->setTotalCount($collection->getSize()); return $searchResult; } /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return PostInterface * @throws StateException */ public function save(PostInterface $post) { try { /** @var Post $post */ $this->postResource->save($post); $this->registry[$post->getId()] = $this->get($post->getId()); } catch (\Exception $exception) { throw new StateException(__('Unable to save post #%1', $post->getId())); } return $this->registry[$post->getId()]; } /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface $post * @return bool * @throws StateException */ public function delete(PostInterface $post) { try { /** @var Post $post */ $this->postResource->delete($post); unset($this->registry[$post->getId()]); } catch (\Exception $e) { throw new StateException(__('Unable to remove post #%1', $post->getId())); } return true; } /** * @param int $id * @return bool */ public function deleteById(int $id) { return $this->delete($this->get($id)); } } 


La méthode \AlexPoletaev\Blog\Model\PostRepository::getList() devrait renvoyer des données d'un certain format, nous aurons donc également besoin de cette interface:

AlexPoletaev / Blog / Api / Data / PostSearchResultInterface.php
 <?php namespace AlexPoletaev\Blog\Api\Data; use Magento\Framework\Api\SearchResultsInterface; /** * Interface PostSearchResultInterface * @package AlexPoletaev\Blog\Api\Data */ interface PostSearchResultInterface extends SearchResultsInterface { /** * @return \AlexPoletaev\Blog\Api\Data\PostInterface[] */ public function getItems(); /** * @param \AlexPoletaev\Blog\Api\Data\PostInterface[] $items * @return $this */ public function setItems(array $items); } 


Pour faciliter le test de notre module, nous allons créer deux scripts de console qui ajoutent et suppriment des données de test du tableau:

AlexPoletaev / Blog / Console / Command / DeploySampleDataCommand.php
 <?php namespace AlexPoletaev\Blog\Console\Command; use AlexPoletaev\Blog\Api\PostRepositoryInterface; use AlexPoletaev\Blog\Model\Post; use AlexPoletaev\Blog\Model\PostFactory; use Magento\User\Api\Data\UserInterface; use Magento\User\Model\User; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Class DeploySampleDataCommand * @package AlexPoletaev\Blog\Console\Command */ class DeploySampleDataCommand extends Command { /**#@+ * @var string */ const ARGUMENT_USERNAME = 'username'; const ARGUMENT_NUMBER_OF_RECORDS = 'number_of_records'; /**#@-*/ /** * @var PostFactory */ private $postFactory; /** * @var PostRepositoryInterface */ private $postRepository; /** * @var UserInterface */ private $user; /** * @param PostFactory $postFactory * @param PostRepositoryInterface $postRepository * @param UserInterface $user */ public function __construct( PostFactory $postFactory, PostRepositoryInterface $postRepository, UserInterface $user ) { parent::__construct(); $this->postFactory = $postFactory; $this->postRepository = $postRepository; $this->user = $user; } /** * @inheritdoc */ protected function configure() { $this->setName('alex_poletaev:blog:deploy_sample_data') ->setDescription('Blog: deploy sample data') ->setDefinition([ new InputArgument( self::ARGUMENT_USERNAME, InputArgument::REQUIRED, 'Username' ), new InputArgument( self::ARGUMENT_NUMBER_OF_RECORDS, InputArgument::OPTIONAL, 'Number of test records' ), ]) ; parent::configure(); } /** * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { $username = $input->getArgument(self::ARGUMENT_USERNAME); /** @var User $user */ $user = $this->user->loadByUsername($username); if (!$user->getId() && $output->getVerbosity() > 1) { $output->writeln('<error>User is not found</error>'); return null; } $records = $input->getArgument(self::ARGUMENT_NUMBER_OF_RECORDS) ?: 3; for ($i = 1; $i <= (int)$records; $i++) { /** @var Post $post */ $post = $this->postFactory->create(); $post->setAuthorId($user->getId()); $post->setTitle('test title ' . $i); $post->setContent('test content ' . $i); $this->postRepository->save($post); if ($output->getVerbosity() > 1) { $output->writeln('<info>Post with the ID #' . $post->getId() . ' has been created.</info>'); } } } } 


AlexPoletaev / Blog / Console / Command / RemoveSampleDataCommand.php
 <?php namespace AlexPoletaev\Blog\Console\Command; use AlexPoletaev\Blog\Model\ResourceModel\Post as PostResource; use Magento\Framework\App\ResourceConnection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Class RemoveSampleDataCommand * @package AlexPoletaev\Blog\Console\Command */ class RemoveSampleDataCommand extends Command { /** * @var ResourceConnection */ private $resourceConnection; /** * @param ResourceConnection $resourceConnection */ public function __construct( ResourceConnection $resourceConnection ) { parent::__construct(); $this->resourceConnection = $resourceConnection; } /** * @inheritdoc */ protected function configure() { $this->setName('alex_poletaev:blog:remove_sample_data') ->setDescription('Blog: remove sample data') ; parent::configure(); } /** * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { $connection = $this->resourceConnection->getConnection(); $connection->truncateTable($connection->getTableName(PostResource::TABLE_NAME)); if ($output->getVerbosity() > 1) { $output->writeln('<info>Sample data has been successfully removed.</info>'); } } } 


La principale caractéristique de Magento 2 est l'utilisation généralisée de sa propre implémentation de l' injection de dépendance . Pour que Magenta sache à quelle interface l'implémentation correspond, nous devons spécifier ces dépendances dans le fichier di.xml. Dans le même temps, nous enregistrerons les scripts de console nouvellement créés dans ce fichier:

AlexPoletaev / Blog / etc / di.xml
 <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="AlexPoletaev\Blog\Api\Data\PostInterface" type="AlexPoletaev\Blog\Model\Post"/> <preference for="AlexPoletaev\Blog\Api\PostRepositoryInterface" type="AlexPoletaev\Blog\Model\PostRepository"/> <preference for="AlexPoletaev\Blog\Api\Data\PostSearchResultInterface" type="Magento\Framework\Api\SearchResults" /> <type name="Magento\Framework\Console\CommandList"> <arguments> <argument name="commands" xsi:type="array"> <item name="deploy_sample_data" xsi:type="object">AlexPoletaev\Blog\Console\Command\DeploySampleDataCommand</item> <item name="remove_sample_data" xsi:type="object">AlexPoletaev\Blog\Console\Command\RemoveSampleDataCommand</item> </argument> </arguments> </type> </config> 


Enregistrez maintenant les routes pour l'API REST, cela se fait dans le fichier webapi.xml:

AlexPoletaev / Blog / etc / webapi.xml
 <?xml version="1.0"?> <routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd"> <route url="/V1/blog/posts" method="POST"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="save"/> <resources> <resource ref="anonymous"/> </resources> </route> <route url="/V1/blog/posts/:id" method="DELETE"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="deleteById"/> <resources> <resource ref="anonymous"/> </resources> </route> <route url="/V1/blog/posts/:id" method="GET"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="get"/> <resources> <resource ref="anonymous"/> </resources> </route> <route url="/V1/blog/posts" method="GET"> <service class="AlexPoletaev\Blog\Api\PostRepositoryInterface" method="getList"/> <resources> <resource ref="anonymous"/> </resources> </route> </routes> 


Ici, nous indiquons à Magente quelle interface et quelle méthode de cette interface utiliser lors de la demande d'une URL spécifique et avec une méthode http spécifique (POST, GET, etc.). De plus, afin de simplifier, une ressource anonymous est utilisée, ce qui permet à quiconque de frapper notre API, sinon vous devez configurer les droits d'accès (ACL).

Climax


Toutes les autres étapes supposent que le mode développeur est activé. Cela évite les manipulations inutiles avec le déploiement de statiques de contenu et la compilation DI.

Enregistrez notre nouveau module, exécutez la commande: php bin/magento setup:upgrade .

Vérifiez qu'une nouvelle table alex_poletaev_blog_post a été créée .

Ensuite, chargez les données de test à l'aide de notre script personnalisé:

 php bin/magento -v alex_poletaev:blog:deploy_sample_data admin 

Le paramètre admin dans ce script est le nom d' utilisateur de la table admin_user (il peut différer pour vous), en un mot, l'utilisateur du panneau d'administration, qui sera écrit dans la colonne author_id.

Vous pouvez maintenant commencer les tests. Pour les tests, j'ai utilisé Magento 2.2.4, domaine http://m224ce.local/ .

Une façon de tester l'API REST consiste à ouvrir http://m224ce.local/swagger et à utiliser la fonctionnalité de swagger, mais n'oubliez pas que la méthode getList n'y fonctionne pas correctement. J'ai également testé toutes les méthodes avec curl, exemples:

Obtenez un article avec id = 2

 curl -X GET -H "Accept: application/json" "http://m224ce.local/rest/all/V1/blog/posts/2" 

La réponse est:

 {"id":2,"author_id":1,"title":"test title 2","content":"test content 2","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"} 

Obtenez une liste d'articles avec author_id = 2

 curl -g -X GET -H "Accept: application/json" "http://m224ce.local/rest/all/V1/blog/posts?searchCriteria[filterGroups][0][filters][0][field]=author_id&searchCriteria[filterGroups][0][filters][0][value]=1&searchCriteria[filterGroups][0][filters][0][conditionType]=eq" 

La réponse est:

 {"items":[{"id":1,"author_id":1,"title":"test title 1","content":"test content 1","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"},{"id":2,"author_id":1,"title":"test title 2","content":"test content 2","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"},{"id":3,"author_id":1,"title":"test title 3","content":"test content 3","created_at":"2018-06-06 21:35:54","updated_at":"2018-06-06 21:35:54"}],"search_criteria":{"filter_groups":[{"filters":[{"field":"author_id","value":"1","condition_type":"eq"}]}]},"total_count":3} 

Supprimer l'article avec id = 3

 curl -X DELETE -H "Accept: application/json" "http://m224ce.local/rest/all/V1/blog/posts/3" 

La réponse est:

 true 

Enregistrez le nouvel article

 curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d '{"post": {"author_id": 1, "title": "test title 4", "content": "test content 4"}}' "http://m224ce.local/rest/all/V1/blog/posts" 

La réponse est:

 {"id":4,"author_id":1,"title":"test title 4","content":"test content 4","created_at":"2018-06-06 21:44:24","updated_at":"2018-06-06 21:44:24"} 

Veuillez noter que pour une demande avec la méthode http POST, vous devez transmettre la clé de publication , qui correspond en fait au paramètre d'entrée ($ post) pour la méthode

 \AlexPoletaev\Blog\Api\PostRepositoryInterface::save() 

Dénouement


Pour ceux qui sont intéressés par ce qui se passe pendant la demande et comment Magenta la traite, je donnerai ci-dessous quelques liens vers les méthodes avec mes commentaires. Si quelque chose ne fonctionne pas, ces méthodes doivent d'abord être débitées.

Le responsable du traitement de la demande
\ Magento \ Webapi \ Controller \ Rest :: dispatch ()

Appelé ensuite
\ Magento \ Webapi \ Controller \ Rest :: processApiRequest ()

De nombreuses autres méthodes sont appelées dans processApiRequest , mais la deuxième plus importante
\ Magento \ Webapi \ Controller \ Rest \ InputParamsResolver :: resol ()

\ Magento \ Webapi \ Controller \ Rest \ Router :: match () - un itinéraire spécifique est déterminé (à l'intérieur, via la \Magento\Webapi\Model\Rest\Config::getRestRoutes() , tous les itinéraires appropriés sont extraits de la demande de la demande). L'objet route contient toutes les données nécessaires pour traiter la demande - classe, méthode, droits d'accès, etc.

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: process ()
- utilise \Magento\Framework\Reflection\MethodsMap::getMethodParams() , où les paramètres de méthode sont extraits par réflexion

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: convertValue () - plusieurs options pour convertir un tableau en DataObject ou en tableau à partir d'un DataObject

\ Magento \ Framework \ Webapi \ ServiceInputProcessor :: _ createFromArray () - conversion directe, où à travers la réflexion la présence des getters et setters est vérifiée (rappelez-vous, j'ai dit plus haut que nous y reviendrons?) Et qu'ils ont une portée publique. Ensuite, l'objet est rempli de données via les setters.

À la toute fin, dans la méthode
\ Magento \ Webapi \ Controller \ Rest :: processApiRequest () , via call_user_func_array méthode call_user_func_array méthode de l'objet de référentiel est appelée.

Épilogue


Dépôt de modules Github

Il existe deux façons d'installer:

1) Via le compositeur. Pour ce faire, ajoutez l'objet suivant au tableau de repositories dans le fichier composer.json

 { "type": "git", "url": "https://github.com/alexpoletaev/magento2-blog-demo" } 

Tapez ensuite la commande suivante dans le terminal:

 composer require alexpoletaev/magento2-blog-demo:dev-master 

2) Téléchargez les fichiers du module et copiez-les manuellement dans le répertoire app/code/AlexPoletaev/Blog

Quelle que soit la méthode que vous choisissez, à la fin, vous devez exécuter la mise à niveau:

 php bin/magento setup:upgrade 

J'espère que cet article sera utile à quelqu'un. Si vous avez des commentaires, des suggestions ou des questions, n'hésitez pas à commenter. Merci de votre attention.

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


All Articles