[Back to LOC CLI Guidebook](https://hackmd.io/4LIsNIuWQnuR70JMeuBAEA?view) [Setup LOC CLI Environment](https://hackmd.io/igLh4azUT2aI8Fv-q-0e-g) [LOC CLI Installation](https://hackmd.io/igLh4azUT2aI8Fv-q-0e-g?view#Download-LOC-CLI) [LOC CLI Commands](https://hackmd.io/R4mrz2t1QSyTCHH73_2itg?view) [Local Simple Runtime Execution](https://hackmd.io/JhAMB49rS4CrpNdhHed7YA) # Getting Started - Hello World (TypeScript) In this tutorial, we are going to create a simple LOC data process using TypeScript. This data process would receive a POST request with JSON data, which contains a ```name``` field. It would return a response including this message: ```json { message: Hello, <name>! } ``` ## Create a Data Process :::info See the ++[**setup guide**](https://hackmd.io/igLh4azUT2aI8Fv-q-0e-g)++ for how to prepare your local LOC CLI environment, including getting a .yaml profile file and install **Node.js**. We also assume you are have renamed your LOC CLI to ```loc.exe```. You can also open the LOC CLI workspace directory (for example, ```/FST```) in VS Code (File -> Open Folder...). ::: ### Generate a Data Process Project In your LOC CLI workspace root directory (```FST``` in our example), create a new data process with ```bash loc new hello-world ``` You should see a new project ``` FST hello-world-ts generic-logic 1.ts 2.ts aggregator-logic.ts api-route-config config.yaml package.json tsconfig.json ``` Then open the LOC CLI root directory (**not** the project directory) as workspace in your VS Code. :::info LOC data processes will be executed in a [Deno](https://deno.land/) runtime so you don't need to install TypeScript on your machine. ::: ### Install Dependencies A LOC CLI TypeScript project requires dependency packages for type checks and deployment rolling-up. 1. Open a new terminal and switch to the project root dir: ```bash cd hello-world-ts ``` 2. Install project dependencies and type definitions (using NPM from Node.js and Git): ```bash npm i lodash npm i -D @types/lodash npm i github:fstnetwork/saffron-sdk#logic-0.5.1 ``` :::info Since ```fstnetwork/saffron-sdk``` is currently a private Github repository, please contact FST Network for granting you access. ::: 3. Switch back to the LOC workspace dir: (Windows) ```bash cd.. ``` (macOS/Linux) ```bash cd - ``` ### Project Config First look at the ```config.yaml``` in the project directory: ```yaml version: 0.1.0 name: hello-world-ts description: description timeoutSeconds: 180 aggregatorLogic: name: aggregator file: aggregator-logic.ts genericLogics: - name: generic-1 file: 1.ts - name: generic-2 file: 2.ts ``` This file contains key information of the data process, including time out and the file name/order of generic logics. For now we won't change anything here, but keep in mind you can configure them as you like. ## Implement Logics ### Generic Logics #1 The 1^st^ generic reads the ```name``` field from JSON data, convert it into Unicode string and store it in the data process' session storage: ```typescript import { GenericContext, RailwayError } from "@saffron/logic"; import isEmpty from "lodash/isEmpty"; /** * * The codes in 'run' are executed when no error occurrs in Generic Logic. * */ export async function run(ctx: GenericContext) { // a function that transforms byte array to string const UTF8ArrToStr = (aBytes: number[]): string => { if (isEmpty(aBytes)) { return "{}"; } const utf8decoder = new TextDecoder(); return utf8decoder.decode(new Uint8Array(aBytes)); } // type checking data source (may be http or message queue) let body: number[] = []; if ("http" in ctx.payload) { body = ctx.payload.http.body; } else if ("messageQueue" in ctx.payload) { body = ctx.payload.messageQueue.data; } else { throw new Error("this logic accept http/messageQueue payload"); } // read and parse JSON data from the request body const payload = JSON.parse(UTF8ArrToStr(body)); // log payload content ctx.agents.logging.info({ payload: payload }); // extract name from payload (default value is "World") const name: string = (payload?.name) || "World"; // write name into session store await ctx.agents.sessionStorage.putString("name", name); } /** * * The codes in 'handleError' is executed when an error occurrs in Generic Logic, * or the CURRENT running Logic just gets an error. * */ export async function handleError(ctx: GenericContext, error: RailwayError) { ctx.agents.logging.error(error.message); // log the error } ``` :::info See ++[**Agent List**](https://hackmd.io/Uj-tC7l9Q82VyGr8R5PL2Q)++ for reference of LOC agents. While using TypeScript, it is *necessary* to check what's in the ```ctx.payload``` (using so-called ++[type guards](https://www.typescriptlang.org/docs/handbook/2/narrowing.html))++ to avoid type errors. It would be ```ctx.payload.http.body``` in this example, but the TypeScript compiler won't know that. ::: ### Generic Logic #2 The 2^nd^ generic logic reads the ```name``` from session storage and send an event. ```typescript import { GenericContext, RailwayError } from "@saffron/logic"; /** * * The codes in 'run' is executed when no error occurred in Generic Logic. * */ export async function run(ctx: GenericContext) { // read name from session store const name = await ctx.agents.sessionStorage.get("name") as string; const events = [ { sourceDID: "Hello_World", // source DID targetDID: name, // target DID will be user's name labelName: `Hello, ${name}!`, // event label (greeting message) meta: "", // meta (empty) type: "default", // default group }, ]; // emit an event to event store await ctx.agents.eventStore.emit(events); // log event ctx.agents.logging.info(`emit event: ${JSON.stringify(events)}`); } /** * * The codes in 'handleError' is executed when there is any error occurred * in Generic Logic or CURRENT running Logic just gets an error. * */ export async function handleError(ctx: GenericContext, error: RailwayError) { ctx.agents.logging.error(error.message); // log the error } ``` ### Aggregator Logic The aggregator logic also reads the ```name``` from sessoin storage and send a response to the caller. ```typescript import { AggregatorContext, RailwayError } from "@saffron/logic"; /** * * The codes in 'run' are executed when no error occurrs in Aggregator Logic. * */ export async function run(ctx: AggregatorContext) { // read name from session store const name = await ctx.agents.sessionStorage.get("name") as string; const response = { message: `Hello, ${name}!` }; // send response to API route ctx.agents.result.finalize({ status: "ok", taskId: ctx.task.taskId, response: response }); // log response ctx.agents.logging.info({ response: response }); } /** * * The codes in 'handleError' is executed when an error occurrs in Generic Logic, * or the CURRENT running Logic just gets an error. * */ export async function handleError(ctx: AggregatorContext, error: RailwayError) { ctx.agents.logging.error(error.message); // log the error } ``` ## Deploy and Manage the Data Process/API Route See [Getting Started - Hello World (JavaScript)](https://hackmd.io/IiHvmAtjTTGFfakaH0dWuw) for more details. - Login: ```bash loc login ``` - Deploy data process ```hello-world-ts``` using profile ```example```: ```bash loc deploy hello-world-ts -ts -p example ``` - Deploy API route in ```api-route-config.yaml``` (be mindful of the project path): ```bash loc ar deploy -f hello-world-ts/api-route-config.yaml ``` - Deploy ```hello-world-ts``` with its API route at the same time: ```bash loc deploy hello-world-ts -ts -ar ``` :::info ```./loc deploy hello-world-ts -ts -ar``` replaces the API route but will still upload a new data process. You need to manually delete the older one(s) in order to release unused resources. ::: - Display the list of data processes or API routes: ```bash loc dp list loc ar list ``` - Remove a data process of API route: ```bash loc dp delete <data process pid> loc ar delete <api route pid> ``` --- <text style="font-size:17pt">**LOC CLI Guidebook Catalogue**</text> <text style="font-size:13pt"> [LOC CLI Introduction](https://hackmd.io/J5r2l2OaRgKF9LACR5KHsg?view)</text> <text style="font-size:13pt"> [LOC Concept](https://hackmd.io/mwTxDdBjSuiKrAmainQZAA?view)</text> <text style="font-size:13pt"> [LOC CLI Commands](https://hackmd.io/R4mrz2t1QSyTCHH73_2itg?view)</text> <text style="font-size:13pt"> [Getting Started - JavaScript](https://hackmd.io/IiHvmAtjTTGFfakaH0dWuw?view)</text> <text style="font-size:13pt"> [Getting Started - TypeScript](https://hackmd.io/kz93Th7vTCCbO3GFxp3r-A?view)</text> <text style="font-size:13pt"> [Reference - Agent List](https://hackmd.io/Uj-tC7l9Q82VyGr8R5PL2Q?view)</text> <text style="font-size:13pt"> [Reference - Event Fields Comparison Table](https://hackmd.io/N2Km6-8kRI2tMR5X4tRHeQ?view)</text> ###### tags: `LOC CLI`