Technical Articles
SAP Cloud SDK for JavaScriptでPostリクエストを受け取る
SAP Cloud SDK for JavaScriptを使ってHttpのPostリクエストを受け取るNode.jsアプリを開発する方法のメモです。といってもSAP Cloud SDK for Javascriptは何も使っておらず、実質Nest.jsのみを使っています。
Node.jsとSAP Cloud SDK for JavaScriptについては、別記事「SAP Cloud SDK for JavaScriptを使ってSAP CP CFへアプリをデプロイ」を参照ください。
Node.jsプログラムはGitHubに置いています。
開発環境
以下の環境で実行しています。
- OS: Ubuntu18.04.01 LTS
- nvm: 0.35.3
- Node.js: 12.16.2
- npm: 6.14.4
- SAP Cloud SDK for JavaScript:1.19.0
- SAP Cloud SDK cli: 0.1.8
- nest cli: 7.1.2
手順
0. Git
おまけです。GitHubでRepositoryをREADME.mdなしで作り、Cloneしておきます。
1. Node.js開発
1.1. プロジェクト作成
Cloneしたディレクトリから以下のコマンドでProject作成。途中、以下のプロンプトに返答。
$ sap-cloud-sdk init
This folder does not contain a `package.json`.
Should a new `nest.js` project be initialized in this folder? (y|n): y
Directory is not empty. Creating the scaffold will fail if there are conflicting files. Should ALL files in this directory be removed? (y|n): n
Building application scaffold... done
Enter project name (for use in manifest.yml) [node-rest-post]: node-rest-post
Do you want to provide anonymous usage analytics to help us improve the SDK? (y|n): n
✔ Creating files
✔ Modifying test config
✔ Adding dependencies to package.json
✔ Installing dependencies
✔ Modifying `.gitignore`
+--------------------------------------------------------------+
✅ Init finished successfully.
? Next steps:
- Run the application locally (`npm run start:dev`)
- Deploy your application (`npm run deploy`)
? Consider setting up Jenkins to continuously build your app.
Use `sap-cloud-sdk add-cx-server` to create the setup script.
+--------------------------------------------------------------+
- Should a new `nest.js` project be initialized in this folder? (y|n): y
- Directory is not empty. Creating the scaffold will fail if there are conflicting files. Should ALL files in this directory be removed? (y|n): n
- Enter project name (for use in manifest.yml) [node-rest-post]: node-rest-post
- Do you want to provide anonymous usage analytics to help us improve the SDK? (y|n): n
ls で作成されたファイルなどを確認します。
$ ls -al
total 628
drwxr-xr-x 9 i348221 i348221 4096 Apr 20 10:26 .
drwxr-xr-x 15 i348221 i348221 4096 Apr 20 10:19 ..
-rw-r--r-- 1 i348221 i348221 92 Apr 20 10:24 credentials.json
drwxr-xr-x 2 i348221 i348221 4096 Apr 20 10:24 deployment
-rw-r--r-- 1 i348221 i348221 599 Apr 20 10:24 .eslintrc.js
drwxr-xr-x 8 i348221 i348221 4096 Apr 20 10:24 .git
-rw-r--r-- 1 i348221 i348221 422 Apr 20 10:26 .gitignore
-rw-r--r-- 1 i348221 i348221 1101 Apr 20 10:24 Jenkinsfile
-rw-r--r-- 1 i348221 i348221 174 Apr 20 10:24 manifest.yml
-rw-r--r-- 1 i348221 i348221 64 Apr 20 10:24 nest-cli.json
drwxr-xr-x 774 i348221 i348221 24576 Apr 20 10:26 node_modules
-rw-r--r-- 1 i348221 i348221 34 Apr 20 10:24 .npmrc
-rw-r--r-- 1 i348221 i348221 2658 Apr 20 10:26 package.json
-rw-r--r-- 1 i348221 i348221 521308 Apr 20 10:26 package-lock.json
drwxr-xr-x 2 i348221 i348221 4096 Apr 20 10:24 .pipeline
-rw-r--r-- 1 i348221 i348221 51 Apr 20 10:24 .prettierrc
-rw-r--r-- 1 i348221 i348221 3000 Apr 20 10:24 README.md
drwxr-xr-x 3 i348221 i348221 4096 Apr 20 10:24 s4hana_pipeline
-rw-r--r-- 1 i348221 i348221 17 Apr 20 10:24 sap-cloud-sdk-analytics.json
drwxr-xr-x 2 i348221 i348221 4096 Apr 20 10:24 src
-rw-r--r-- 1 i348221 i348221 82 Apr 20 10:24 systems.json
drwxr-xr-x 2 i348221 i348221 4096 Apr 20 10:24 test
-rw-r--r-- 1 i348221 i348221 97 Apr 20 10:24 tsconfig.build.json
-rw-r--r-- 1 i348221 i348221 336 Apr 20 10:24 tsconfig.json
1.2. Controller作成
Controller “test” をnest cliで作成。中身は後で更新します。
$ nest g controller test
CREATE src/test/test.controller.spec.ts (479 bytes)
CREATE src/test/test.controller.ts (97 bytes)
UPDATE src/app.module.ts (322 bytes)
1.3. DTO作成
DTO(Data Transfer Object)を作成します。<project-root>/scr/test ディレクトリ配下に”test.dto.ts”を手で作成します。<project-root>/scr/test/dto のディレクトリに作成する方法も多いですが、今回は簡易的にするためdtoディレクトリは省略。また、サービスも併せて作る方法もあるらしいですが、時間がなかったのでメリットなど調べていません。
今回はSAP Conversational AIのWebhookを例とします。
export class RequestBodyDTO {
readonly action_id: string;
readonly conversation: Conversation;
readonly nlp: Nlp;
}
export class Conversation {
readonly id: string;
readonly language: string;
readonly memory: Memory;
readonly participan_data: string;
readonly skill: string;
readonly skill_occurences: number;
readonly skill_stack: string[];
}
export class Nlp {
readonly act: string;
readonly entities: string[];
readonly intents: string[];
readonly language: string;
readonly processing_language: string;
readonly sentiment: string;
readonly source: string;
readonly status: number;
readonly timestamp: string;
readonly type: string;
readonly uudd: string;
readonly version: string;
}
export class Memory {
readonly entitySample: Entity;
}
export class Entity {
readonly confidence: number;
readonly raw: string;
readonly value: string;
}
1.4. Controller変更
ステップ1.2.で作成したControllerを変更します。デコレーター@Bodyを使ってリクエストBodyの内容を受け取っています。オウム返しにレスポンスBodyに設定します。
import { Controller, Post, Body } from '@nestjs/common';
import { RequestBodyDTO } from './test.dto';
@Controller('test')
export class TestController {
@Post()
async createLeaveRequest(@Body() requestBodyDTO: RequestBodyDTO) {
// リクエストBodyの内容をログ出力
console.log(requestBodyDTO);
console.log('entitySample: ' + requestBodyDTO.conversation.memory.entitySample.raw);
return requestBodyDTO;
}
}
2. テスト実行
ローカルでテスト実行します。
$ npm run start:debug
[11:08:48 AM] Starting compilation in watch mode...
[11:08:59 AM] Found 0 errors. Watching for file changes.
Debugger listening on ws://127.0.0.1:9229/357a1057-8f41-4421-b81a-908ebbcbd4bc
For help, see: https://nodejs.org/en/docs/inspector
[Nest] 8373 - 04/20/2020, 11:08:59 AM [NestFactory] Starting Nest application...
[Nest] 8373 - 04/20/2020, 11:08:59 AM [InstanceLoader] AppModule dependencies initialized +13ms
[Nest] 8373 - 04/20/2020, 11:08:59 AM [RoutesResolver] AppController {}: +5ms
[Nest] 8373 - 04/20/2020, 11:08:59 AM [RouterExplorer] Mapped {, GET} route +3ms
[Nest] 8373 - 04/20/2020, 11:08:59 AM [RoutesResolver] TestController {/test}: +1ms
[Nest] 8373 - 04/20/2020, 11:08:59 AM [RouterExplorer] Mapped {/test, POST} route +1ms
[Nest] 8373 - 04/20/2020, 11:08:59 AM [NestApplication] Nest application successfully started +3ms
curlを使ってHttpリクエストを投げます。Bodyの中身は省略しています(DTOで定義しても、Keyのエントリがなければエラーなく無視されます).。
オウム返しですが、リクエストBodyがそのまま返ってきています。
$ curl -X POST -H "Content-Type: application/json" -d '{"conversation": {"memory": {"entitySample": {"raw": "This is test"}}}}' localhost:3000/test
{"conversation":{"memory":{"entitySample":{"raw":"This is test"}}}}
今回はCFへのデプロイはしませんが、興味ある方は記事「SAP Conversational AIへWebhookでReplyを設定」を参照ください。