Categories


Archives


Recent Posts


Categories


Magento 2: Understanding the Web API Architecture

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Another high level first pass at an important topic for Magento 2 developers. Corrections and clarifications are more than welcome.

Magento 2, like Magento 1, has a “web” API. This has nothing to do with the @api notation on classes, methods, and interfaces. The Web API is a way for programmers to programmatically interact with a single freestanding Magento instance without writing native Magento/PHP code and installing it into that freestanding service. To fully understand the Magento 2 API, it helps to understand the Magento 1 API.

Magento 1 API Overview

Magento 1 initially shipped with a SOAP and XML-RPC based API. Later versions of Magento 1 introduced a REST API, although this REST API had less business logic functionality than the XML-RPC and SOAP APIs, and never gained wide adoption. The Magento 1 API, in addition to providing a standard way to interact with a single freestanding Magento instance, also contained important, stable business logic for performing certain actions that required access to several CRUD operations. As mentioned, the REST API did not hook into the same business logic routines as the SOAP and XML-RPC.

Authenticating a Magento 1 SOAP/XML-RPC API request required a username and passphrase created for an API user. For authorization, this API user could be assigned roles that were roughly analogous with the Magento admin user ACL roles.

Authenticating a Magento 1 REST API request involved an oAuth (or oAuth-ish) token request process. Authorization required a separate assignment of roles that were separate from the Magento 1 SOAP/XML-RPC API. Again, limited business logic, poor documentation, and poor evangelism around this feature left a lot of the inner workings of the Magento 1 REST API unknown even to the most experienced of Magento developers.

Magento 2 API Overview

Magento 2 ships with a SOAP and REST based API. There is no longer an XML-RPC based API. The SOAP and REST based APIs are, from a business logic point of view, equivalent. In addition to providing a method for programmers to programmatically interact with a single freestanding Magento instance without writing native Magento/PHP code, the Magento 2 REST API is also designed to allows browser based, client side javascript code access to API calls.

The Magento 2 SOAP and REST APIs are versioned. This implies, but does not guarantee, that old API calls will continue to work identically in future versions of Magento. If new functionality is needed, the API call will be presumably versioned. Since Magento 2 is such a young platform, it’s hard to know how stable the business logic in these methods will remain.

The Magento 2 SOAP API no longer has a single WSDL. Instead, individual API objects/services each have their own WSDL. You can see a list of these on the Magento dev docs site.

Authentication and Authorization

Authentication (logging in to the API) is a tricky topic to cover. To log in to the API, you need to make a request to a token API endpoint. For SOAP services this is the integrationAdminTokenServiceV1 or integrationCustomerTokenServiceV1 endpoint. For the REST service this is the V1/integration/customer/token or V1/integration/admin/token endpoint. When you make these API calls, you include a username and password as parameters. This username and password is either a Magento customer username and password, or a Magento admin user username and password. These API calls will return a token. You use this token to authenticate and authorize against an API method with an Authorization: Bearer --- header.

Authorization (which ACL protected methods you can access) is tied directly to the user you requested a token as. i.e. you get a token with an admin user, you get that admin user’s ACL rules. Unlike Magento 1, there are not API specific ACLs. These are the same ACL rules as a regular admin user.

If you get a token with a customer username/password, you can only access API methods with <resource ref="self"></resource> or <resource ref="anonymous"></resource>. The <resource ref="anonymous"></resource> methods can be called without any authorization.

The Magento dev docs site has some good code samples of this token requesting.

Session Based Authentication

In addition to token based API requests, Magento can also authenticate using the current browser session. This (obviously) only works if you’re in a browser.

For example, if you make a request to the following URL while logged in

http://magento.example.com/index.php/rest/V1/customers/me

you can access the currently logged in user’s information. You can do this with any API endpoint with a <resource ref="self"></resource>.

<route url="/V1/customers/me" method="GET"><service class="MagentoCustomerApiCustomerRepositoryInterface" method="getById"></service><resources><resource ref="self"></resource></resources><data><parameter name="customerId" force="true">%customer_id%</parameter></data></route>

Notice that me is not actually a parameter, it’s just part of the endpoint name.

Session based authentication is useful when creating rich javascript applications that need to access a user’s information. Its not clear if this session based authentication extends to SOAP calls made from browsers, but if you’re using a Javascript based SOAP client we’ll assume you know what you’re doing (or that you’re a wild and crazy programmer and we’re backing away).

These session based authentication endpoints seem limited to customer accounts. i.e. there are no endpoints related to admin users.

oAuth

There is also code for oAuth based authentication and authorization – although it’s not 100% clear how all this works. Internally, Magento has the concept of something called an integration. You can create integrations in the backend at System -> Integrations.

An integration appears to allow Magento administrators or extension programmers add an oAuth endpoint to Magento. That is, if you wanted to create a Magento feature or application that used oAuth, you would need to create an integration. This would create the oAuth endpoint that oAuth clients could hit.

Update: The above is incorrect. Integrations allow a store owner to create a special “integration user” for a third party service. This integration user makes API requests using oAuth. Full details are here.

Each integration has a set of ACL permissions associated with it. When oAuth clients make API requests they include the standard oAuth token headers, and will have access to any method associated with the integration’s set of oAuth permissions.

Magento 2 API Code Points

Every Magento API call/request runs through a standard Magento controller. There are separate controllers for REST and SOAP requests.

REST: vendor/magento/module-webapi/Controller/Rest.php
SOAP: vendor/magento/module-webapi/Controller/Soap.php

Each of these controllers is responsible for examining the request, and determining which PHP object and method Magento should call to handle the request. The REST controller does this directly. The SOAP controller hands this responsibility off to a “SOAP Server” object. This object should be familiar to Magento 1 programmers.

A Magento 2 SOAP server users a Soap Server Factory object to create a different SOAP Server object. (Welcome to corporate OOP)

#File: vendor/magento/module-webapi/Model/Soap/Server.php
public function handle()
{
    $rawRequestBody = file_get_contents('php://input');
    // $this->_checkRequest($rawRequestBody);
    $options = ['encoding' => $this->getApiCharset(), 'soap_version' => SOAP_1_2];
    $soapServer = $this->_soapServerFactory->create($this->generateUri(true), $options);
    $soapServer->handle($rawRequestBody);
}    

If you examine this factory’s create method

#File: vendor/magento/module-webapi/Model/Soap/ServerFactory.php    
public function create($url, $options)
{
    $soapServer = $this->_objectManager->create('SoapServer', ['wsdl' => $url, 'options' => $options]);
    $soapServer->setObject($this->_soapHandler);
    return $soapServer;
}

You’ll see its creating a native, PHP SoapServer object. This code uses a Magento object manager rather than a new keyword. If you’re familiar with PHP’s SoapServer, you know you provide it with a handler object. Magento’s handler class/object is a MagentoWebapiControllerSoapRequestHandler, located at

vendor/magento/module-webapi/Controller/Soap/Request/Handler.php

This is the object that, during a SOAP API request, examines the request and determines which PHP object and method Magento should call.

To determine which PHP class and object Magento should call to handle an API request, the above objects examine a merged webapi.xml tree.

vendor/magento/module-backend/etc/webapi.xml
vendor/magento/module-bundle/etc/webapi.xml
vendor/magento/module-catalog/etc/webapi.xml
vendor/magento/module-catalog-inventory/etc/webapi.xml
vendor/magento/module-checkout/etc/webapi.xml
vendor/magento/module-checkout-agreements/etc/webapi.xml
vendor/magento/module-cms/etc/webapi.xml
vendor/magento/module-configurable-product/etc/webapi.xml
vendor/magento/module-customer/etc/webapi.xml
vendor/magento/module-directory/etc/webapi.xml
vendor/magento/module-downloadable/etc/webapi.xml
vendor/magento/module-eav/etc/webapi.xml
vendor/magento/module-gift-message/etc/webapi.xml
vendor/magento/module-integration/etc/webapi.xml
vendor/magento/module-quote/etc/webapi.xml
vendor/magento/module-sales/etc/webapi.xml
vendor/magento/module-sales-rule/etc/webapi.xml
vendor/magento/module-search/etc/webapi.xml
vendor/magento/module-store/etc/webapi.xml
vendor/magento/module-tax/etc/webapi.xml

A sample of a configuration from one of these files

<route url="/V1/taxRates/:rateId" method="GET"><service class="MagentoTaxApiTaxRateRepositoryInterface" method="get"></service><resources><resource ref="Magento_Tax::manage_tax"></resource></resources></route>

As you can see, these configuration files are biased towards a RESTFul view of the universe – defining the HTTP route of a method (/V1/taxRates/:rateId), the HTTP method a REST request should use (method="GET"), the PHP class (MagentoTaxApiTaxRateRepositoryInterface), and PHP method (method="get") Magento should use to handle the request. Beware of confusing the HTTP method and the PHP method. They’re sometimes the same word!

Since the configuration files are biased towards a RESTFul version of the universe, Magento uses a MagentoWebapiModelServiceMetadata object to transform the configuration into information the SOAP handler object can use to match up a SOAP service with the PHP class and method.

vendor/magento/module-webapi/Model/ServiceMetadata.php

The resources defined in the webapi.xml resources are standard Magento ACL resource classes, and define who can access each method.

You’ll also notice the service class defined in this specific case is a PHP interface. This is a Magento Object Manager type, which is linked up with a concrete class in the di.xml tree with a class preference

$ find . -name di.xml | xargs grep TaxRateRepositoryInterface
./vendor/magento/module-tax/etc/di.xml:    <preference for="MagentoTaxApiTaxRateRepositoryInterface" type="MagentoTaxModelCalculationRateRepository"></preference>

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 31st March 2016