diff --git a/packages/core/core/__tests__/factories/proxyUtils.spec.ts b/packages/core/core/__tests__/factories/proxyUtils.spec.ts deleted file mode 100644 index 0a78f9d38e..0000000000 --- a/packages/core/core/__tests__/factories/proxyUtils.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ - -import * as utils from './../../src/utils/nuxt/_proxyUtils'; -import isHttps from 'is-https'; - -jest.mock('is-https'); - -describe('[CORE - factories] apiFactory/_proxyUtils', () => { - it('returns base url based on incomming headers', () => { - expect(utils.getBaseUrl(null)).toEqual('/api/') - - ;(isHttps as jest.Mock).mockReturnValue(true); - expect(utils.getBaseUrl({ headers: { host: 'some-domain' } } as any)).toEqual('https://some-domain/api/') - - ;(isHttps as jest.Mock).mockReturnValue(false); - expect(utils.getBaseUrl({ headers: { host: 'some-domain' } } as any)).toEqual('http://some-domain/api/') - - ;(isHttps as jest.Mock).mockReturnValue(true); - expect(utils.getBaseUrl({ headers: { host: 'some-domain', 'x-forwarded-host': 'forwarded-host' } } as any)).toEqual('https://forwarded-host/api/') - - ;(isHttps as jest.Mock).mockReturnValue(false); - expect(utils.getBaseUrl({ headers: { host: 'some-domain', 'x-forwarded-host': 'forwarded-host' } } as any)).toEqual('http://forwarded-host/api/'); - }); - - it('returns proxy for defined api', () => { - const givenApi = { - getProduct: jest.fn() - }; - - const client = { - post: jest.fn(() => ({ then: jest.fn() })) - }; - - const proxiedApi = utils.createProxiedApi({ givenApi, client, tag: 'ct' }); - - proxiedApi.getProduct({ product: 1 }); - proxiedApi.getCategory({ category: 1 }); - - expect(givenApi.getProduct).toBeCalled(); - expect(client.post).toBeCalledWith('/ct/getCategory', [{ category: 1 }]); - }); - - it('reads cookies from incomming request', () => { - expect(utils.getCookies(null)).toEqual(''); - expect(utils.getCookies({} as any)).toEqual(''); - expect(utils.getCookies({ req: { headers: {} } } as any)).toEqual(''); - expect(utils.getCookies({ req: { headers: { cookie: { someCookie: 1 } } } } as any)).toEqual({ someCookie: 1 }); - }); - - it('it cobines config with the current one', () => { - jest.spyOn(utils, 'getCookies').mockReturnValue(''); - jest.spyOn(utils, 'getBaseUrl').mockReturnValue('some-url'); - - expect(utils.getIntegrationConfig( - null, - { someGivenOption: 1 } - )).toEqual({ - axios: { - baseURL: 'some-url', - headers: {} - }, - someGivenOption: 1 - }); - }); - - it('it cobines config with the current one and adds a cookie', () => { - jest.spyOn(utils, 'getCookies').mockReturnValue('xxx'); - jest.spyOn(utils, 'getBaseUrl').mockReturnValue('some-url'); - - expect(utils.getIntegrationConfig( - null, - {} - )).toEqual({ - axios: { - baseURL: 'some-url', - headers: { - cookie: 'xxx' - } - } - }); - }); -}); diff --git a/packages/core/core/__tests__/utils/nuxt/proxyUtils.spec.ts b/packages/core/core/__tests__/utils/nuxt/proxyUtils.spec.ts new file mode 100644 index 0000000000..e6202a4593 --- /dev/null +++ b/packages/core/core/__tests__/utils/nuxt/proxyUtils.spec.ts @@ -0,0 +1,82 @@ +import * as utils from '../../../src/utils/nuxt/_proxyUtils'; + +describe('[CORE - utils] _proxyUtils', () => { + it('returns proxy for defined api', () => { + const givenApi = { + getProduct: jest.fn() + }; + + const client = { + post: jest.fn(() => ({ then: jest.fn() })) + }; + + const proxiedApi = utils.createProxiedApi({ givenApi, client, tag: 'ct' }); + + proxiedApi.getProduct({ product: 1 }); + proxiedApi.getCategory({ category: 1 }); + + expect(givenApi.getProduct).toBeCalled(); + expect(client.post).toBeCalledWith('/ct/getCategory', [{ category: 1 }]); + }); + + it('reads cookies from incoming request', () => { + expect(utils.getCookies(null)).toEqual(''); + expect(utils.getCookies({} as any)).toEqual(''); + expect(utils.getCookies({ req: { headers: {} } } as any)).toEqual(''); + expect(utils.getCookies({ req: { headers: { cookie: { someCookie: 1 } } } } as any)).toEqual({ someCookie: 1 }); + }); + + it('it combines config with the current one', () => { + jest.spyOn(utils, 'getCookies').mockReturnValue(''); + + expect(utils.getIntegrationConfig( + { + $config: { + middlewareUrl: 'some-url' + } + } as any, + { someGivenOption: 1 } + )).toEqual({ + axios: { + baseURL: 'some-url', + headers: {} + }, + someGivenOption: 1 + }); + }); + + it('it combines config with the current one and adds a cookie', () => { + jest.spyOn(utils, 'getCookies').mockReturnValue('xxx'); + + expect(utils.getIntegrationConfig( + { + $config: { + middlewareUrl: 'some-url' + } + } as any, + {} + )).toEqual({ + axios: { + baseURL: 'some-url', + headers: { + cookie: 'xxx' + } + } + }); + }); + + it('it throws error when no middlewareUrl is passed in config', () => { + jest.spyOn(utils, 'getCookies').mockReturnValue(''); + + expect(() => { + utils.getIntegrationConfig( + { + $config: { + middlewareUrl: '' + } + } as any, + {} + ); + }).toThrowError(); + }); +}); diff --git a/packages/core/core/src/utils/nuxt/_proxyUtils.ts b/packages/core/core/src/utils/nuxt/_proxyUtils.ts index 093830e61e..168e029bc0 100644 --- a/packages/core/core/src/utils/nuxt/_proxyUtils.ts +++ b/packages/core/core/src/utils/nuxt/_proxyUtils.ts @@ -1,4 +1,3 @@ -import { IncomingMessage } from 'http'; import { Context as NuxtContext } from '@nuxt/types'; import merge from 'lodash-es/merge'; import { ApiClientMethod } from './../../types'; @@ -9,16 +8,6 @@ interface CreateProxiedApiParams { tag: string; } -export const getBaseUrl = (req: IncomingMessage, basePath: string | undefined = '/'): string => { - if (!req) return `${basePath}api/`; - const { headers } = req; - const isHttps = require('is-https')(req); - const scheme = isHttps ? 'https' : 'http'; - const host = headers['x-forwarded-host'] || headers.host; - - return `${scheme}://${host}${basePath}api/`; -}; - export const createProxiedApi = ({ givenApi, client, tag }: CreateProxiedApiParams) => new Proxy(givenApi, { get: (target, prop, receiver) => { @@ -37,9 +26,15 @@ export const getCookies = (context: NuxtContext) => context?.req?.headers?.cooki export const getIntegrationConfig = (context: NuxtContext, configuration: any) => { const cookie = getCookies(context); + const { middlewareUrl } = context.$config; + + if (!middlewareUrl) { + throw new Error('Missing configuration option: middlewareUrl'); + } + const initialConfig = merge({ axios: { - baseURL: getBaseUrl(context?.req, context?.base), + baseURL: middlewareUrl, headers: { ...(cookie ? { cookie } : {}) } diff --git a/packages/core/core/src/utils/nuxt/index.ts b/packages/core/core/src/utils/nuxt/index.ts index 9ca1d86b3a..4389c24186 100644 --- a/packages/core/core/src/utils/nuxt/index.ts +++ b/packages/core/core/src/utils/nuxt/index.ts @@ -25,12 +25,6 @@ export const integrationPlugin = (pluginFn: NuxtPlugin) => (nuxtCtx: NuxtContext const configure = (tag, configuration) => { const injectInContext = createAddIntegrationToCtx({ tag, nuxtCtx, inject }); const config = getIntegrationConfig(nuxtCtx, configuration); - const { middlewareUrl, ssrMiddlewareUrl } = (nuxtCtx as any).$config; - - if (middlewareUrl) { - config.axios.baseURL = process.server ? ssrMiddlewareUrl || middlewareUrl : middlewareUrl; - } - const client = axios.create(config.axios); const api = createProxiedApi({ givenApi: configuration.api || {}, client, tag }); diff --git a/packages/core/docs/changelog/6680.js b/packages/core/docs/changelog/6680.js new file mode 100644 index 0000000000..c05b84997c --- /dev/null +++ b/packages/core/docs/changelog/6680.js @@ -0,0 +1,15 @@ +module.exports = { + description: 'get api host from middleware url', + link: 'https://github.com/vuestorefront/vue-storefront/pull/6680', + isBreaking: true, + breakingChanges: [ + { + module: '@vue-storefront/core', + before: 'The `middlewareUrl` property was optional', + after: 'The `middlewareUrl` is required', + comment: 'The `middlewareUrl` property in the `nuxt.config.js` file is now required. Please follow the instruction in the Migration Guide.' + } + ], + author: 'Dawid Ziobro', + linkToGitHubAccount: 'https://github.com/dawid-ziobro' +}; diff --git a/packages/core/docs/getting-started/configuration.md b/packages/core/docs/getting-started/configuration.md index d0be8248e6..00e372d42f 100644 --- a/packages/core/docs/getting-started/configuration.md +++ b/packages/core/docs/getting-started/configuration.md @@ -16,6 +16,21 @@ You can learn more about this file and available configuration options on the [N The `middleware.config.js` file is as essential as `nuxt.confis.js`, but much simpler and likely smaller. It configures the Server Middleware used for communication with e-commerce platforms and contains sensitive credentials, custom endpoints, queries, etc. +What is typical for every integration is the `middlewareUrl` property which defines the URL to the Server Middleware. Usually, it's your application domain followed by the `/api` path. + +Example: + +```javascript +// nuxt.config.js +export default { + publicRuntimeConfig: { + middlewareUrl: 'https://yourdomain.com/api/' + } +} +``` + +For the local development, set it to `http://localhost:3000/api/`. + You can learn more about Server Middleware and available configuration options on the [Server Middleware](/architecture/server-middleware.html) page. ## Optional configuration files diff --git a/packages/core/docs/reference/migrate/2.5.7/overview.md b/packages/core/docs/reference/migrate/2.5.7/overview.md new file mode 100644 index 0000000000..812cecc7f3 --- /dev/null +++ b/packages/core/docs/reference/migrate/2.5.7/overview.md @@ -0,0 +1,39 @@ +# Migrating projects to 2.5.7 + +## Update `nuxt.config.js` + +In this release, we made the `middlewareUrl` property required for security reasons. Open the `nuxt.config.js` file and add the `middlewareUrl` property like shown below: + +```javascript +// nuxt.config.js +export default { + publicRuntimeConfig: { + middlewareUrl: 'https://yourdomain.com/api/' // For the local development, set it to `http://localhost:3000/api/`. + } +} +``` + +:::warning +Make sure to pass whole url with protocol and/or port and suffix it with `/api/`. +::: + +If you don't want to hardcode the URL in the configuration file, you can use environmental variables. + +Example: + +```javascript +// nuxt.config.js +export default { + publicRuntimeConfig: { + middlewareUrl: process.env.API_BASE_URL + } +} +``` + +Then add an entry in the `.env` file or use any other method for passing environmental variables that suits your needs. + +Example: +``` +// .env +API_BASE_URL=https://yourdomain.com/api/ +``` diff --git a/packages/core/docs/reference/migrate/index.md b/packages/core/docs/reference/migrate/index.md index 12468f0cfd..fd9110e41c 100644 --- a/packages/core/docs/reference/migrate/index.md +++ b/packages/core/docs/reference/migrate/index.md @@ -1,5 +1,8 @@ # Migration guides +## 2.5.7 +- [Overview](./2.5.7/overview.md) + ## 2.5.0 - [Overview](./2.5.0/overview.md)