Magento 2 as a headless solution
Answers to the questions
Who is responsible for formatting data, for example prices. Magento API and frontend framework?
Magento API provides access to the data and business logic. Formatting data/prices are part of presentation logic, so on this way, you have more flexibility to present information in the way you want (without being forced to do it on Magento way).
For example, you can utilize javascript to detect locale settings and provide appropriate data. Check following: navigator.language toLocaleString()
Or, you can even choose to import prices from Magento to 3rd party system, or data analysis tool, and having prices formatted according to the currency format would only break import process until you solve "currency conversion".
Who is responsible for resizing product images and cache them? Because in the native Magento 2 API there is no resize or cache system.
Exactly. As I said above, Magento provides access to the data (without presentation logic). It's up to you how you'll use it.
For example, you may opt for adaptive image resize http://adaptive-images.com/details.htm, so you can easily use original image and do whatever you want.
You can choose the way how you'll cache images, do you want to use lossy or lossless compression for reducing images, etc.
Do I need to create new custom isolated API or extend native for future upgrade purpose?
I recommend you to make your API which will be used for presentation logic, and you'll be 99.9% (my guess) sure that you'll not be affected by a future upgrade of Magento2 API.
Do you recommend to use an extra layer to combine CMS and Magento API?
Highly recommended. But, the extra layer doesn't have to be an additional application; it can be a Magento2 module too. The good thing about this is the fact that you're free to combine it however you want; you can build your proxy layer using any language/technology you want.
I appreciate you to share your return in experience.
There are many approaches you can use here. I'll share my opinion on it.
My Approach to Headless
First, I would split it into two layers: proxy layer and presentation layer.
Proxy layer
The first thing you'll have to consider is about building Proxy layer. Behind the scenes, you can utilize Magento API, CMS API, ERP API, x API, whatever you want...
In the proxy layer, you're free to use and organize data the way you want. You can implement caching layer there, as well as additional functionalities for data formatting, customer tracking, various automatizations, etc. In general, anything you need for easy-juggling in the presentation layer.
The proxy layer doesn't have to be coded in PHP; it can be coded in Java, NodeJS, or you can even utilize AWS API Gateway, AWS SQS, and Lambda for providing a whole proxy layer, or just part of it.
One of the approaches you can use is described by Fabrizio Branca at http://fbrnc.net/blog/2015/10/super-scaling-magento
Presentation layer
Presentation layer depends on client platform; if you're going to use it for Mobile App, things are pretty clear about the way how you should utilize proxy API.
For a web application, there are many possibilities. You can use:
- Standard PHP solution (powered by any framework) where you can utilize any of PHP templating engines (like Smarty, Twig, Dwoo...) to provide HTML output
- Java/NodeJS/whatever language you feel familiar with
- Purely javascript based solution, which would render all HTML and would call appropriate APIs through ajax to populate it with data
- Any hybrid/combination of those approaches from above
This is not by the book list, I've just shared few combinations. In reality, your imagination is the only limit.
Final thoughts
Use javascript based solution as much as you can, as it can provide a better experience to the Customer, smaller payload for page loads, you can even do speculative data load if you can predict customer's next actions.
BUT, the problem with the purely javascript solution is SEO. If all of your data is loaded through Ajax, Google probably would not be able to parse it.
The solution is to make a hybrid app which will serve whole HTML page on the first load, for example when you hit /catalog/shoes. For any further navigation through the site, you can utilize ajax to fetch only needed blocks.
One of the approaches would be creating snapshots of your page, for example by using PhantomJS. There are also few paid solutions for this, like:
- https://prerender.io
- http://www.brombone.com
I can share some insights of developing headless magento projects as my company has created 2 of them.
We have decided to use reactjs as a frontend application and connect it with node powered backend. API calls to magento was performed by the node on the server side. This meant no calls to magento were send from the browser.
From the API point of view it is good but there are some problems that we've met during the development. Magento2 endpoints sometimes are very limited. By default endpoint handler does not allow to inject additional data to the response as they are not provide extension_attributes
to each one. With frontend written separately it is not a good news. We were many times facing the need to add some data and couldn't do this for native magento endpoint due to lack of extension_attributes
. Those instances required as to either override magento endpoint and provide our own interface with additional fields or create our custom endpoint extending the magento one and changing what we need.
For example we needed to override /rest/V1/categories
as magento by default didn't add url path to the category tree. /rest/V1/products
which should fetch product data was also too limited for us as we needed to use it for category view and we wanted to receive available filters in that response.
Another issue were missing endpoints. We had to create ones for sending contact email, breadcrumbs for category, fetching quote data from quoteId and a few additional to deal with project specific elements. Generally speaking where in normal Magento2 front you would create a block fetching some custom collection to deal with you may need to add your api endpoint.
The most trick part was checkout. Although it is prepared for headless mode there are still some parts that required specific adjustment. If you are using paypal then normally you would be redirected to paypal site for payment with some tokent. For us this token need to be fetched separately as we do not follow standard redirect way. Similar case was with hooking up Adyen which required redirect after placing the order. Standard magento endpoint only returns order id on success and does not allow to inject redirect url. We also had some problems with implementing 3dSecure.
One major thing to consider and to make clear for the customer before going headless is that all frontend related parts of external modules will need to be rewritten for your specific implementation. As currently there is no way for a module to add it's own data to any headless part. The only thing the module can do is provide API endpoints.
All in all headless magento is definitely possible. We ended up having custom module for those adjustments and new endpoints that could be used with other projects.
React front works very well as react front can cache a lot of things and node backend is extremely fast. We are removing the time needed for view part of standard magento request this way.
If you want to check how it behaves here are links to the projects:
https://therake.com/
https://www.emperia.ch/
If someone speaks Dutch can check also this article about therake: http://www.marketingfacts.nl/berichten/headless-magento-2-de-toekomst-van-e-commerce
[UPDATE]
Update regarding checkout flow question. As I wrote checkout was tricky. Payment gateways on api levels are basically non-existent. For example, in regular checkout most payment gateways redirects you to the different site for finishing payment. Some of those modules are creating orders in magento in pending state, some (paypal express) do redirect before order is created. Those redirects often rely on your session to get details back after return. This was a problem as placeOrder api endpoint only returns id of the newly created order and not a info of a redirect. Since we also were hitting not magento directly but node backend the session need to be properly restored when returning from the gateway. Our current projects have paypal and Adyen gateways integrated and it took us over 150h. Any forms for payment methods need to be created manually as it is inserted via layout xml and there is no way to get information about any additional fields required by the payment method via API.
Here is open source project https://github.com/ishakhsuvarov/going-headless
This repository is created per discussion "Going Headless", which was a part of Imagine 2017 DevExchange sessions, to collect and discuss ideas regarding usage of Magento's Web API with custom frontend. The Main goal of this project is to collect the most critical and painful points in Web API flows and development of a solution, which would satisfy most of the use cases.