Table of Contents for
Magento 2 Development Quick Start Guide

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Magento 2 Development Quick Start Guide by Branko Ajzele Published by Packt Publishing, 2018
  1. Magento 2 Development Quick Start Guide
  2. Title Page
  3. Copyright and Credits
  4. Magento 2 Development Quick Start Guide
  5. Packt Upsell
  6. Why subscribe?
  7. Packt.com
  8. Contributors
  9. About the author
  10. About the reviewer
  11. Packt is searching for authors like you
  12. Table of Contents
  13. Preface
  14. Who this book is for
  15. What this book covers
  16. To get the most out of this book
  17. Download the example code files
  18. Code in Action
  19. Conventions used
  20. Get in touch
  21. Reviews
  22. Understanding the Magento Architecture
  23. Technical requirements
  24. Installing Magento
  25. Modes
  26. Areas
  27. Request flow processing
  28. Modules
  29. Creating the minimal module
  30. Cache
  31. Dependency injection
  32. Argument injection
  33. Virtual types
  34. Proxies
  35. Factories
  36. Plugins
  37. The before plugin
  38. The around plugin
  39. The after plugin
  40. Events and observers
  41. Console commands
  42. Cron jobs
  43. Summary
  44. Working with Entities
  45. Technical requirements
  46. Understanding types of models
  47. Creating a simple model
  48. Methods worth memorizing
  49. Working with setup scripts
  50. The InstallSchema script
  51. The UpgradeSchema script
  52. The Recurring script
  53. The InstallData script
  54. The UpgradeData script
  55. The RecurringData script
  56. Extending entities
  57. Creating extension attributes
  58. Summary
  59. Understanding Web APIs
  60. Technical requirements
  61. Types of users
  62. Types of authentication
  63. Types of APIs
  64. Using existing web APIs
  65. Creating custom web APIs
  66. Understanding search criteria
  67. Summary
  68. Building and Distributing Extensions
  69. Technical requirements
  70. Building a shipping extension
  71. Distributing via GitHub
  72. Distributing via Packagist
  73. Summary
  74. Developing for Admin
  75. Technical requirements
  76. Using the listing component
  77. Using the form component
  78. Summary
  79. Developing for Storefront
  80. Technical requirements
  81. Setting up the playground
  82. Calling and initializing JS components
  83. Meet RequireJS
  84. Replacing jQuery widget components
  85. Extending jQuery widget components
  86. Creating jQuery widgets components
  87. Creating UI/KnockoutJS components
  88. Extending UI/KnockoutJS components
  89. Summary
  90. Customizing Catalog Behavior
  91. Technical requirements
  92. Creating the size guide
  93. Creating the same day delivery
  94. Flagging new products
  95. Summary
  96. Customizing Checkout Experiences
  97. Technical requirements
  98. Passing data to the checkout
  99. Adding order notes to the checkout
  100. Summary
  101. Customizing Customer Interactions
  102. Technical requirements
  103. Understanding the section mechanism
  104. Adding contact preferences to customer accounts
  105. Adding contact preferences to the checkout
  106. Summary
  107. Other Books You May Enjoy
  108. Leave a review - let other readers know what you think

Using existing web APIs

The CRUD and search models of web APIs are implemented through a set of *RepositoryInterface interfaces, found in the <VendorName>/<ModuleName>/Api/<EntityName>RepositoryInterface.php files.

The majority of these repository interfaces define a specific set of common methods:

  • save
  • get
  • getById
  • getList
  • delete
  • deleteById

The data type that flows through these methods follows a certain pattern, where each entity passing through an API has a data interface defined in a <VendorName>/<ModuleName>/Api/Data/<EntityName>Interface.php file.

Let's take a closer look at <MAGENTO_DIR>/module-cms/Api/BlockRepositoryInterface.php:

interface BlockRepositoryInterface
{
public function save(
\Magento\Cms\Api\Data\BlockInterface $block
);

public function getById($blockId);

public function getList(
\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
);

public function delete(
\Magento\Cms\Api\Data\BlockInterface $block
);

public function deleteById($blockId);
}

The concrete implementations of repository interfaces can usually be found in the <VendorName>/<ModuleName>/Model/<EntityName>Repository.php or the <VendorName>/<ModuleName>/Model/ResourceModel/<EntityName>Repository.php files. The exact location is not that relevant, as webapi.xml should always use an interface for a class argument for its service element definition. The mapping between the interface and concrete implementation then happens in the module's di.xml file via a preference definition. From an integrator's point of view, using APIs does not require any knowledge of concrete implementations.

The PHPDoc @return tag is a requirement for every getter method on an API interface, otherwise, Each getter must have a doc block error is thrown.

The Swagger URL, http://magelicious.loc/swagger, will generate a Swagger UI interface, that allows us to visualize and interact with the API's resources:

By default, documentation returned here is limited to anonymous users only. Generating a valid API key, via the POST /V1/integration/customer/token or POST /V1/integration/admin/token will unlock the documentation for all the resources available to a given user. While Swagger certainly has its place in development workflows, oftentimes the Postman tool is a more robust solution for those working extensively with APIs.

Let's go ahead and CRUD our way through the cmsBlock interface, using REST endpoints:

  • save (create a new block) POST /V1/cmsBlock
  • save (update an existing block by id) PUT /V1/cmsBlock/:id
  • getById (get an existing block by id) GET /V1/cmsBlock/:blockId
  • deleteById (delete an existing block) DELETE /V1/cmsBlock/:blockId
  • getList (get an array of existing blocks) GET /V1/cmsBlock/search

We will be using the integrator type of user. This will be our Magento admin user, assigned either full resources, or at least the Resources | Content | Elements | Blocks resource under the Role Resource tab of the System | Permissions | User Roles | Edit | Add New Role screen.

We start with the admin login request, in order to obtain a token for later requests:

POST /index.php/rest/V1/integration/admin/token HTTP/1.1
Host: magelicious.loc
Content-Type: application/json
{
"username": "branko",
"password": "jrdJ%0i9a69n"
}

The successful JSON response should contain our API token, which we will be using for any subsequent API calls. The token itself is stored in the oauth_token table, under the token column. We further have consumer_id, admin_id, and customer_id columns in that table. These get filled depending on the user type we used to log in. Both consumer_id and admin_id are of the integrator type. These columns get filled accordingly depending on the user and authentication types used; as in customer versusĀ integrator, and token-based vs OAuth-based vs session-based authentication.

Now let's create a new block via POST /V1/cmsBlock; this triggers the save method:

POST /rest/V1/cmsBlock HTTP/1.1
Host: magelicious.loc
Content-Type: application/json
Authorization: Bearer 8pcvbwrp97l5m1pvcdnis6e3930n4rsj
{
"block": {
"identifier": "x-block",
"title": "The X Block",
"content": "<p>The <strong>X Block</strong> Content...</p>",
"active": true
}
}

The successful JSON response should return our newly created block:

{
"id": 1,
"identifier": "x-block",
"title": "The X Block",
"content": "<p>The <strong>X Block</strong> Content...</p>",
"active": true
}

Now let's update the existing cmsBlock via PUT /V1/cmsBlock/:id; this triggers the save method:

PUT /rest/V1/cmsBlock/1 HTTP/1.1
Host: magelicious.loc
Content-Type: application/json
Authorization: Bearer 8pcvbwrp97l5m1pvcdnis6e3930n4rsj
{
"block": {
"identifier": "y-block",
"title": "The Y Block",
"content": "<p>The <strong>Y Block</strong> Content...</p>",
"active": true
}
}

The successful JSON response should return the updated block:

{
"id": 1,
"identifier": "y-block",
"title": "The Y Block",
"content": "<p>The <strong>Y Block</strong> Content...</p>",
"active": true
}

Let's now fetch one of the existing blocks via GET /V1/cmsBlock/:blockId; this triggers the getById method:

GET /rest/V1/cmsBlock/1 HTTP/1.1
Host: magelicious.loc
Content-Type: application/json
Authorization: Bearer 8pcvbwrp97l5m1pvcdnis6e3930n4rsj

The successful JSON response is structurally identical to that of the save method.

Now, let's try deleting one of the blocks via DELETE /V1/cmsBlock/:blockId; this triggers the deleteById method:

DELETE /rest/V1/cmsBlock/2 HTTP/1.1
Host: magelicious.loc
Content-Type: application/json
Authorization: Bearer 8pcvbwrp97l5m1pvcdnis6e3930n4rsj

The successful JSON response returns a single true or false.

Finally, let's try fetching the list of blocks via GET /V1/cmsBlock/search; this triggers the getList method:

GET /rest/V1/cmsBlock/search?searchCriteria[filter_groups][0][filters][0][field]=title&amp;searchCriteria[filter_groups][0][filters][0][value]=%Block%&amp;searchCriteria[filter_groups][0][filters][0][condition_type]=like HTTP/1.1
Host: magelicious.loc
Content-Type: application/json
Authorization: Bearer 8pcvbwrp97l5m1pvcdnis6e3930n4rsj

Sadly, the GET request does not allow for the body, so ?searchCriteria... has to be passed via a URL.

The successful JSON response returns an object comprised of items, search_criteria, and total_count top-level keys:

{
"items": [
{
"id": 4,
"identifier": "x-block",
"title": "The X Block",
"content": "The <strong>X Block</strong> Content...",
"creation_time": "2018-06-23 07:30:06",
"update_time": "2018-06-23 07:30:06",
"active": true
},
{
"id": 5,
"identifier": "y-block",
"title": "The Y Block",
"content": "The <strong>Y Block</strong> Content...",
"creation_time": "2018-06-23 07:30:14",
"update_time": "2018-06-23 07:30:14",
"active": true
}
],
"search_criteria": {...},
"total_count": 2
}

We will address the search_criteria in more detail later on.