[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`