© 2016 Magento, Inc. Page | 1
API Design
Best practices
Igor Miniailo
Magento 2 Architect
© 2016 Magento, Inc. Page | 2
© 2016 Magento, Inc. Page | 3
© 2016 Magento, Inc. Page | 4
Why is API so crucial?
© 2016 Magento, Inc. Page | 5
© 2016 Magento, Inc. Page | 6
© 2016 Magento, Inc. Page | 7
© 2016 Magento, Inc. Page | 8
Semantic Versioning
Version numbers are in the format
MAJOR.MINOR.PATCH, where:
– MAJOR indicates incompatible API changes
– MINOR indicates backward-compatible
functionality has been added
– PATCH indicates backward-compatible bug
fixes
© 2016 Magento, Inc. Page | 9
The backward compatibility policy
applies to PHP code annotated with
@api
© 2016 Magento, Inc. Page | 10
Public and Private code
© 2016 Magento, Inc. Page | 11
Public vs Private code
Private code is not supposed to
be used by third party modules,
so, in most cases, its
modifications will only trigger
PATCH version bumps.
Changes in public code always
trigger MINOR or MAJOR
version bumps.
© 2016 Magento, Inc. Page | 12
What examples of Public code Magento has?
• PHP Interface (marked with @api)
• PHP Class (marked with @api)
• Javascript Interface (marked with @api)
• Javascript Class (marked with @api)
• Virtual Type (marked with @api)
• URL paths
• Console commands and their arguments
• Less Variables & Mixins
• Message queue topics and their data types
• UI component declarations
• Layout handles declared by modules
• Events triggered by component (both static dynamic)
• Schema of configuration types introduced by module
• Structure of System Configuration fields used by module
© 2016 Magento, Inc. Page | 13
API vs SPI (Extension Points)
A PHP Interface in Magento can be used several ways by the core
product and extension developers.
• As an API. is a set of interfaces and their
implementations that a module provides to other
modules
• As a Service Provider Interface (SPI). is a set of
interfaces that a module uses internally and allows their
implementation by other modules.
• As both. APIs and SPIs are not mutually exclusive.
© 2016 Magento, Inc. Page | 14
After the code is released, both API and SPI can
be evolved in a backwards-compatible way. But
both have their specific limitations.
© 2016 Magento, Inc. Page | 15
© 2016 Magento, Inc. Page | 16
© 2016 Magento, Inc. Page | 17
© 2016 Magento, Inc. Page | 18
© 2016 Magento, Inc. Page | 19
© 2016 Magento, Inc. Page | 20
We do not distinguish them separately.
SPIs are annotated the same as APIs.
© 2016 Magento, Inc. Page | 21
Who decides whether interface/class belong to API or SPI?
YOU
© 2016 Magento, Inc. Page | 22
Dependency Rules API
If a module uses (calls) an API, it should be dependent on the MAJOR
version.
API dependency example
{
...
"require": {
"magento/module-customer": "~100.0", // (>=100.0 <101.0.0)
},
...
}
© 2016 Magento, Inc. Page | 23
Dependency Rules SPI
If a module implements an API/SPI, it should be dependent on the
MAJOR+MINOR version.
SPI dependency example
{
...
"require": {
"magento/module-customer": "~100.0.0", // (>=100.0.0 <100.1.0)
},
...
}
© 2016 Magento, Inc. Page | 24
http://devdocs.magento.com/guides/v2.1/release-notes/backward-
incompatible-changes-2.1.html
© 2016 Magento, Inc. Page | 25
Prohibited Code Changes
© 2016 Magento, Inc. Page | 26
• Interface/class removal
• Public & protected method removal
• Introduction of a method to a class or
interface
PHP - Prohibited Code Changes
© 2016 Magento, Inc. Page | 27
MagentoCatalogApiCategoryRepositoryInterface
© 2016 Magento, Inc. Page | 28
MagentoCatalogApiCategoryListInterface
© 2016 Magento, Inc. Page | 29
PHP - Prohibited Code Changes
• Static function removal
• Parameter addition in public methods
• Parameter addition in protected
methods
© 2016 Magento, Inc. Page | 30
© 2016 Magento, Inc. Page | 31
PHP - Prohibited Code Changes
• Method argument type modification
• Modification of types of thrown
exceptions (unless a new exception is
a subtype of the old one)
• Constructor modification
© 2016 Magento, Inc. Page | 32
class ExistingClass
{
/**
* @var NewDependencyInterface $newDependency
*/
private $newDependency;
public function __construct(
OldDependencyIntreface $oldDependency,
$oldRequiredConstructorParameter,
$oldOptinalConstructorParameter = null,
NewDependencyInterface $newDependency = null
) {
...
$this>newDependency = $newDependency ?: MagentoFrameworkAppObjectManager::getInstance()
->get(NewDependencyInterface::class);
...
}
public function existingFunction() {
// Existing functionality
...
// Use $this->newDependency wherever the new dependency is needed
...
}
}
© 2016 Magento, Inc. Page | 33
PHP - Prohibited Code Changes
• Modifying the default values of
optional arguments in public and
protected methods
• Removing or renaming constants
© 2016 Magento, Inc. Page | 34
The main rule is that backwards compatibility
is more important than niceness and effort of
the implementation.
© 2016 Magento, Inc. Page | 35
Coupling Between Objects Reaches Its Limit with
a New Dependency
© 2016 Magento, Inc. Page | 36
We MUST do continuous Refactoring!
Backward Compatibility should not be an excuse
for not doing refactoring!
© 2016 Magento, Inc. Page | 37
Backward Compatible Fix
*it works (most of the time), but code quality
is far from good enough
© 2016 Magento, Inc. Page | 38
Good object oriented programming in the service layer is basically
functional programming:
• constructor injection
• immutable state
• single responsibility principle
• uniform interfaces
• value objects passed across services
Bringing these concepts to an extreme leads to single-method,
immutable objects.
© 2016 Magento, Inc. Page | 39
© 2016 Magento, Inc. Page | 40
Why execute but not __invoke?
© 2016 Magento, Inc. Page | 41
PHP 7
• Return Types
• Scalar Type hinting
© 2016 Magento, Inc. Page | 42
Repositories
In Magento 2 Repositories are considered as an implementation
of Facade pattern which provides a simplified interface to a larger body
of code responsible for Domain Entity management.
The main intention is to make API more readable and reduce
dependencies of business logic code on the inner workings of a
module, since most code uses the facade, thus allowing more flexibility
in developing the system.
© 2016 Magento, Inc. Page | 43
Repositories
© 2016 Magento, Inc. Page | 44
© 2016 Magento, Inc. Page | 45
© 2016 Magento, Inc. Page | 46
Good API design
Don't make your client do anything you can do
for them (this reduces the amount of boilerplate
code your client will have)
© 2016 Magento, Inc. Page | 47
© 2016 Magento, Inc. Page | 48
Q & A
@iminyaylo
engcom@magent.com

API design best practices

  • 1.
    © 2016 Magento,Inc. Page | 1 API Design Best practices Igor Miniailo Magento 2 Architect
  • 2.
    © 2016 Magento,Inc. Page | 2
  • 3.
    © 2016 Magento,Inc. Page | 3
  • 4.
    © 2016 Magento,Inc. Page | 4 Why is API so crucial?
  • 5.
    © 2016 Magento,Inc. Page | 5
  • 6.
    © 2016 Magento,Inc. Page | 6
  • 7.
    © 2016 Magento,Inc. Page | 7
  • 8.
    © 2016 Magento,Inc. Page | 8 Semantic Versioning Version numbers are in the format MAJOR.MINOR.PATCH, where: – MAJOR indicates incompatible API changes – MINOR indicates backward-compatible functionality has been added – PATCH indicates backward-compatible bug fixes
  • 9.
    © 2016 Magento,Inc. Page | 9 The backward compatibility policy applies to PHP code annotated with @api
  • 10.
    © 2016 Magento,Inc. Page | 10 Public and Private code
  • 11.
    © 2016 Magento,Inc. Page | 11 Public vs Private code Private code is not supposed to be used by third party modules, so, in most cases, its modifications will only trigger PATCH version bumps. Changes in public code always trigger MINOR or MAJOR version bumps.
  • 12.
    © 2016 Magento,Inc. Page | 12 What examples of Public code Magento has? • PHP Interface (marked with @api) • PHP Class (marked with @api) • Javascript Interface (marked with @api) • Javascript Class (marked with @api) • Virtual Type (marked with @api) • URL paths • Console commands and their arguments • Less Variables & Mixins • Message queue topics and their data types • UI component declarations • Layout handles declared by modules • Events triggered by component (both static dynamic) • Schema of configuration types introduced by module • Structure of System Configuration fields used by module
  • 13.
    © 2016 Magento,Inc. Page | 13 API vs SPI (Extension Points) A PHP Interface in Magento can be used several ways by the core product and extension developers. • As an API. is a set of interfaces and their implementations that a module provides to other modules • As a Service Provider Interface (SPI). is a set of interfaces that a module uses internally and allows their implementation by other modules. • As both. APIs and SPIs are not mutually exclusive.
  • 14.
    © 2016 Magento,Inc. Page | 14 After the code is released, both API and SPI can be evolved in a backwards-compatible way. But both have their specific limitations.
  • 15.
    © 2016 Magento,Inc. Page | 15
  • 16.
    © 2016 Magento,Inc. Page | 16
  • 17.
    © 2016 Magento,Inc. Page | 17
  • 18.
    © 2016 Magento,Inc. Page | 18
  • 19.
    © 2016 Magento,Inc. Page | 19
  • 20.
    © 2016 Magento,Inc. Page | 20 We do not distinguish them separately. SPIs are annotated the same as APIs.
  • 21.
    © 2016 Magento,Inc. Page | 21 Who decides whether interface/class belong to API or SPI? YOU
  • 22.
    © 2016 Magento,Inc. Page | 22 Dependency Rules API If a module uses (calls) an API, it should be dependent on the MAJOR version. API dependency example { ... "require": { "magento/module-customer": "~100.0", // (>=100.0 <101.0.0) }, ... }
  • 23.
    © 2016 Magento,Inc. Page | 23 Dependency Rules SPI If a module implements an API/SPI, it should be dependent on the MAJOR+MINOR version. SPI dependency example { ... "require": { "magento/module-customer": "~100.0.0", // (>=100.0.0 <100.1.0) }, ... }
  • 24.
    © 2016 Magento,Inc. Page | 24 http://devdocs.magento.com/guides/v2.1/release-notes/backward- incompatible-changes-2.1.html
  • 25.
    © 2016 Magento,Inc. Page | 25 Prohibited Code Changes
  • 26.
    © 2016 Magento,Inc. Page | 26 • Interface/class removal • Public & protected method removal • Introduction of a method to a class or interface PHP - Prohibited Code Changes
  • 27.
    © 2016 Magento,Inc. Page | 27 MagentoCatalogApiCategoryRepositoryInterface
  • 28.
    © 2016 Magento,Inc. Page | 28 MagentoCatalogApiCategoryListInterface
  • 29.
    © 2016 Magento,Inc. Page | 29 PHP - Prohibited Code Changes • Static function removal • Parameter addition in public methods • Parameter addition in protected methods
  • 30.
    © 2016 Magento,Inc. Page | 30
  • 31.
    © 2016 Magento,Inc. Page | 31 PHP - Prohibited Code Changes • Method argument type modification • Modification of types of thrown exceptions (unless a new exception is a subtype of the old one) • Constructor modification
  • 32.
    © 2016 Magento,Inc. Page | 32 class ExistingClass { /** * @var NewDependencyInterface $newDependency */ private $newDependency; public function __construct( OldDependencyIntreface $oldDependency, $oldRequiredConstructorParameter, $oldOptinalConstructorParameter = null, NewDependencyInterface $newDependency = null ) { ... $this>newDependency = $newDependency ?: MagentoFrameworkAppObjectManager::getInstance() ->get(NewDependencyInterface::class); ... } public function existingFunction() { // Existing functionality ... // Use $this->newDependency wherever the new dependency is needed ... } }
  • 33.
    © 2016 Magento,Inc. Page | 33 PHP - Prohibited Code Changes • Modifying the default values of optional arguments in public and protected methods • Removing or renaming constants
  • 34.
    © 2016 Magento,Inc. Page | 34 The main rule is that backwards compatibility is more important than niceness and effort of the implementation.
  • 35.
    © 2016 Magento,Inc. Page | 35 Coupling Between Objects Reaches Its Limit with a New Dependency
  • 36.
    © 2016 Magento,Inc. Page | 36 We MUST do continuous Refactoring! Backward Compatibility should not be an excuse for not doing refactoring!
  • 37.
    © 2016 Magento,Inc. Page | 37 Backward Compatible Fix *it works (most of the time), but code quality is far from good enough
  • 38.
    © 2016 Magento,Inc. Page | 38 Good object oriented programming in the service layer is basically functional programming: • constructor injection • immutable state • single responsibility principle • uniform interfaces • value objects passed across services Bringing these concepts to an extreme leads to single-method, immutable objects.
  • 39.
    © 2016 Magento,Inc. Page | 39
  • 40.
    © 2016 Magento,Inc. Page | 40 Why execute but not __invoke?
  • 41.
    © 2016 Magento,Inc. Page | 41 PHP 7 • Return Types • Scalar Type hinting
  • 42.
    © 2016 Magento,Inc. Page | 42 Repositories In Magento 2 Repositories are considered as an implementation of Facade pattern which provides a simplified interface to a larger body of code responsible for Domain Entity management. The main intention is to make API more readable and reduce dependencies of business logic code on the inner workings of a module, since most code uses the facade, thus allowing more flexibility in developing the system.
  • 43.
    © 2016 Magento,Inc. Page | 43 Repositories
  • 44.
    © 2016 Magento,Inc. Page | 44
  • 45.
    © 2016 Magento,Inc. Page | 45
  • 46.
    © 2016 Magento,Inc. Page | 46 Good API design Don't make your client do anything you can do for them (this reduces the amount of boilerplate code your client will have)
  • 47.
    © 2016 Magento,Inc. Page | 47
  • 48.
    © 2016 Magento,Inc. Page | 48 Q & A @iminyaylo engcom@magent.com

Editor's Notes

  • #9 We promise to be backward compatible for classes and methods annotated with @api within MINOR and PATCH updates to our components. As changes are introduced, we annotate methods with @deprecated. The methods are removed only with the next MAJOR component version. 
  • #12 Let’s recap what we had with Magento 1 – where everything is an extension points. All the protected mess and so on. We can’t make changes in contract – all changes suppose to extend existing contract.
  • #23 Tilde = Significant Release Operator