Skip to main content

๐Ÿฆธโ€โ™‚๏ธ From Zero to Hero

Welcome! This step-by-step guide will show you exactly how to integrate the MapColoniesโ„ข Config Management system into your service. Let's get you set up! ๐Ÿš€

๐Ÿง  Assumptionsโ€‹

We assume you have an existing service based on the MapColonies boilerplate repo and a solid grasp of JSON Schema. Need a refresher? Check out Understanding JSON Schema.

We highly recommend reading the schemas package readme before diving in.

๐Ÿ—บ๏ธ The Game Planโ€‹

Integrating the config management system requires just four high-level steps:

  1. Initialize: Set up your work environment.
  2. Define: Create a JSON Schema for your service configuration.
  3. Validate: Ensure your schema and generated types are structurally perfect.
  4. Integrate: Wire the schema into your service.

Let's break these down.


๐Ÿ—๏ธ 1. Initialize the Work Environmentโ€‹

  1. Clone the schemas repository:
git clone git@github.com:MapColonies/schemas.git
  1. Navigate into the directory:
cd schemas
  1. Install dependencies:
npm install
  1. Branch out: Create a new branch for your schema.
git branch <my-branch-name>
  1. Open your editor (VS Code recommended):
code .
  1. Create your schema file: Place your new file under the schemas folder. The folder hierarchy defines the ID of your schema. (Example: A schema handling Redis configuration might live at schemas/common/redis/v1.schema.json with the ID https://mapcolonies.com/common/redis/v1). Always start with v1.schema.json and increment sequentially for future versions.

โœ๏ธ 2. Creating the Schemaโ€‹

  1. Add Metadata: Start by filling out the JSON Schema metadata. Rich metadata makes your schema vastly easier for others to understand and use!
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. Add Properties: Build out your schema content. Use the official JSON Schema docs, our Tips page, and other repo schemas for inspiration!
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"
}
}
}
Environment Variables

Use x-env-value to allow overriding a field's value via environment variables! Read more in the config docs and schema docs.

  1. Extend the Boilerplate (Optional): Want your schema to inherit the base boilerplate schema? Simply combine them using allOf:
{
"$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"
}
}
}
}
}
Check Versions

When extending the boilerplate, always double-check that you are referencing the newest version!


โœ… 3. Run Validationsโ€‹

Let's ensure your schema is flawless. Run the validation script to catch any errors early:

npm run validate
Validation Rules

Curious what it checks? View all validation rules here.


๐Ÿ”Ž 4. Validating the Typesโ€‹

The types exported by the schemas package are auto-generated. Let's make sure they generated correctly!

  1. Build the package:
npm run build
  1. Inspect the types: Check the .d.ts files inside the build directory matching your schema hierarchy. Ensure your properties typed out correctly!
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;
} | undefined;
// ... (boilerplate types continue)
};

๐Ÿ”Œ 5. Integration With Your Serviceโ€‹

Before opening a PR, we need to test this locally inside your service.

1. Install your development schema package. You have a few options:

Opening a PR auto-builds a preview package valid for one week!

  1. Push your branch: git push --set-upstream origin <my-branch-name>
  2. Open a PR in the schemas repo.
  3. Copy the generated preview link from the PR comment.
  4. Add it to your service's package.json:
package.json
{
"dependencies": {
"@map-colonies/schemas": "<insert-generated-link>"
}
}
  1. Run npm install.

2. Update your service configuration.

src/common/config.ts
import { type ConfigInstance, config } from '@map-colonies/config';
import { myDomainMySchemaV1, type myDomainMySchemaV1Type } from '@map-colonies/schemas';

// Define the global config type
type ConfigType = ConfigInstance<myDomainMySchemaV1Type>;

let configInstance: ConfigType | undefined;

/**
* Initializes the configuration. Call this early in instrumentation!
*/
async function initConfig(offlineMode?: boolean): Promise<void> {
configInstance = await config({
configName: 'boiler-config',
configServerUrl: 'http://localhost:8080',
schema: myDomainMySchemaV1,
version: 'latest',
offlineMode: offlineMode
});
}
Naming Convention Magic!

Your exported schema names are automatically derived from the $id. https://mapcolonies.com/my-domain/my-schema/v1 automatically becomes myDomainMySchemaV1 and myDomainMySchemaV1Type.

๐ŸŽฏ Next Stepsโ€‹

You did it! ๐ŸŽ‰

  • Submit your PR to the schemas repo for review.
  • Check out the Default Configs guide to learn how to ship safe defaults.