This is a demo implementation showing how to use EpiServer Commerce as a backend platform for Vue Storefront. This demo is based on the Episerver Commerce Quicksilver sample site. The main goal of this project is to provide a set of algorithms and data structures that will help with the integration of EPiServer Commerce and Vue StoreFront. Provided solution consists of two parts: ApiBridge and DataExporter.
- ApiBridge - implements web api required by VSF
- DataExporter - reading, converting and exporting data models from EpiServer to Elasticsearch (where it can be accessed by VSF)
Although the example implementation is based on Quicksilver, both ApiBridge and DataExporter have been developed with customization in mind.
- Setup Quicksilver demo - Quicksilver project
- Setup VSF application - Windows Installation or Linux Installation
- EPiServer.Reference.Commerce.VsfIntegration project has been added. This project contains examples of custom model mappers (e.g. QuicksilverProductMapper) and service adapters (e.g. QuickSilverUserAdapter).
- EPiServer.Reference.Commerce.Site->Features->Product->Models has been moved to EPiServer.Reference.Commerce.Shared->Models->Products
An working example can be found HERE
List of customized properties with example values:
{
"elasticsearch": {
"index": "epi-catalog",
...
},
"cart": {
"setCustomProductOptions": false,
"setConfigurableProductOptions": false,
"create_endpoint": "http://localhost:50244/vsbridge/Cart/create?token={{token}}",
"updateitem_endpoint": "http://localhost:50244/vsbridge/Cart/update?token={{token}}&cartId={{cartId}}",
"deleteitem_endpoint": "http://localhost:50244/vsbridge/Cart/delete?token={{token}}&cartId={{cartId}}",
"pull_endpoint": "http://localhost:50244/vsbridge/Cart/pull?token={{token}}&cartId={{cartId}}",
"totals_endpoint": "http://localhost:50244/vsbridge/Cart/totals?token={{token}}&cartId={{cartId}}",
"paymentmethods_endpoint": "http://localhost:50244/vsbridge/Cart/payment-methods?token={{token}}&cartId={{cartId}}",
"shippingmethods_endpoint": "http://localhost:50244/vsbridge/Cart/shipping-methods?token={{token}}&cartId={{cartId}}",
"shippinginfo_endpoint": "http://localhost:50244/vsbridge/Cart/shipping-information?token={{token}}&cartId={{cartId}}",
"collecttotals_endpoint": "http://localhost:50244/vsbridge/Cart/collect-totals?token={{token}}&cartId={{cartId}}",
"deletecoupon_endpoint": "http://localhost:50244/vsbridge/Cart/delete-coupon?token={{token}}&cartId={{cartId}}",
"applycoupon_endpoint": "http://localhost:50244/vsbridge/Cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}",
...
},
"users": {
"endpoint": "http://localhost:50244/vsbridge/user",
"history_endpoint": "http://localhost:50244/vsbridge/user/order-history?token={{token}}",
"resetPassword_endpoint": "http://localhost:50244/vsbridge/user/reset-password",
"changePassword_endpoint": "http://localhost:50244/vsbridge/user/change-password?token={{token}}",
"login_endpoint": "http://localhost:50244/vsbridge/user/login",
"create_endpoint": "http://localhost:50244/vsbridge/user/create",
"me_endpoint": "http://localhost:50244/vsbridge/user/me?token={{token}}",
"refresh_endpoint": "http://localhost:50244/vsbridge/user/refresh",
...
},
"stock": {
"endpoint": "http://localhost:50244/vsbridge/stock",
...
},
"images": {
"useExactUrlsNoProxy": true,
"baseUrl": "http://localhost:50244/vsbridge/image/",
...
},
...
}
An working example file can be found HERE
List of customized properties with example values:
{
"elasticsearch": {
"indices": [ "epi-catalog" ],
...
},
...
}
List of customized properties with example values:
<configuration>
<configSections>
...
<section name="vsf.export" type="EPiServer.Vsf.DataExport.Configuration.VsfExporterConfiguration, EPiServer.Vsf.DataExport"/>
<section name="vsf.apiBridge" type="EPiServer.Vsf.ApiBridge.VsfApiBridgeConfiguration, EPiServer.Vsf.ApiBridge"/>
</configSections>
...
<vsf.export
elasticServerUrls="http://127.0.0.1:9200"
indexAliasName="epi-catalog"
bulkIndexBatchSize="100" />
<vsf.apiBridge
auth.signingKey="alamakotaalamakotaalamakotaalamakota"
auth.issuer="quicksilver_issuer"
auth.audience="quicksilver_audience"
auth.accessTokenExpiration="60" />
Quicksilver to VSF export procedure.
- Before exporting make sure that:
1.1 VSF (vsf and vsf-api) is up and running
1.2 Quicksilver page is up and running - Navigate to EPiServer CMS Admin panel -> Scheduled Jobs -> Export to Vue Storefront
- Start Manually
After the job has finished, refresh VSF application - all product should be visible.
Quicksilver example default projects:
EPiServer.Reference.Commerce.Site
EPiServer.Reference.Commerce.Shared
EPiServer.Reference.Commerce.Manager
Actual Demo projects:
EPiServer.Vsf.Core - set of core models and interfaces
EPiServer.Vsf.ApiBridge - implementation of VSF web api bridge
EPiServer.Vsf.DataExport - implementation of exporting and model mapping algorithms
EPiServer.Reference.Commerce.VsfIntegration - quick silver customization. This project contains examples of custom model mappers (e.g. FashionProductMapper) and service adapters (e.g. QuickSilverUserAdapter).
- RefreshTokenRepository - Currently there is only one class that implements IRefreshTokenRepository interface, and it is MemoryRefreshTokenRepository.
- StockAdapter - QuickSilverStockAdapter is not fully implemented. The returned VsfStockCheck object is in grate part mocked.
- Placing order after checkout process with account creation does not properly assing order (due to userId) not being sent.
This project provides a set of base classes and interfaces used in project EPiServer.Vsf.ApiBridge and EPiServer.Vsf.DataExport. The intent is that One can override whole logic with custom implementation.
.
+-- ApiBridge - interfaces and models related to VueStoreFront Api bridge.
| +-- Adapter - adapter interfaces for managing users, cars and stock
| +-- Endpoint - api bridge interfaces
| +-- Model - models related to VueStoreFront Api bridge
| | +-- Authorization - related to authorization
| | +-- Cart - related to carts
| | +-- Stock - related to stock
| | +-- User - related to users
+-- Exporting - set of interfaces related to exporting
+-- Mapping - set of interfaces related to exporting
This project provides the implementation for VSF api bridge. VSF api description can be found HERE
.
+-- Authorization
| +-- Claims
| +-- Token
+-- Controllers
+-- Endpoints
+-- Utils
JwtBearerAuthentication middleware is used with custom token provider (VsfJwtBearerTokenProvider).
VsfJwtBearerTokenProvider class is able to extract Jwt token not only from Authorization header, but also from query string.
JwtUserTokenProvider class is responsible for generating access and refresh tokens.
More information about VSF authentication can be found HERE
POST /vsbridge/cart/create - implemented
GET /vsbridge/cart/pull - implemented
POST /vsbridge/cart/update - implemented
POST /vsbridge/cart/delete - implemented
POST /vsbridge/cart/apply-coupon - implemented (further testing needed)
POST /vsbridge/cart/delete-coupon - implemented (further testing needed)
GET /vsbridge/cart/coupon - implemented (further testing needed)
GET /vsbridge/cart/totals - implemented (further testing needed)
GET /vsbridge/cart/payment-methods - implemented (further testing needed)
POST /vsbridge/cart/shipping-methods - implemented (further testing needed)
POST /vsbridge/cart/shipping-information - implemented (further testing needed)
POST /vsbridge/cart/collect-totals - implemented (further testing needed)
POST /vsbridge/user/create - implemented
POST /vsbridge/user/login - implemented
POST /vsbridge/user/refresh - implemented
POST /vsbridge/user/resetPassword - implemented
POST /vsbridge/user/changePassword - implemented
GET /vsbridge/user/order-history - implemented (further testing needed)
GET /vsbridge/user/me - implemented
POST /vsbridge/user/me - implemented
GET /vsbridge/stock/check/:sku - partially implemented
POST /vsbridge/order/create - implemented (further testing needed)
This project provides support for exporting EPiServer Commerce models (mainly products, categories and variants) to Elasticsearch index, where it can consumed by VSF frontend app.
VSF is using model structure similar to Magento2, and it is assumed that the reader is familiar with both models structures: EPiServer Commerce, Magent2 and he understands the differences between them.
.
+-- Attributes
+-- Configuration
+-- Exporting
+-- Mapping - set for models mappers (from EPiServer models to VSF)
+-- Model - set of models suited for indexing in elasticsearch
+-- Utils
+-- Epi
ContentExtractor - is responsible for extracting data (nodes and products) from EpiServer Commerce. ExtractedContentHandler implements logic for handling that data (e.g. mapping to VSF model, indexing in Elasticsearch)
IndexingService - implements logic for indexing data in Elasticsearch
AttributeMapper, CategoryBaseMapper, ProjectBaseMapper - logic for mapping EPiServer Commerce models to VSF
VsfBaseProduct - base VSF product model that should be customized. (see QuicksilverVsfProduct)
QuicksilverVsfProduct - includes Quicksilver products specific properties (e.g. ColorOptions and SizeOptions)
QuicksilverProductMapper - customized mapping for Quicksilver products
QuicksilverNodeMapper - customized mapping for quicksilver nodes
CategoryTreeBuilder - is a helper class for mapping EPiServer NodeContent structure to VSF Category model
ContentPropertyReader - helper class for reading EPiServer Variants properties marked with VsfOptionAttribute
VsfOptionAttribute - is used to mark Variants properties that should be automatically mapped to VSF attributes model. (see EPiServer.Reference.Commerce.Shared.Models.Products.FashionVariant)
This project contains Quicksilver specific implementation (e.g. QuicksilverProductMapper, QuickSilverUserAdapter).
InitializationModule - InitializationModule that will setup DI for this demo
VueStorefrontExportJob - EPiServer job that executes model exporting
In SiteInitialization.ConfigureContainer:
GlobalConfiguration.Configure(config =>
{
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.LocalOnly;
config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings();
config.Formatters.XmlFormatter.UseXmlSerializer = true;
config.DependencyResolver = new StructureMapResolver(context.StructureMap());
config.MapHttpAttributeRoutes();
//REGISTER VSF API
config.RegisterVueStorefrontBridge();
});
In Infrastructure.Owin.Startup.Configuration
//REGISTER VSF AUTH
app.RegisterVueStorefrontAuth(ConfigurationManager.GetSection("vsf.apiBridge") as VsfApiBridgeConfiguration);