Specify environment-specific configuration values for an application
OSF provides a mechanism that you can use to create separate application configuration for development, test, and production environments, and to automatically apply the correct configuration for whichever environment the application is currently running in.
Configuration files
A workspace includes an index.js
configuration file in its
node_modules/@oracle-cx-commerce/osf-config/app-config/
directory. The
settings in this file apply by default to all of the applications in the workspace.
The settings in the configuration files are specified as JSON key/value pairs. The default configuration file contains the following settings:
module.exports = {
cacheEnabled: true, // whether to enable cache or not
cacheOptions: {
validityPeriod: 2 * 60 * 1000, // validity period of the req to be in cache. If expired, the request goes to OCC for re-validation.
ttl: 30 * 60, // if expired, the response against respective request stored in cache gets removed.
max: 99999, // maximum objects to be stored in the cache.
cacheableUrlPatterns: {
// url patterns for which the urls should be cached. If the url doesn't fall under any of these, it is not cache-able.
default: {
urlPatterns: [
'/ccstore/v1/collections',
'/ccstore/v1/countries',
'/ccstore/v1/files/',
'/ccstore/v1/itemTypes',
'/ccstore/v1/locations',
'/ccstore/v1/merchant/cancelReasons',
'/ccstore/v1/merchant/cloudConfiguration',
'/ccstore/v1/merchant/paymentConfigurations',
'/ccstore/v1/merchant/production-Experiments',
'/ccstore/v1/merchant/production-Facebook',
'/ccstore/v1/merchant/returnReasons',
'/ccstore/v1/merchant/samlSettings',
'/ccstore/v1/merchant/shopperSettings',
'/ccstore/v1/payment/types',
'/ccstore/v1/priceListGroups',
'/ccstore/v1/prices/',
'/ccstore/v1/products',
'/ccstore/v1/productTypes',
'/ccstore/v1/registry',
'/ccstore/v1/shippingRegions',
'/ccstore/v1/shippingMethods/',
'/ccstore/v1/sites',
'/ccstore/v1/xregistry'
]
}
}
}
};
To override settings in this file or create additional configuration, you
should not modify the default configuration file directly, because the values in the file
will be restored if you perform certain operations in the workspace. Instead, create an
application-specific index.js
file in the packages/apps/<app-name>/config/app-config/
directory. When an
application is started up, the system checks for this file, and if it exists, merges it in
memory with the default configuration to produce the configuration for the application. Both
files are packaged up with the application and uploaded to the Commerce environment and OSF
controllers.
You can use predefined properties for application-specific settings in this file, as well as custom keys to specify additional configuration. The predefined properties available include:
configRepositoryState
– This object appears at the top level of the merged configuration. It contains settings for the client state, which are loaded at runtime.endpointOrigins
– This object specifies mappings of keys to associated URL domains for calling endpoints.liveConfigurations
– This object contains settings that supplement or modify the merged configuration if the application is running in live mode.appContextConfigurations
– This object containsdevelopment
,test
, andproduction
subobjects. Depending on the application context the application is running in, the settings in the associated subobject are merged with the configuration.
These properties are discussed below.
Local development mode
If the application is running in local development mode, the
system also checks for a config.js
file in the
packages/apps/<app-name>/.occ/
directory. If the file exists, the configuration in it is merged as well. This file can
include the same predefined properties listed above. The file is not included with the
application when it is uploaded, since it applies only to local development
environments.
The next section describes the logic used in merging the configuration in memory and how to create application-specific configuration files based on this logic.
How the configuration is merged
When configuration is merged, the properties from multiple sources are combined in memory to create the configuration for the application. Properties that do not conflict are simply added to the configuration, while properties that are specified in multiple sources must be resolved to determine which values to use.
You can set the same property to different values in multiple configuration
files or even in multiple places in the same configuration file. When configuration is
merged in memory, the system can override values with ones that apply in specific contexts.
This section illustrates how the configuration is merged, using examples of
application-specific index.js
files.
Note that overriding values applies only to top-level properties in the merged configuration. So overriding a scalar property simply replaces the property value in the merged configuration, but overriding a top-level property whose value is an object replaces the object in its entirety, including any subobjects. Properties within objects are not added or overridden individually.
In the following example, the application-specific
configuration file includes configRepositoryState
and
endpointOrigins
settings as well as custom properties:
module.exports = {
// Values to add to the client state
"configRepositoryState": {
"client-state-value-1": 1,
"client-state-value-2": [1000, 2000, 3000],
"client-state-value-3": {
"pizza": "cheese",
"topping": ["olives"]
}
},
// Endpoint Origins for constructing endpoint calls
"endpointOrigins": {
"pizza-endpoint": {
"origin": "https://development.pizza-endpoint.com"
}
},
// Top-Level Custom Properties
"example-top-level-property-string": "sample-value",
"example-top-level-property-array": ["string-1", "string-2"],
"example-top-level-property-object": {
"object-key-a": "nested-object-string",
"object-key-b": [ "value-1", "value-2"],
"object-key-c": { "arg1": 1, "arg2": 2 }
},
};
The default configuration file does not contain a
configRepositoryState
or endpointOrigins
object, so
these objects in the application-specific settings are added to the merged configuration
without overriding anything. The same is true for the custom properties in the
application-specific file. You can use application-specific values to override settings from
the default configuration file, but typically the default settings can be left as is.
Merge a live object
liveConfigurations
object to
the application-specific file shown
above:
// Merged with above when --live flag is turned on
"liveConfigurations": {
"example-top-level-property-string": "override-sample-value",
"configRepositoryState": {
"client-state-value-1": 777,
"client-state-live-value": "in client state when live flag is turned on"
}
}
The liveConfigurations
object contains settings that are
merged into the configuration only if the application is running in live mode. (They are
omitted if the application is run in preview mode.) The live settings are merged if the
application is running on a live controller, or if it is running locally and is started up
with the --live
flag.
In this example, the properties in the liveConfigurations
object override the equivalent top-level properties in the merged configuration. The value
of the example-top-level-property-string
property is changed from
sample-value
to override-sample-value
in the merged
configuration, and the entire top-level configRepositoryState
object is
replaced by the one under liveConfigurations
.
Context-specific configuration
In addition to the settings in the examples above, the application-specific
configuration file can also have an appContextConfigurations
object that
includes settings that are merged conditionally, depending on the environment (development,
test, or production) the application is running in. For example:
"appContextConfigurations": {
// will be merged with top-level properties when --appContext development or ENV_TYPE=DEV
"development": {
"example-top-level-property-string": "sample-value-development",
"configRepositoryState": {
"client-state-value-1": 333
},
// Merged with above when --live flag is turned on
"liveConfigurations": {
"example-top-level-property-string": "override-sample-value-development-live"
}
},
// will be merged with top-level properties when --appContext test or ENV_TYPE=TST
"test": {
"example-top-level-property-string": "sample-value-test",
"configRepositoryState": {
"client-state-value-1": 444
},
// Merged with above when --live flag is turned on
"liveConfigurations": {
"example-top-level-property-string": "override-sample-value-test-live"
}
},
// will be merged with top-level properties when --appContext test or ENV_TYPE=PRD
"production": {
"example-top-level-property-string": "sample-value-production",
"configRepositoryState": {
"client-state-value-1": 555
},
// Merged with above when --live flag is turned on
"liveConfigurations": {
"example-top-level-property-string": "override-sample-value-production-live"
}
}
}
As this example shows, the appContextConfigurations
object
can have development
, test
, and
production
subobjects. When the application is started up, the settings
associated with the environment the application is running in are merged. The environment is
determined by an environment variable on the controller, or by the
--appContext
flag if the application is started up locally.
In this example, if the application is running in the test environment, the
test
object is merged. The value of
example-top-level-property-string
is changed to
sample-value-test
, and the configRepositoryState
object
in test
overrides the top-level configRepositoryState
.
Notice, though, that each environment-specific object can also have a
liveConfigurations
subobject. If the application is running in live mode,
the liveConfigurations
subobject is merged after the rest of the
environment-specific object. In this example, merging the
liveConfigurations
subobject changes the value of
example-top-level-property-string
to
override-sample-value-test-live
.
Finally, if an application is running in local development mode, the
packages/apps/<app-name>/.occ/
file is also
merged. This file can also contain config.js
configRepositoryState
,
endpointOrigins
, liveConfigurations
, and
appContextConfigurations
objects, as well as custom properties, to
override or supplement the properties set elsewhere.
View the merged configuration
You can debug the merged configuration to ensure that it is what you expect it to be. To do this, enter the following command to display the configuration without starting up the application:
yarn occ serve --listConfig
When you use the serve
command with the
--listConfig
flag, you can also use other command-line flags to specify
the application context. These settings override the values supplied in environment
variables and in the workspace's .occ/config.js
file. For example, the
following command returns the merged configuration for running an application in the live
context of the test environment:
yarn occ serve --listConfig --live --appContext test
Endpoint origins
The endpointOrigins
object provides a way to store the base
URLs for endpoints in application configuration files. This makes it possible to override
these URLs on a context-specific basis.
When you create endpoints from a Swagger catalog using the
create-endpoint
command, an entry is automatically added to the top-level
endpointOrigins
object of the application's
/config/app-config/index.js
file. (If the file does not already exist, it
is created automatically.) For example, you can create an endpoint like this:
yarn occ create-endpoint --directoryName my-endpoints --swagger http://www.example.com/catalogApi --endpoints getOrder
An entry for the specified directory name (in this case,
my-endpoints
) is added to the file:
"endpointOrigins": {
"my-endpoints": {
"origin": "http://www.example.com/catalogApi:443"
}
}
The value of the origin
property is set to value of the
host
property in the Swagger catalog. If the location specified with the
--swagger
flag does not exactly match the value from the catalog, the
entry also includes a catalogOrigin
property with the specified value. For
example:
"endpointOrigins": {
"my-endpoints": {
"origin": "http://www.example.com/catalogApi:443",
"catalogOrigin": "http://www.example.com/catalogApi"
}
}
For more information about using the create-endpoint
command,
see Create components using command-line tools.
Context-specific endpoint origins
By default, the endpointOrigins
settings apply to all environments, but
you can override them for specific environments using the
appContextConfigurations
object. For example, if the production
environment accesses the Swagger catalog in a different location, you might specify:
"appContextConfigurations": {
"production": {
"endpointOrigins": {
"my-endpoints": {
"origin": "http://www.example.com/PRODcatalogApi"
}
}
}
}