From dce44d962b5635f05d8ce86beb2c97ffcd821a5c Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Tue, 13 Jun 2023 23:44:42 +0200 Subject: [PATCH 01/11] Add hybrid FE design draft --- .../14.best-practices/19.hybrid-fe-design/docs.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md new file mode 100644 index 00000000..76cd68f3 --- /dev/null +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -0,0 +1,11 @@ +--- +title: Hybrid FE design using Webhooks, Checkout and Shop APIs +altTitle: Hybrid FE design +excerpt: If you're building a larger website, you might want to use both Checkout and Shop APIs to build all your FE functions +taxonomy: + category: docs +--- + +## Lorem ipsum + +asd From 05514b1ce5c3edcb61aaee5cd26e91a02b7dd110 Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:04:56 +0200 Subject: [PATCH 02/11] Proper docs --- .../19.hybrid-fe-design/docs.md | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index 76cd68f3..58f08e50 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -6,6 +6,54 @@ taxonomy: category: docs --- -## Lorem ipsum +## Why does Centra provide two different webshop APIs -asd +Shop API is our original webshop API, designed in the times when the Internet was older. Stateless REST APIs were taking over, and no one really understood the need to go stateful, respecting the context of the webshop user. + +Few years later we realised that stateless is not great in the world where you try your best to save up on bandwidth, while you're also exposing too much unnecessary data to too many actors. We therefore wrote Checkout API, which was stateful and more byte-conservative, which gave us great options to optimise your API responses based on the context of your selection. + +Today we find ourselves in a new Internet, where static page generation and smart caching are very much desired, and we realised that stateful Checkout API is not always the best solution to feed the middle-ware servers with data, where the output of the API depends on the context of the shopper. Once again, we realise that an API that serves all available data, always, actually posesses a true value when it comes to fetching all required data, like when you're building your caches. + +## The high-level concept of a hybrid FE solution + +![](hybrid.png) + +In short: +* Shop API builds the shop's backend, the backbone of your front end +* Checkout API builds the shop's checkout experience, from entering the website to a successful checkout (or at least a Cart Abandonment email) + +## The one big thing in common + +Both Shop and Checkout APIs use the same `product` IDs (which are [display item IDs](/fe-development/fe-elements#why-do-i-see-different-product-ids-in-the-centra-backend-and-in-checkout-api), meaning the product variants activated on a store display. These are the same IDs that are returned by the [Centra Webhook plugin](/plugins/centra-webhook) activated in a `Checkout API` mode. Therefore, same webhook events can be used by both APIs, for both back-end (Shop API) and front-end (Checkout API) functions. + +Same `product` and `item` IDs are used by [/products](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/5.%20product%20catalog/post_products) and [/items](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/2.%20selection%20handling%2C%20cart/post_items__item_) endpoints in both Shop and Checkout APIs. + +## Characteristics of Checkout API + + + Newer Centra REST webshop API + + Stateful + + Returns only data relevant for session + + Small API response sizes + + Includes all most recent webshop functions + + - Difficult to poll multiple markets / pricelists /
warehouses / languages at once + - Building a cache / static page generation
requires multiple API calls per each product + +## Characteristics of Shop API + + - Older Centra REST webshop API + - Stateless + - Returns all data, always + - Large API response sizes + - Not all latest webshop functions available + + + By design returns products in all markets /
pricelists / warehouses / languages at once + + Building a cache / static page generation
requires much fewer number of API calls + +Basically, in Shop API each [GET /products/{productId}](https://docs.centra.com/swagger-ui/?urls.primaryName=ShopAPI#/default/get_products__product_) API call returns product data
in every market / pricelist / warehouse / language

 + +### Known limitations of Shop API + +Current known problems: + - Minimal data returned for each `relatedProducts`, 
requiring one API call per each product ID + - Unable to fetch multiple product IDs at once From 5834b1c2f92eda9d0a5b66ef96199f0c4ea50688 Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:05:26 +0200 Subject: [PATCH 03/11] Add files via upload --- .../19.hybrid-fe-design/fe-hybrid-design.png | Bin 0 -> 47565 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pages/03.fe-development/14.best-practices/19.hybrid-fe-design/fe-hybrid-design.png diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/fe-hybrid-design.png b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/fe-hybrid-design.png new file mode 100644 index 0000000000000000000000000000000000000000..ffb405a821d66858a49f9e9313dc81f178fabe83 GIT binary patch literal 47565 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 >^`N)Q~tk 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 Date: Wed, 14 Jun 2023 00:06:06 +0200 Subject: [PATCH 04/11] Fix image --- .../14.best-practices/19.hybrid-fe-design/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index 58f08e50..b553699a 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -16,7 +16,7 @@ Today we find ourselves in a new Internet, where static page generation and smar ## The high-level concept of a hybrid FE solution -![](hybrid.png) +![](fe-hybrid-design.png) In short: * Shop API builds the shop's backend, the backbone of your front end From 13972260e4ae66d45e60a840c45424e40454a679 Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:09:55 +0200 Subject: [PATCH 05/11] Update docs.md --- .../14.best-practices/19.hybrid-fe-design/docs.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index b553699a..41da104c 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -18,9 +18,14 @@ Today we find ourselves in a new Internet, where static page generation and smar ![](fe-hybrid-design.png) -In short: -* Shop API builds the shop's backend, the backbone of your front end -* Checkout API builds the shop's checkout experience, from entering the website to a successful checkout (or at least a Cart Abandonment email) +In short: +* Shop API builds the shop's backend, the backbone of your front end +* Checkout API builds the shop's checkout experience, from entering the website to a successful checkout (or at least a [Cart Abandonment](/plugins/cartabandonment) email) +* Centra Webhooks are used to only trigger updates of relevant data + +[notice-box=info] +In case of a network or application failure, remember to always include a mechanism to completely re-build your middle-ware cache from scratch. Use it as a failsafe after unplanned outages, where individual webhooks might have been lost. +[/notice-box] ## The one big thing in common From ff409232bb6e79f5746247ba80ab2bf8d05fec16 Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 00:14:03 +0200 Subject: [PATCH 06/11] Update docs.md --- .../14.best-practices/19.hybrid-fe-design/docs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index 41da104c..a814768b 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -12,16 +12,16 @@ Shop API is our original webshop API, designed in the times when the Internet wa Few years later we realised that stateless is not great in the world where you try your best to save up on bandwidth, while you're also exposing too much unnecessary data to too many actors. We therefore wrote Checkout API, which was stateful and more byte-conservative, which gave us great options to optimise your API responses based on the context of your selection. -Today we find ourselves in a new Internet, where static page generation and smart caching are very much desired, and we realised that stateful Checkout API is not always the best solution to feed the middle-ware servers with data, where the output of the API depends on the context of the shopper. Once again, we realise that an API that serves all available data, always, actually posesses a true value when it comes to fetching all required data, like when you're building your caches. +Today we find ourselves in a new Internet, where static page generation and smart caching are very much desired, and we realised that stateful Checkout API is not always the best solution to feed the middle-ware servers with data, where the output of the API depends on the context of the shopper. Once again, we realise that a stateless API that serves all available data, always, actually posesses a true value when it comes to fetching all required data, like when you're building your caches. ## The high-level concept of a hybrid FE solution ![](fe-hybrid-design.png) In short: -* Shop API builds the shop's backend, the backbone of your front end -* Checkout API builds the shop's checkout experience, from entering the website to a successful checkout (or at least a [Cart Abandonment](/plugins/cartabandonment) email) -* Centra Webhooks are used to only trigger updates of relevant data +* [Shop API](https://docs.centra.com/swagger-ui/?urls.primaryName=ShopAPI) builds the shop's backend, the backbone of your front end +* [Checkout API](/fe-development/fe-elements) builds the shop's checkout experience, from entering the website to a successful checkout (or at least a [Cart Abandonment](/plugins/cartabandonment) email) +* [Centra Webhooks](/plugins/centra-webhook) are used to only trigger updates of relevant data [notice-box=info] In case of a network or application failure, remember to always include a mechanism to completely re-build your middle-ware cache from scratch. Use it as a failsafe after unplanned outages, where individual webhooks might have been lost. @@ -31,7 +31,7 @@ In case of a network or application failure, remember to always include a mechan Both Shop and Checkout APIs use the same `product` IDs (which are [display item IDs](/fe-development/fe-elements#why-do-i-see-different-product-ids-in-the-centra-backend-and-in-checkout-api), meaning the product variants activated on a store display. These are the same IDs that are returned by the [Centra Webhook plugin](/plugins/centra-webhook) activated in a `Checkout API` mode. Therefore, same webhook events can be used by both APIs, for both back-end (Shop API) and front-end (Checkout API) functions. -Same `product` and `item` IDs are used by [/products](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/5.%20product%20catalog/post_products) and [/items](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/2.%20selection%20handling%2C%20cart/post_items__item_) endpoints in both Shop and Checkout APIs. +Same `product` and `item` IDs are used by [GET/POST /products](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/5.%20product%20catalog/post_products) and [POST /items](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/2.%20selection%20handling%2C%20cart/post_items__item_) endpoints in both Shop and Checkout APIs. ## Characteristics of Checkout API From a1d4664792a753458479394df75d336a98738e9c Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 08:48:00 +0200 Subject: [PATCH 07/11] Update docs.md --- .../14.best-practices/19.hybrid-fe-design/docs.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index a814768b..9e4a041b 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -8,9 +8,9 @@ taxonomy: ## Why does Centra provide two different webshop APIs -Shop API is our original webshop API, designed in the times when the Internet was older. Stateless REST APIs were taking over, and no one really understood the need to go stateful, respecting the context of the webshop user. +Shop API is our original webshop API, designed in the times when the Internet was older. Stateless REST APIs were taking over, and no one really cared about respecting the context of the webshop user. It was OK to serve all data to everybody. -Few years later we realised that stateless is not great in the world where you try your best to save up on bandwidth, while you're also exposing too much unnecessary data to too many actors. We therefore wrote Checkout API, which was stateful and more byte-conservative, which gave us great options to optimise your API responses based on the context of your selection. +Few years later we realised that stateless is not great in the world where you try your best to save up on bandwidth, while you're also exposing too much unnecessary data to too many actors. We therefore wrote Checkout API, which was stateful and more byte-conservative, which gave us great options to optimise your API responses based on location and language of your session. Today we find ourselves in a new Internet, where static page generation and smart caching are very much desired, and we realised that stateful Checkout API is not always the best solution to feed the middle-ware servers with data, where the output of the API depends on the context of the shopper. Once again, we realise that a stateless API that serves all available data, always, actually posesses a true value when it comes to fetching all required data, like when you're building your caches. @@ -24,7 +24,7 @@ In short: * [Centra Webhooks](/plugins/centra-webhook) are used to only trigger updates of relevant data [notice-box=info] -In case of a network or application failure, remember to always include a mechanism to completely re-build your middle-ware cache from scratch. Use it as a failsafe after unplanned outages, where individual webhooks might have been lost. +In case of a network or application issues, remember to always include a mechanism to completely re-build your middle-ware cache from scratch. Use it as a failsafe after unplanned outages, where individual webhooks might have been lost. [/notice-box] ## The one big thing in common From ee48308bd2950a1590727e860db56d701578c442 Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 08:48:19 +0200 Subject: [PATCH 08/11] Update docs.md --- .../14.best-practices/19.hybrid-fe-design/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index 9e4a041b..2e299bde 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -8,7 +8,7 @@ taxonomy: ## Why does Centra provide two different webshop APIs -Shop API is our original webshop API, designed in the times when the Internet was older. Stateless REST APIs were taking over, and no one really cared about respecting the context of the webshop user. It was OK to serve all data to everybody. +Shop API is our original webshop API, designed in the times when the Internet was older. Stateless REST APIs were taking over, and no one really cared about respecting the context of the webshop user. It was OK to serve the same data to everybody. Few years later we realised that stateless is not great in the world where you try your best to save up on bandwidth, while you're also exposing too much unnecessary data to too many actors. We therefore wrote Checkout API, which was stateful and more byte-conservative, which gave us great options to optimise your API responses based on location and language of your session. From 4ce90d9d861b1406ca7173b6f4e99c21f3bf81cc Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 08:50:50 +0200 Subject: [PATCH 09/11] Update docs.md --- .../14.best-practices/19.hybrid-fe-design/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index 2e299bde..bad4972a 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -29,7 +29,7 @@ In case of a network or application issues, remember to always include a mechani ## The one big thing in common -Both Shop and Checkout APIs use the same `product` IDs (which are [display item IDs](/fe-development/fe-elements#why-do-i-see-different-product-ids-in-the-centra-backend-and-in-checkout-api), meaning the product variants activated on a store display. These are the same IDs that are returned by the [Centra Webhook plugin](/plugins/centra-webhook) activated in a `Checkout API` mode. Therefore, same webhook events can be used by both APIs, for both back-end (Shop API) and front-end (Checkout API) functions. +Both Shop and Checkout APIs use the same `product` IDs (which are [display item IDs](/fe-development/fe-elements#why-do-i-see-different-product-ids-in-the-centra-backend-and-in-checkout-api), meaning the product variants activated on a store display). These are the same IDs that are returned by the [Centra Webhook plugin](/plugins/centra-webhook) activated in a `Checkout API` mode. Therefore, same webhook events can be used by both APIs, for both back-end (Shop API) and front-end (Checkout API) functions. Same `product` and `item` IDs are used by [GET/POST /products](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/5.%20product%20catalog/post_products) and [POST /items](https://docs.centra.com/swagger-ui/?api=CheckoutAPI#/2.%20selection%20handling%2C%20cart/post_items__item_) endpoints in both Shop and Checkout APIs. From f70d82994e9d1a7b5152f2daa0c25ff248bd1bef Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Wed, 14 Jun 2023 08:52:13 +0200 Subject: [PATCH 10/11] Styling --- .../14.best-practices/19.hybrid-fe-design/docs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index bad4972a..58c9bd8b 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -41,7 +41,7 @@ Same `product` and `item` IDs are used by [GET/POST /products](https://docs.cent + Small API response sizes + Includes all most recent webshop functions - - Difficult to poll multiple markets / pricelists /
warehouses / languages at once + - Difficult to poll multiple markets / pricelists / warehouses / languages at once - Building a cache / static page generation
requires multiple API calls per each product ## Characteristics of Shop API @@ -55,7 +55,7 @@ Same `product` and `item` IDs are used by [GET/POST /products](https://docs.cent + By design returns products in all markets /
pricelists / warehouses / languages at once + Building a cache / static page generation
requires much fewer number of API calls -Basically, in Shop API each [GET /products/{productId}](https://docs.centra.com/swagger-ui/?urls.primaryName=ShopAPI#/default/get_products__product_) API call returns product data
in every market / pricelist / warehouse / language

 +Basically, in Shop API each [GET /products/{productId}](https://docs.centra.com/swagger-ui/?urls.primaryName=ShopAPI#/default/get_products__product_) API call returns product information in every market / pricelist / warehouse / language

 ### Known limitations of Shop API From 8fb9025e4c520cca2f77b9972f46affebe74d3ac Mon Sep 17 00:00:00 2001 From: piotr-symonowicz <49191214+piotr-symonowicz@users.noreply.github.com> Date: Fri, 16 Jun 2023 08:42:40 +0200 Subject: [PATCH 11/11] Elin's rewrite --- .../14.best-practices/19.hybrid-fe-design/docs.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md index 58c9bd8b..9c4e1363 100644 --- a/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md +++ b/pages/03.fe-development/14.best-practices/19.hybrid-fe-design/docs.md @@ -8,11 +8,11 @@ taxonomy: ## Why does Centra provide two different webshop APIs -Shop API is our original webshop API, designed in the times when the Internet was older. Stateless REST APIs were taking over, and no one really cared about respecting the context of the webshop user. It was OK to serve the same data to everybody. +Shop API is our original webshop API, which was developed during a time when the Internet was in its earlier stages. Stateless REST APIs were becoming popular, and there wasn't much emphasis on considering the context of the webshop user, it was acceptable to serve the same data to everyone. -Few years later we realised that stateless is not great in the world where you try your best to save up on bandwidth, while you're also exposing too much unnecessary data to too many actors. We therefore wrote Checkout API, which was stateful and more byte-conservative, which gave us great options to optimise your API responses based on location and language of your session. +As time went on and Centra continued to progress, we recognized the limitations of stateless APIs where conserving bandwidth and minimizing unnecessary data exposure were becoming more important. To address this, we introduced the Checkout API, which was stateful and more byte-conservative to optimise the API responses based on the user's location and language. -Today we find ourselves in a new Internet, where static page generation and smart caching are very much desired, and we realised that stateful Checkout API is not always the best solution to feed the middle-ware servers with data, where the output of the API depends on the context of the shopper. Once again, we realise that a stateless API that serves all available data, always, actually posesses a true value when it comes to fetching all required data, like when you're building your caches. +In the present day we find that the demands have changed again, static page and smart caching are highly desired, stateful APIs such as Checkout API is not the best solution to feed middle-ware servers with data when that data depends on the context of the individual shopper. A stateless API that consistently serves all available data can prove valuable, particularly when building caches and retrieving all the necessary data. ## The high-level concept of a hybrid FE solution