Skip to main content

From Zero to Hero

Step by step guide on how to integrate the MapColonies™ Config Management system into your service.

Assumptions

This guide assumes that you have an already existing service based on the MapColonies boilerplate repo, and basic knowledge of JSON Schema. If needed you can read and learn about JSON Schema in the following link: https://json-schema.org/understanding-json-schema.

It is also recommended to read the schemas package readme.

Before we start

In general, the implementation of the MapColonies™ Config Management system consists of the following steps:

  1. Work environment setup.
  2. Define a JSON Schema for your service configuration.
  3. Validating that the schema and the generated types are correct.
  4. Integrating the schema with your service. Below each step is explained in detail.

Initialize the work environment

  1. Clone the schemas repo into your own machine:
git clone git@github.com:MapColonies/schemas.git
  1. Change the working directory.
cd schemas
  1. Install the dependencies.
npm install
  1. Create a new branch for your schema.
git branch <my-branch-name>
  1. Open the repository in your editor (vscode for this guide).
code .
  1. Create a file for your schema under the schemas folder.

    The directory hierarchy represents the ID of the schema. For example, a common schema that handles redis configuration might be under schemas/common/redis/v1.schema.json and its id will be https://mapcolonies.com/common/redis/v1.

    The file name is based on the order of the schema. If it's the first one, the name should be v1.schema.json, otherwise it should be the next number in order.

Creating the schema

  1. Start by filling all the metadata for your JSON Schema. The more metadata you fill, it will be easier to understand and use your schema.
schemas/my-domain/my-schema/v1.schema.json
{
"$id": "https://mapcolonies.com/my-domain/my-schema/v1",
"type": "object",
"title": "myDomainMySchemaV1",
"description": "My domain's schema"
}
  1. Create your schema content. Use the official JSON Schema docs, The tips page and check other schemas in the repo for reference.
schemas/my-domain/my-schema/v1.schema.json
{
"$id": "https://mapcolonies.com/my-domain/my-schema/v1",
"type": "object",
"title": "myDomainMySchemaV1",
"description": "My domain's schema",
"properties": {
"id": {
"type": "string",
"description": "The unique identifier for the entity"
},
"name": {
"type": "string",
"description": "The name of the entity"
},
"age": {
"type": "integer",
"description": "The age of the entity",
"x-env-value": "ENTITY_AGE"
},
"isAlive": {
"type": "boolean",
"description": "Is the entity alive",
"x-env-value": "ENTITY_IS_ALIVE"
}
}
}
tip

You can use x-env-value to enable overriding the value of a field using environment variable. For more information check out the relevant docs in config and schemas.

  1. If we want our service schema to extend the base boilerplate schema we could do this like that:
{
"$id": "https://mapcolonies.com/my-domain/my-schema/v1",
"type": "object",
"title": "myDomainMySchemaV1",
"description": "My domain's schema",
"allOf": [
{
"$ref": "https://mapcolonies.com/common/boilerplate/v2"
},
{
"type": "object",
"properties": {
"myDomain": {
"$ref": "#/definitions/myDomainMySchemaV1"
}
}
}
],
"definitions": {
"myDomainMySchemaV1": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The unique identifier for the entity"
},
"name": {
"type": "string",
"description": "The name of the entity"
},
"age": {
"type": "integer",
"description": "The age of the entity",
"x-env-value": "ENTITY_AGE"
},
"isAlive": {
"type": "boolean",
"description": "Is the entity alive",
"x-env-value": "ENTITY_IS_ALIVE"
}
}
}
}
}

      The result is a combined object with both the boilerplate schema and our own properties.

important

When extending the boilerplate, you should check and make sure you extend the newest version. The version in this guide might be older.

Run validations

We want to make sure that the schema are valid, therefore we need to check the schema for errors. To do so we can run the following command and make changes based on the feedback.

npm run validate
info

To see all the validations check the following doc: https://github.com/MapColonies/schemas?tab=readme-ov-file#validations

Validating the types

The types that the schemas package exports are automatically generated from the json schema. We want to make sure that the types are correct before we move forward. This way we can check the types and if anything is wrong go back and fix the schema.

  1. Build the package:
npm run build
  1. Check that the types are as you expected. They can be found under the build directory under the same hierarchy as the schema. For example, those are the types generated for the schema we created above extending the boilerplate schema:
build/schemas/my-domain/my-schema/v1.schema.d.ts
import { typeSymbol } from '../../symbol.js';
declare const exported: {
readonly [typeSymbol]: {
[x: string]: unknown;
myDomain?: {
[x: string]: unknown;
id?: string | undefined;
name?: string | undefined;
age?: number | undefined;
isAlive?: boolean | undefined;
} | undefined;
openapiConfig: {
[x: string]: unknown;
filePath: string;
basePath: string;
rawPath: string;
uiPath: string;
};
telemetry: {
[x: string]: unknown;
logger: {
[x: string]: unknown;
level: "info" | "trace" | "debug" | "warn" | "error" | "fatal";
prettyPrint: boolean;
};
shared: {
[x: string]: unknown;
serviceName?: string | undefined;
serviceVersion?: string | undefined;
hostname?: string | undefined;
};
tracing: {
[x: string]: unknown;
debug?: boolean | undefined;
url?: string | undefined;
traceRatio?: number | undefined;
isEnabled: boolean;
};
};
server: {
[x: string]: unknown;
port: number;
request: {
[x: string]: unknown;
payload: {
[x: string]: unknown;
limit: string;
};
};
};
};
...
note

The rest of the file is important for the inner working of the schemas package. You should check only the types.

Checking integration with your service

Before merging the changes you made, we want to make sure it works with your service.

  1. install the development version of the schemas package into your service. There are multiple ways to achieve that, with some of them described below.

When opening a PR in the schemas repo, the latest version of your branch will be built and be available for a week.

  1. Push your changes to the remote repository.
git push --set-upstream origin <my-branch-name>
  1. Open a PR in the schemas repo.
  2. If all the validations pass, a comment will appear with instructions and link to the package.
  3. Insert the link into your service's package.json file.
package.json
{
"dependencies": {
"@map-colonies/schemas": <insert-generated-link>
}
}
  1. Install the package.
npm install

  1. Change the config in your service to use the new schema.
src/common/config.ts

import { type ConfigInstance, config } from '@map-colonies/config';
import { <your-new-schema>, type [your-new-schema-type] } from '@map-colonies/schemas';

// Choose here the type of the config instance and import this type from the entire application
type ConfigType = ConfigInstance<[your-new-schema-type]>;

let configInstance: ConfigType | undefined;

/**
* Initializes the configuration by fetching it from the server.
* This should only be called from the instrumentation file.
* @returns A Promise that resolves when the configuration is successfully initialized.
*/
async function initConfig(offlineMode?:boolean): Promise<void> {
configInstance = await config({
configName: 'boiler-config',
configServerUrl: 'http://localhost:8080',
schema: <your-new-schema>,
version: 'latest',
offlineMode: offlineMode
});
}
  1. Check that the service works as expected.

Next steps

Now that you finished writing your schema, you can submit a PR to the schemas repo and ask for it to be reviewed.

You can also check the default configs guide to learn how to define default configs for your schema.

We hope this guide was helpful and you were able to integrate the MapColonies™ Config Management system into your service.

If you have any questions or need help, feel free to ask for help.

If you have any suggestions for this guide, please open a pull request.