vuestorefront / vue-storefront

Alokai is a Frontend as a Service solution that simplifies composable commerce. It connects all the technologies needed to build and deploy fast & scalable ecommerce frontends. It guides merchants to deliver exceptional customer experiences quickly and easily.
https://www.alokai.com
MIT License
10.64k stars 2.08k forks source link

Mutliwebsite support for the vue-storefront-api #1135

Closed pkarw closed 6 years ago

pkarw commented 6 years ago

Regarding #1134

If we add a global URL parameter - like: /api/:store_code/user/login as an addition to current routes: /api/user/login we'll be able to run the multi-website configuration of the vue-storefront-api

OR we can set the store_code as an HTTP header - like X-VS-Store - which is probably the easier way to handle the vue-storefront part (see below - the second step)

The second thing is to modify the default.json config and then the api adapter instantiation. Currently, we have the config like this:

    "elasticsearch": {
      "httpAuth": "",
      "host": "localhost:8080/api/catalog",
      "index": "vue_storefront_catalog"
    },
    "magento2": {
        "url": "http://magento2.demo-1.xyz.com",
        "imgUrl": "http://localhost:8080/media/catalog/product",
        "assetPath": "/../var/magento2-sample-data/pub/media",
        "magentoUserName": "",
        "magentoUserPassword": "",
        "httpUserName": "",
        "httpUserPassword": "",
        "api": {
            "url": "http://demo-magento2.vuestorefront.io/rest",
            "consumerKey": "byv3730rhoulpopcq64don8ukb8lf2gq",
            "consumerSecret": "u9q4fcobv7vfx9td80oupa6uhexc27rb",
            "accessToken": "040xx3qy7s0j28o3q0exrfop579cy20m",
            "accessTokenSecret": "7qunl3p505rubmr7u1ijt7odyialnih9"
        }
    },

What we need to have is:

    "elasticsearch": {
      "httpAuth": "",
      "host": "localhost:8080/api/catalog",
      "index": "vue_storefront_catalog"
    },
    "magento2": {
        "url": "http://magento2.demo-1.xyz.com",
        "imgUrl": "http://localhost:8080/media/catalog/product",
        "assetPath": "/../var/magento2-sample-data/pub/media",
        "magentoUserName": "",
        "magentoUserPassword": "",
        "httpUserName": "",
        "httpUserPassword": "",
        "api": {
            "url": "http://demo-magento2.vuestorefront.io/rest",
            "consumerKey": "byv3730rhoulpopcq64don8ukb8lf2gq",
            "consumerSecret": "u9q4fcobv7vfx9td80oupa6uhexc27rb",
            "accessToken": "040xx3qy7s0j28o3q0exrfop579cy20m",
            "accessTokenSecret": "7qunl3p505rubmr7u1ijt7odyialnih9"
        }
    },

"stores": {
  "en": {
    "elasticsearch": {
      "httpAuth": "",
      "host": "localhost:8080/api/catalog",
      "index": "vue_storefront_catalog_en"
    },
    "magento2": {
        "url": "http://magento2.demo-1.xyz.com/en",
        "imgUrl": "http://localhost:8080/media/catalog/product",
        "assetPath": "/../var/magento2-sample-data/pub/media",
        "magentoUserName": "",
        "magentoUserPassword": "",
        "httpUserName": "",
        "httpUserPassword": "",
        "api": {
            "url": "http://demo-magento2.vuestorefront.io/en/rest",
            "consumerKey": "byv3730rhoulpopcq64don8ukb8lf2gq",
            "consumerSecret": "u9q4fcobv7vfx9td80oupa6uhexc27rb",
            "accessToken": "040xx3qy7s0j28o3q0exrfop579cy20m",
            "accessTokenSecret": "7qunl3p505rubmr7u1ijt7odyialnih9"
        }
    },
}

}

So - to have the default config + config per store. If the api is called with the "store_code" paramter - we simple are querying the different ES index + differnt rest api endpoints

In the second step - we need to add the parameter to the vue-storefront config: changing the vue-storefront/config/default.json from:

    "elasticsearch": {
      "httpAuth": "",
      "host": "localhost:8080/api/catalog",
      "index": "vue_storefront_catalog"
    },
    "i18n": {
      "defaultCountry": "US",
      "defaultLanguage": "EN",
      "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "jp-JP", "ru-RU", "it-IT", "pt-BR"],
      "defaultLocale": "en-US",
      "currencyCode": "USD",
      "currencySign": "$",
      "dateFormat": "HH:mm D/M/YYYY"
    },
...

to:

    "elasticsearch": {
      "httpAuth": "",
      "host": "localhost:8080/api/catalog",
      "index": "vue_storefront_catalog"
    },
    "storeCode": "",
"stores": {
"en": {
    "storeCode": "en",
    "title": "English store",
    "url": "",
    "iconUrl": "",
    "elasticsearch": {
      "httpAuth": "",
      "host": "localhost:8080/api/catalog",
      "index": "vue_storefront_catalog"
    },
    "i18n": {
      "defaultCountry": "US",
      "defaultLanguage": "EN",
      "availableLocale": ["en-US","de-DE","fr-FR","es-ES","nl-NL", "jp-JP", "ru-RU", "it-IT", "pt-BR"],
      "defaultLocale": "en-US",
      "currencyCode": "USD",
      "currencySign": "$",
      "dateFormat": "HH:mm D/M/YYYY"
    },
}
}
...

.. and change it in all the occurences.

Then we need to change the API endpoints by adding the store_code to the URL of the API endpoint or as a header (regarding which option has been chosen in the step 1).

If we like to change the urls we need to change:

   "cart": {
      "server_merge_by_default": true,
      "synchronize": false,
      "synchronize_totals": false,
      "setCustomProductOptions": true,
      "setConfigurableProductOptions": true,
      "create_endpoint": "http://localhost:8080/api/cart/create?token={{token}}",
      "updateitem_endpoint": "http://localhost:8080/api/cart/update?token={{token}}&cartId={{cartId}}",
      "deleteitem_endpoint": "http://localhost:8080/api/cart/delete?token={{token}}&cartId={{cartId}}",
      "pull_endpoint": "http://localhost:8080/api/cart/pull?token={{token}}&cartId={{cartId}}",
      "totals_endpoint": "http://localhost:8080/api/cart/totals?token={{token}}&cartId={{cartId}}",
      "paymentmethods_endpoint": "http://localhost:8080/api/cart/payment-methods?token={{token}}&cartId={{cartId}}",
      "shippingmethods_endpoint": "http://localhost:8080/api/cart/shipping-methods?token={{token}}&cartId={{cartId}}",
      "shippinginfo_endpoint": "http://localhost:8080/api/cart/shipping-information?token={{token}}&cartId={{cartId}}",
      "collecttotals_endpoint": "http://localhost:8080/api/cart/collect-totals?token={{token}}&cartId={{cartId}}",
      "deletecoupon_endpoint": "http://localhost:8080/api/cart/delete-coupon?token={{token}}&cartId={{cartId}}",
      "applycoupon_endpoint": "http://localhost:8080/api/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"
    },

to sth like:

   "cart": {
      "server_merge_by_default": true,
      "synchronize": false,
      "synchronize_totals": false,
      "setCustomProductOptions": true,
      "setConfigurableProductOptions": true,
      "create_endpoint": "http://localhost:8080/api{{store_code}}/cart/create?token={{token}}",
      "updateitem_endpoint": "http://localhost:8080/api{{store_code}}/cart/update?token={{token}}&cartId={{cartId}}",
      "deleteitem_endpoint": "http://localhost:8080/api{{store_code}}/cart/delete?token={{token}}&cartId={{cartId}}",
      "pull_endpoint": "http://localhost:8080/api{{store_code}}/cart/pull?token={{token}}&cartId={{cartId}}",
      "totals_endpoint": "http://localhost:8080/api{{store_code}}/cart/totals?token={{token}}&cartId={{cartId}}",
      "paymentmethods_endpoint": "http://localhost:8080/api{{store_code}}/cart/payment-methods?token={{token}}&cartId={{cartId}}",
      "shippingmethods_endpoint": "http://localhost:8080/api{{store_code}}/cart/shipping-methods?token={{token}}&cartId={{cartId}}",
      "shippinginfo_endpoint": "http://localhost:8080/api{{store_code}}/cart/shipping-information?token={{token}}&cartId={{cartId}}",
      "collecttotals_endpoint": "http://localhost:8080/api{{store_code}}/cart/collect-totals?token={{token}}&cartId={{cartId}}",
      "deletecoupon_endpoint": "http://localhost:8080/api{{store_code}}/cart/delete-coupon?token={{token}}&cartId={{cartId}}",
      "applycoupon_endpoint": "http://localhost:8080/api{{store_code}}/cart/apply-coupon?token={{token}}&cartId={{cartId}}&coupon={{coupon}}"
    },

... and change the core/scripts/installer.js accordingly. Please note that we have api{{store_code}}/ and not api/{{store_code}} to support the default situation when no store-code is provided because of the last step :)

Last step we need to is to add store_code to the network calls:

https://github.com/DivanteLtd/vue-storefront/blob/ecd5eb0a7eddc112342771587bf3ac0e868feb00/core/store/lib/task.js#L27

We can use just the .. replace method to replace {{store_code}} with the currently selected store.

The current store selector is a different task: https://github.com/DivanteLtd/vue-storefront/issues/881

The currently selected store should be saved in the localForage:

  const usersCollection = global.$VS.db.usersCollection
  usersCollection.setItem('current-store', '')

and in the store.state.user.currentStore vuex variable

pkarw commented 6 years ago

Done in the https://github.com/pkarw/vue-storefront/commits/feature/1135_multistore https://github.com/DivanteLtd/vue-storefront-api/tree/feature/1135_multistore