-
Notifications
You must be signed in to change notification settings - Fork 1
Node.js Cody Tutorial Exercise II
Exercise I introduced the core functionality of Cody. You can model business logic on an event map using Event Storming semantics and generate source code from it. So far we only generated an empty interface. But Cody offers much more than that! In Exercise II you'll learn how to use Card Metadata to define a schema and derive properties from it.
Execute docker-compose run --rm exercises npm run exercise2
to see what we have to do next.
We're asked to add a buildingId
and a name
property (both of type string
) to the AddBuilding
command. Now it would be easy to just open the file and add those two properties. But we should expand our code generation logic instead. This has some significant advantages:
- an InspectIO event map acts as documentation
- one can generate contracts like an OpenAPI schema from Card Metadata
- it is easier to discuss and design new features or refactorings when such details are included on the event map
Ok let's use a simple code generator implementation first to understand the basics. In a later tutorial part we'll look at some useful libraries that provide abstractions for advanced use cases.
Change the command hook in cody-tutorial/cody-bot/src/hooks/onCommandHook.ts
like this:
import {CodyHook} from "../board/code";
import {Node} from "../board/graph";
import {CodyResponse, CodyResponseType, isCodyError} from "../general/response";
import {nodeNameToPascalCase} from "../utils/string";
import {Context} from "./Context";
import {writeFileSync} from "../utils/filesystem";
import {parseJsonMetadata} from "../utils/metadata";
/**
* onCommandHook
*
* @param {Node} command Information about command card received from InspectIO
* @param {Context} ctx Context object populated in codyconfig.ts
* @returns Promise<CodyResponse>
*/
export const onCommandHook: CodyHook<Context> = async (command: Node, ctx: Context): Promise<CodyResponse> => {
// Cody ships with some util functions for common tasks
const cmdName = nodeNameToPascalCase(command);
const cmdFilename = cmdName+'.ts';
// ctx.srcFolder is set in codyconfig.ts
const cmdFile = ctx.srcFolder + `/Command/${cmdFilename}`;
let successDetails = 'Checklist\n\n';
const commandMetadata = parseJsonMetadata<{[prop: string]: string}>(command);
if(isCodyError(commandMetadata)) {
return commandMetadata;
}
if(typeof commandMetadata !== 'object') {
// You can return your own error responses, too
return {
cody: `I expected metadata of command "${command.getName()}" to be an object, but it is of type: `
+ typeof commandMetadata,
type: CodyResponseType.Error
};
}
let properties = "";
for(const prop in commandMetadata) {
if(commandMetadata.hasOwnProperty(prop)) {
const type = commandMetadata[prop];
// Append property to properties string which is inserted in interface below
properties = properties + ` ${prop}: ${type};\n`;
}
}
const content = `
export interface ${cmdName} {
${properties}
}
`;
// Util functions return Cody-Error-Responses in case something went wrong
const writeFileErr = writeFileSync(cmdFile, content);
if(isCodyError(writeFileErr)) {
return writeFileErr;
}
successDetails = successDetails + `✔️ Command file ${cmdFile} written\n`;
// Cody responses can be formatted similar to browser console formatting
// @see https://developers.google.com/web/tools/chrome-devtools/console/console-write#styling_console_output_with_css
return {
cody: `Wasn't easy, but command ${cmdName} should work now!`,
details: ['%c'+successDetails, 'color: #73dd8e;font-weight: bold'],
}
}
Now we can switch to InspectIO and set the following metadata in JSON format to the AddBuilding
command:
{
"buildingId": "string",
"name": "string"
}
Metadata can be set by opening the Metadata Sidebar (choose Metadata from top menu) and selecting the appropriate card or sticky note. Metadata changes are saved automatically.
Once metadata is set we can trigger Cody again ...
... and validate the result by executing docker-compose run --rm exercises npm run exercise2
again:
Cards on an InspectIO event map can have additional information set as metadata. By default metadata is stored in JSON format. Metadata itself is schemaless, meaning users are free to define any structure. The structure can be defined and even be type checked using Metadata Templates. In a Cody hook you have access to raw metadata and use it for advanced code generation.
Join the community chat on Gitter.
No beta user yet? Request access in the community chat.