Fettuccine “Carbonara” Poached Egg and Smoked Bacon

@Cedro

RESTful Web APIs is the follow-up book to RESTful Web Services and is an updated view on how to build a truly RESTful service. It was published in late 2013 so has the benefit of a few years of hindsight compared to the original book, and it is written by one of the original authors, Leonard Richardson. I wrote down some thoughts on the original book and wanted to see what this “sequel” had to offer.

There are a number of insightful ideas and the authors try to be pragmatic. Personally, I think it is difficult to build a truly RESTful service with hypermedia but the book gives several ideas and exercises on how to build one.

Forget Resource-Oriented Architecture

While RESTful Web Services introduced Resource-Oriented Architecture (ROA), RESTful Web APIs basically casts the methodology aside. Today, most APIs use the uniform interface (GET, POST, PUT, DELETE), status codes, and can support multiple representations of resources (JSON, XML, etc.) with various degrees of success. However, the book poses the idea that it is the hypermedia part that is missing and yet is the most powerful concept in RESTful architectures.

Hypermedia is what distinctly separates RESTful architectures from RPC/SOAP-based ones. It is what makes the web “work” without versioning and without having to learn rules for visiting each website.

You don’t know or care that you’re visiting revision 1.0 or revision 2500 of a website. You just browse it. And when you browse a website, you do not have to construct URLs based on some convention or figure out what parameters are available. There are hyperlinks and forms to guide you. For those that like poor acronyms, HATEOS is the concept missing from today’s RESTful APIs.

The book proposes a change in mindset from resource-based designs to designs based on states (representations) and transitions (links) between states.

Random Thoughts

PATCH for update

Instead of PUT, use PATCH for updates. Some frameworks such as Ruby on Rails have wholeheartedly made this change. The only controversial part is perhaps the lack of widespread support for this addition to the standard HTTP methods (whether it be in proxies, frameworks, etc.).

JSON-Patch and an RFC for XML patching are suggested for partial updates.

How to Represent Dynamic Resources as Hypermedia

URI Templates and forms were generally suggested to expose parameters for resources.

Collection+JSON was also shown as a possible hypermedia format to represent collections of items and to present the templates and forms. The book still referred to Atom for some use cases but Atom seems to increasingly lack usage. I actually would have liked some form of Atom to remain in usage because other standards like PubSubHubBub seemed to provide a more realtime (using webhooks yet more efficient) web.

Versioning

One of the ideas is that the need for versioning is not as important with hypermedia providing part of the solution. Unfortunately, the book and I believe we are a ways off from clients automatically understanding the semantics behind the data. Unlike most programmed API clients, web browsers have a person deciding which links to click on the web.

Due to the lack of smarter clients, APIs may have to be versioned when breaking changes are made. The book provides a few non-hypermedia possible solutions for versioning an API that are commonly used (e.g. version in path). The book makes an interesting case when hypermedia can definitely help but until we have clients that are programmed to take advantage of the hypermedia, it may be difficult to solely rely on hypermedia to prevent breaking API clients.

Better References

The book lists a number of resources, hypermedia standards, ways to register your media type, ways to register your link relations, etc. as examples. It also gave some quick information about each.

While hypermedia perhaps still isn’t an essential component of some RESTful APIs, there seems to be an upswing in adoption of forms of hypermedia. I don’t recall it mentioned in the book but the GitHub API seems to be adopting hypermedia. I used to refer to the Twitter API as one of the better examples of a practical RESTful API but it seems GitHub’s API is better.

Conclusion

Overall the book was a healthy read. While it mainly focused on hypermedia, it provided several good thought exercises on how to design a better RESTful API using hypermedia. Most API designers/implementors would probably get more out of RESTful Web APIs today than RESTful Web Services just due to the advancement of general understanding of RESTful architectures.

Dependency injection (DI) is one of the major new features in Magento 2. Dependency injection’s benefits are explained more thoroughly in other pages around the web but hopefully this page helps clarify some usage details.

However, dependency injection is not a new concept so don’t be afraid of the intimidating terminology. Many languages have multiple implementations. Java has JSR-299 CICD and more commonly used third party libraries like Google Guice and Spring. Even JavaScript frameworks have dependency injection in AngularJS and Ember.js amongst others. And of course, there are PHP libraries also doing dependency injection.

ObjectManager

The ObjectManager is responsible for creating objects (known as an Injector in some libraries).

The \Magento\Framework\ObjectManagerInterface is the injector interface for Magento 2. The implementation is located at \Magento\Framework\ObjectManager.

What does the ObjectManager do?

Imagine you have the following 3 classes.

<?php
class CookieReader {
    public function __construct() {
        // empty
    }
}

class HttpRequest {

    private $cookieReader;

    public function __construct(
        CookieReader $cookieReader
    } {
        $this->$cookieReader = $cookieReader;
    }
}

class Controller {

    private $httpRequest;

    public function __construct(
        HttpRequest $httpRequest
    ) {
        $this->httpRequest = $httpRequest;
    }
}

Let’s say that Magento 2 needs a Controller instance. It uses the ObjectManager to create an instance of the Controller class.

When the ObjectManager is asked to create a Controller object, the ObjectManager must figure out what to pass into the Controller’s constructor parameters. The parameters are the class’s dependencies.

A simple view is the ObjectManager recursively determines how to create objects for constructor parameters until it can fulfill all the dependencies and then (finally!) creates the Controller object.

In more detail:

  1. The ObjectManager determines that it needs a HttpRequest object to pass into the Controller’s constructor.
  2. Then, the ObjectManager determines that HttpRequest needs a CookieReader.
  3. Luckily, CookieReader does not have any parameters for its constructor so the ObjectManager could just effectively call new CookieReader().
  4. Once the ObjectManager has a CookieReader, it can create the HttpRequest.
  5. Finally, the ObjectManager has a HttpRequest, so it can create a Controller.

This is a basic explanation because there are complex scenarios during object creation but developers usually do not have to worry about how dependencies are fulfilled. Developers specify what they need in their class constructors, and the ObjectManager will try to figure out how to get the right parameters to pass in.

How is the ObjectManager used in the app?

Starting at the index.php entry point, there are bootstrapping functions that create an ObjectManagerFactory and then initializes an ObjectManager. Once initialized, the ObjectManager is used to create the real application object which recursively fulfills all of the dependencies. Then the real application object is used to run() the application.

Should I use the ObjectManager directly?

No, unless you really know what you’re doing.

There are some framework and auto-generated classes that require the ObjectManager to be passed into their constructors (hey, the ObjectManager knows how to pass itself into a constructor :) ). However, as a best practice, you should not have an ObjectManager constructor parameter and should not directly instantiate the ObjectManager itself.

If you use the ObjectManager directly, you are probably using it as a service-locator. Service locators make unit testing more difficult, hide dependencies, and make it difficult to assemble the right dependencies in certain contexts.

Your dependencies should be declared in your constructor, and you should let the framework give you the right objects to construct your type.

Use automatically generated Factories if you need to create objects in your business logic code.

Constructor-based injection

Magento 2 supports constructor-based injection as demonstrated above.

Setter/method based injection is not currently used in Magento 2. Setter/method based injection uses set<PropertyName>() methods to inject dependencies versus calling a single constructor.

One advantage of constructor-based injection is a defined method for initialization. Once your constructor is called, you can do whatever you need with all the parameters and not have to worry that only some of the parameters were set. Setter/method based injection sometimes requires a “post-construct” method (either annotated or defined by convention) to do the final initialization after all the setters are called. Constructor-based injection is more verbose however.

No phpDoc required

In Magento 2, phpDoc is not required for dependency injection (but of course, you’re going to document your code when appropriate, right? :) ).

The types for the arguments are gathered from the actual type hint on the constructor parameters. In other words, you need to have the HttpRequest in the HttpRequest $httpRequest in the constructor parameter list.

Should I use Interfaces in my parameters?

Yes.

You should primarily because you should not depend on the actual implementation behind the interface. The Interface is the public API and is much more stable.

Is there any magic to constructor parameters?

If you have default parameter values, these parameters should be last in the parameter list.

<?php
class Type {

    public function __construct(
        SomeType $a,
        SomeOtherType $b = null,
        $c = "default value"
    ) {

Unless a value is specified in an arguments element in a di.xml, the ObjectManager will not pass in any value (so your constructor will use the default value).

Also, if you extend a class, you should try to keep the same order of the parameters as your parent class’s constructor. This keeps things sane.

di.xml Configuration File

di.xml files contain the dependency injection configuration. Note that modules can have their own di.xml such as in the Customer module. Also, modules can have even more specific config for the frontend and adminhtml areas.

Configuration within the same scope will be merged together. More specific scope levels will override the more generic scoped config.

How does the ObjectManager know which real implementation to use for an Interface?

The di.xml specifies which implementation to use:

<preference for="Magento\Framework\Url\EncoderInterface" type="Magento\Framework\Url\Encoder" />

Every constructor that asks for an EncoderInterface will get a Magento\Framework\Url\Encoder passed to it.

Shared Object / Singleton Lifecycle

By default, the ObjectManager creates a single instance of a class and re-uses the same instance across injections. The ObjectManager manages the singleton scope for the object for any code that is instantiated by the ObjectManager (basically everything in Magento 2).

So if you specify a StoreManager in a Helper class’s constructor and then also specify a StoreManager in a Controller class, the same StoreManager will be passed to both constructors.

Note that while this is a managed singleton lifecycle, this is more like a per request lifecycle object in other languages (e.g. in a Java EE application server) due to the nature of the PHP runtime which usually starts one isolated process per request. So the same instance will not be used between 2 different requests.

How to Use Non-Shared Object Lifecycles in Injections

If you need to create objects in your business logic (e.g. you need to create a new model instance), you are generally advised to use a Factory if at all possible.

However, there are cases where you want to declare a type to be a non-shared. In other words, you want a new unique object instance passed into every class that declares a dependency for that type.

In that case, your di.xml could contain a type element with a shared attribute set to false:

<type name="Magento\Framework\Data\Structure" shared="false" />

Whenever a \Magento\Framework\Data\Structure is declared as a parameter in a constructor, the ObjectManager will pass a new object in every time.

Note that this is similar to a prototype lifecycle in other frameworks/libraries.

What if I want to specify a type for only one constructor?

So if you need to specify the exact type to use in a specific constructor, you can use the following config:

<type name="Magento\Framework\Logger\Handler\System">
    <arguments>
        <argument name="filesystem" xsi:type="object">Magento\Framework\Filesystem\Driver\File</argument>
    </arguments>
</type>

The arguments element can contain multiple argument elements. The name attribute’s value (“filesystem”) corresponds to the name of the constructor parameter ($filesystem).

The xsi:type specifics that you want an object to be passed into the constructor and the argument element value specifies that you want a \Magento\Framework\Filesystem\Driver\File to be instantiated.

So when a Magento\Framework\Logger\Handler\System is instantiated, it will be passed in Magento\Framework\Filesystem\Driver\File to its $filesystem constructor parameter.

What if my constructor takes a string?

As shown above, you can specify exact argument values in a constructor.

<type name="Monolog\Handler\StreamHandler">
    <arguments>
        <argument name="stream" xsi:type="string">var/log/system.log</argument>
    </arguments>
</type>

Note that the xsi:type attribute specifies a string, and the string’s value will be the element’s value. You can see similar configuration for other primitive types.

What if you have a cyclic reference?

Suppose that you have cyclic reference where class A depends on class B and class B depends on class A. While this should not intentionally occur, it can happen as the dependency graph grows.

You should use a Proxy. It’s as easy as adding some di.xml config:

<type name="Magento\Framework\Message\Manager">
    <arguments>
        <argument name="session" xsi:type="object">Magento\Framework\Message\Session\Proxy</argument>
    </arguments>
</type>

The Proxy class is automatically created for \Magento\Framework\Message\Session due to code generation.

Proxies are also useful for lazy-loading types which are expensive to create.

Questions?

Ask on the Magento Stack Exchange. You could also raise an issue on the Magento 2 GitHub tracker.

Disclaimer: These are some practical notes about Magento 2, and while I try to be technically accurate, there are edge cases and details that I will gloss over. Note that I did not architect or write any of the relevant code but I do work on the Magento 2 codebase. This is not an official Magento 2 doc. You should find more detailed information at the official Developer Docs.