REST API公開
UIとは結合していないアクション処理相当をREST APIとして外部に公開する機能です。
外部からREST APIアプリケーションに対して、REST呼び出しを行うことができるようになります。
REST呼び出しを受けたREST APIアプリケーションは処理を行い返答したり、実行環境のDBにアクセスしたり、外部のREST APIを呼び出して、その結果を返答したりできます。
作成
REST API定義の作成手順は以下の通りです。
- 同じパネル内にある
[作成]
ボタンから[新規]
を選択します。 - ダイアログ内にある
[Rest API ID]
フィールドと[Rest API ラベル]
フィールドに情報を入力して、[作成]
ボタンをクリックします。 - REST APIの設定項目を入力し、
[保存]
ボタンをクリックします。 REST APIの設定項目は以下の通りです。
項目 | 入力 | 説明 |
---|---|---|
メソッド | 必須 | HTTPメソッドを指定します。 次の5種類から1つ選択します。
|
リソース | 必須 | パスセグメントを入力します。 パスパラメータは{xx} のようにカッコで括ってください。 |
デバッグエンドポイント URL | デバッグデプロイしたREST API を呼び出すためのURLです。 https://{ドメイン}/dev/{Rest API ID}/{リソース} URLを開いたり、クリップボードへコピーすることもできます。 | |
リリースエンドポイント URL | リリースデプロイしたREST API を呼び出すためのURLです。 https://{ドメイン}/prod/{Rest API ID}/{リソース} URLを開いたり、クリップボードへコピーすることもできます。 | |
コンテンツタイプ | レスポンスヘッダへ初期登録されるタイプを設定します。 コンテンツタイプを設定しても、アクションで上書きすることは可能です。 | |
認証を必要とする | 必須 | 認証を必要とするかどうかを設定します。
|
[アクションエディタ]
ボタンをクリックし、アクションエディタを開きます。- アクションボードへ記述、ユーザ関数作成などを行い、
[保存]
ボタンをクリックします。
デプロイ
REST API定義をデプロイすることで、REST APIの公開となります。
REST API 定義にある右上の[デプロイ]
ボタンをクリックし、デプロイを行います。
例えば、下記の定義をデプロイします。
- アプリケーション定義のID
「restapi_sample」
- REST API定義のメソッド
「GET」
- REST API定義のリソース
「employee/{id}」
このREST APIが使用しているリソース数は、3つになります。(メソッドはカウント対象外となります。) デプロイした実行環境のリソース合計数は、ルート分も含むので4つになります。
/restapi_sample /employee /{id} GET
この後、下記の定義をデプロイします。
- アプリケーション定義のID
「restapi_sample」
- REST API定義のメソッド
「POST」
- REST API定義のリソース
「calculator」
REST APIのリソースは下記のようになります。 デプロイした実行環境のリソース合計数は、ルート分も含めて5つになります。
/restapi_sample /calculator POST /employee /{id} GET
アクションエディタ
REST APIのアクションスクリプトの記述について、デスクトップやモバイルのアクションと異なる点があります。 ここではできることや注意点について説明します。
オブジェクト
REST APIのアクションスクリプト内で使用できるオブジェクトについて説明します。
オブジェクト | 説明 |
---|---|
$const | $constを参照してください。 |
$fn | ビルトイン関数を呼び出すことができます。 使用できる関数については、下記の表を参照してください。 |
$req | $reqを参照してください。 |
$res | $resを参照してください。 |
ビルトイン関数
REST APIのアクションスクリプト内で使用できるビルトイン関数について説明します。
ビルトイン関数 | 説明 |
---|---|
$fn.getFile(path) | $fn.getFile(path)を参照してください。 |
$fn.getFileNames(path) | $fn.getFileNames(path)を参照してください。 |
$fn.putFile(path, parameters) | $fn.putFile(path, parameters)を参照してください。 |
$fn.deleteFile(path) | $fn.deleteFile(path)を参照してください。 |
$fn.getUsers(groupName?,option) | $fn.getUsers(groupName?,option)を参照してください。 |
$fn.createUser(param) | $fn.createUser(param)を参照してください。 |
$fn.updateUser(param) | $fn.updateUser(param)を参照してください。 |
$fn.deleteUser(email) | $fn.deleteUser(email)を参照してください。 |
$fn.resetPassword(param) | $fn.resetPassword(param)を参照してください。 |
$fn.getGroups(option) | $fn.getGroups(option)を参照してください。 |
$fn.createGroup(param) | $fn.createGroup(param)を参照してください。 |
$fn.addUsers(param) | $fn.addUsers(param)を参照してください。 |
$fn.removeUsers(param) | $fn.removeUsers(param)を参照してください。 |
$fn.svf.oauth2.token() | $fn.svf.oauth2.token()を参照してください。 |
$fn.svf.oauth2.revoke() | $fn.svf.oauth2.revoke()を参照してください。 |
$fn.svf.artifacts.print() | $fn.svf.artifacts.print()を参照してください。 |
$fn.svf.artifacts.info() | $fn.svf.artifacts.info()を参照してください。 |
$fn.svf.artifacts.download() | $fn.svf.artifacts.download()を参照してください。 |
$fn.svf.actions.status() | $fn.svf.actions.status()を参照してください。 |
$fn.sendMail(param) | $fn.sendMail(param)を参照してください。 |
$fn.csvToObject(csv) | $fn.csvToObject(csv)を参照してください。 |
$fn.getPresignedUrl(path,options) | $fn.getPresignedUrl(path,options)を参照してください。 |
$fn.listUsersByEmail(email,option) | $fn.listUsersByEmail(email,option)を参照してください。 |
$fn.listUsersByName(name,option) | $fn.listUsersByName(name,option)を参照してください。 |
編集
REST API定義のIDとラベルを変更できます。
REST API一覧から編集したいREST APIの[メニュー]
- [編集]
を選択します。
また、REST API項目も編集を行うことができます。
編集後は[保存]
ボタンをクリックします。
削除
REST API定義を削除するには、REST APIの[メニュー]
-[削除]
を選択します。
コピー
REST API定義をコピーし、指定アプリケーションへ挿入することができます。
REST API一覧からコピーしたいUIの[メニュー]
-[コピー]
を選択します。
検索
REST APIはパネル上部の検索フィールドからRest APIラベルでフィルタできます。
エクスポート
REST API定義をファイルとしてローカルにダウンロードすることができます。
REST APIの[メニュー]
-[エクスポート]
を選択することで可能です。
インポート
ローカルにエクスポートしたREST API定義はサービスにアップロードすることができます。
REST APIリスト右上の [作成]
ボタンから[インポート]
を選択します。
[インポート]
ダイアログからREST API定義ファイルを選択して、アップロードを実行します。
インポート可能な定義は、アプリケーションタイプ「REST API」
のREST API定義のみです
コミット
ユーザはリポジトリに対してアプリ定義をコミットを行うことができます。
フリー環境にデプロイ済みのサンプルREST API
サンプルREST APIの情報
リソース | デバッグエンドポイントURL | リリースエンドポイントURL | メソッド | 認証 | Content-Type[Request] | Content-Type[Response] |
---|---|---|---|---|---|---|
/employee/{id} | https://api.feda9x.webperformer.jp/dev/restapi_sample/employee/{id} | https://api.feda9x.webperformer.jp/prod/restapi_sample/employee/{id} | GET | Required | - | application/json |
/calculator | https://api.feda9x.webperformer.jp/dev/restapi_sample/calculator | https://api.feda9x.webperformer.jp/prod/restapi_sample/calculator | POST | Required | application/json | text/plain |
APIキー
デプロイ環境 | APIキー |
---|---|
デバッグ | uarsnOdmlF3Wcth1C8KeaPg4njkheaq7VtAYh0De |
リリース | 0mUykFa2j82t08kA8Xdhe5W4a7THnv8Maq3MtN4v |
リソース: /employee/{id} の仕様
従業員 id をパスパラメータに指定することで、JSON 形式で5名のダミーの従業員情報をJSONで返却します。
[ { "id": "E001", "name": "Tom Williams", "age": 28 }, { "id": "E002", "name": "David Campbell", "age": 39 }, { "id": "E003", "name": "Nick Raj", "age": 21 }, { "id": "E004", "name": "Kevin Dean", "age": 45 }, { "id": "E005", "name": "John Smith", "age": 26 }]
REST API呼び出し成功時は、HTTPステータス200を返却します。 レスポンスのContent-Typeは、application/jsonです。 レスポンスボディは、id(E001~E005)に該当する従業員の情報のみを返却します。
(GET /employee/E001 の例)
{"id": "E001","name": "Tom Williams","age": 28}
存在しないIDを指定時、HTTPステータス404を返却します。 レスポンスの Content-Type は application/jsonです。 レスポンスボディは以下の通りです。 {“message”: “Employee ID {id} not found.”}
アクション定義
/* Modules */const util = require("node:util");/* Consts */const EMPLOYEES = [ { id: "E001", name: "Tom Williams", age: 28, }, { id: "E002", name: "David Campbell", age: 39, }, { id: "E003", name: "Nick Raj", age: 21, }, { id: "E004", name: "Kevin Dean", age: 45, }, { id: "E005", name: "John Smith", age: 26, },];/* Class */class EmployeeService { constructor() { } find({ employeeId }) { return EMPLOYEES.find((e) => e.id === employeeId); }}class Response { static ok(employee) { return { statusCode: 200, headers: { "Content-Type": "application/json", }, body: JSON.stringify(employee), }; } static notFound({ employeeId }) { return { statusCode: 404, headers: { "Content-Type": "application/json", }, body: JSON.stringify({ message: util.format($const.MESSAGE_EMPLOYEE_NOT_FOUND, employeeId), }), }; } static internalServerError() { return { statusCode: 500, headers: { "Content-Type": "application/json", }, body: JSON.stringify({ message: $const.MESSAGE_EMPLOYEE_INTERNAL_SERVER_ERROR, }), }; }}class Api { constructor() { this.employeeService = new EmployeeService(); }
execute({ pathParameters }) { try { const employeeId = pathParameters?.id; const employee = this.employeeService.find({ employeeId }); if (!employee) { return Response.notFound({ employeeId }); } return Response.ok(employee); } catch (e) { console.error(e); return Response.internalServerError(); } }}/* Instances */const api = new Api();/* Main */const response = api.execute({ pathParameters: $req.pathParameters,});$res.statusCode = response.statusCode;$res.headers = response.headers;$res.body = response.body;
定数定義
名前 | データ型 | 値 |
---|---|---|
MESSAGE_EMPLOYEE_INTERNAL_SERVER_ERROR | String | System error. |
MESSAGE_EMPLOYEE_NOT_FOUND | String | Employee ID %s not found. |
リソース: /calculator の仕様
arg1とarg2の引数、および、operation (加算または減算) を受けると、計算結果の値を返却します。
- arg1: -99999999~99999999 までの数値
- arg2: -99999999~99999999 までの数値
- operation: plus|minu
リクエストのContent-Typeは、application/jsonです。 リクエストボディは以下の通りです。
例){ "arg1": 1234.56, "arg2": -123.45, "operation": "plus"}
成功時、HTTPステータス200を返却します。 レスポンスの Content-Type はtext/plainです。 レスポンスボディは以下の様に計算結果のみを返却します。 例)1111.11
数値(number型)の有効桁数は16桁(JSの仕様でIEEE 754の倍精度。小数含む。)です。 BigNumberに変換して計算します。
arg1, arg2, operation が不正な場合、レスポンスのHTTPステータスは400とします。 レスポンスの Content-Typeは text/plainです。 レスポンスボディは一律以下を返却します。 Input values are incorrect.
アクション定義
/* Consts */const ARG_MIN = -99999999;const ARG_MAX = 99999999;/* Class */class Calculator { constructor(type) { this.type = type; } /** * @param {number} arg1 * @param {number} arg2 * @returns {BigNumber} */ calculate(arg1, arg2) { throw new Error("Not implemented."); }}class PlusCalculator extends Calculator { constructor() { super("plus"); } /** * @param {number} arg1 * @param {number} arg2 * @returns {BigNumber} */ calculate(arg1, arg2) { return BigNumber(arg1).plus(BigNumber(arg2)); }}class MinusCalculator extends Calculator { constructor() { super("minus"); } /** * @param {number} arg1 * @param {number} arg2 * @returns {BigNumber} */ calculate(arg1, arg2) { return BigNumber(arg1).minus(BigNumber(arg2)); }}class CalculatorManager { /** * @param {Calculator[]} calculators */ constructor(calculators) { this.calculators = calculators; } /** * @param {string} type * @returns {Calculator} */ getCalculator(type) { return this.calculators.find((c) => c.type === type); } /** * @returns {string} */ getTypes() { return this.calculators.map((c) => c.type); }}class Response { /** * @param {BigNumber} result */ static ok(result) { return { statusCode: 200, headers: { "Content-Type": "text/plain", }, body: result?.toFixed(), }; } static badRequest() { return { statusCode: 400, headers: { "Content-Type": "text/plain", }, body: $const.MESSAGE_CALC_BAD_REQUEST, }; } static internalServerError() { return { statusCode: 500, headers: { "Content-Type": "text/plain", }, body: $const.MESSAGE_CALC_INTERNAL_SERVER_ERROR, }; }}class Api { constructor() { this.calcManager = new CalculatorManager([ new PlusCalculator(), new MinusCalculator() ]); } toParams(body) { try { return JSON.parse(body); } catch (e) { console.error("Invalid request body: ", e); return null; } } isValid({ type, arg1, arg2 }) { const allowedTypes = this.calcManager.getTypes(); // type. if (!allowedTypes.includes(type)) { return false; } // arg1. if (typeof arg1 !== "number") { return false; } if (arg1 < ARG_MIN || ARG_MAX < arg1) { return false; } // arg2. if (typeof arg2 !== "number") { return false; } if (arg2 < ARG_MIN || ARG_MAX < arg2) { return false; } return true; } /** * @param {{ * body: string; * }} */ execute({ body }) { try { const params = this.toParams(body); if (!params) { return Response.badRequest(); } const type = params.operation; const arg1 = params.arg1; const arg2 = params.arg2; if (!this.isValid({ type, arg1, arg2 })) { return Response.badRequest(); } const calculator = this.calcManager.getCalculator(type); const result = calculator.calculate(arg1, arg2); return Response.ok(result); } catch (e) { console.error(e); return Response.internalServerError(); } }}/* Instances */const api = new Api();/* Main */const response = api.execute({ body: $req.body,});$res.statusCode = response.statusCode;$res.headers = response.headers;$res.body = response.body;
定数定義
名前 | データ型 | 値 |
---|---|---|
MESSAGE_CALC_BAD_REQUEST | String | Input values are incorrect. |
MESSAGE_CALC_INTERNAL_SERVER_ERROR | String | System error. |
ブラウザからRESTを呼び出す場合
RESTAPIをデプロイした場合に 単純リクエストではない場合にプリフライトリクエストが発生します。
そのため、OPTIONSメソッドも追加で用意する必要があります。
OPTIONSメソッドでは、指定された URL またはサーバーの許可されている通信オプションをリクエストします。
アクション定義
const response = { statusCode: 200, headers: { 'Access-Control-Allow-Origin' : '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'origin,x-api-key' , }};$res= response;return $res;
ヘッダー名 | 説明 |
---|---|
Access-Control-Allow-Origin | 指定されたオリジンからのリクエストを行うコードでレスポンスが共有できるかどうかを示します |
Access-Control-Allow-Methods | リソースにアクセスするときに利用できる 1 つまたは複数のメソッドを指定します |
Access-Control-Allow-Headers | 実際のリクエストの間に使用できる HTTP ヘッダーを示すために使用されます |