サポート > Wagby Developer Network(R8) > REST API 活用ガイド > 更新 [1] 画面操作に準じた制御

更新処理は二つの方法があります。ここでは(Wagbyの更新画面操作と同じように)「更新開始」「更新実行」という二段階で行う方法を説明します。edit GET, edit PUTの順で行います。

指定したデータのロックを行います。

@RequestMapping(value="/rest/[modelid]/edit/{pkey}", method=GET)

URL例

http://localhost:8921/wagby/rest/customer/edit/1000

レスポンス - データ取得成功

STATUS=200 OK
返戻の内容例を示します。

{
 "entityp": {
   "customerid": {
     "content":"1000",
     "formatted": null,
     "errorcode":""
   },
   "name": {
     "content":"Satou",
     "formatted": null,
     "errorcode":""
   },
   "email": [
     {
       "id": 1,
       "priority": null,
       "content": null,
       "errorcode":""
     }
   ]
 },
 "errors": {
   "jfcinfo": [],
   "jfcwarn": [],
   "jfcdebug": [],
   "jfcerror": []
 },
 "status":"updateCustomer.input",
 "pkey": null,
 "entity": {
   "customerid": 1000,
   "name": "Satou",
   "email": []
 }
}

レスポンス - データが見つからない

STATUS=404 Not Found

指定したデータのロックを行います。

@RequestMapping(value="/rest/[modelid]/edit", method=GET)

URL例

http://localhost:8921/wagby/rest/customer/edit?customerid=1000

レスポンス

「更新開始(主キーURL指定)」と同様です。

ロックを解除します。更新は行われません。

@RequestMapping(value="/rest/[modelid]/edit/cancel", method=GET)

URL例

http://localhost:8921/wagby/rest/customer/edit/cancel

レスポンス

返戻の内容例を示します。

{
 "entityp": null,
 "errors": {
   "jfcinfo": [],
   "jfcwarn": [],
   "jfcdebug": [],
   "jfcerror": []
 },
 "status":"showCustomer",
 "pkey": "1000",
 "entity": null
}

更新画面にてデータを入力し、リロードした際のデータを返します。更新の前に入力した値を使って、(サーバ側で)計算処理を行い、その結果を受け取るという目的で利用します。

@RequestMapping(value="/rest/[modelid]/edit/refresh", method=POST, headers="Content-Type=application/x-www-form-urlencoded")

URL例

http://localhost:8921/wagby/rest/customer/edit/refresh

リクエスト

フォーム画面と同様のパラメータを指定します。
例:
customer_p$002fcustomerid=1000
customer_p$002fname=Satou

レスポンス

入力した値に対して、計算処理などが行われたあとの値が返ります。

{
 "entityp": {
   "customerid": {
     "content":"1000",
     "formatted": null,
     "errorcode":""
   },
   "name": {
     "content":"Satou",
     "formatted": null,
     "errorcode":""
   },
   "email": [
     {
       "id": 1,
       "priority": null,
       "content": null,
       "errorcode":""
     }
   ]
 },
 "errors": {
   "jfcinfo": [],
   "jfcwarn": [],
   "jfcdebug": [],
   "jfcerror": []
 },
 "status":"updateCustomer.input",
 "pkey": null,
 "entity": {
   "customerid": 1000,
   "name": "Satou",
   "email": []
 }
}

レスポンス

「更新キャンセル」と同様です。

@RequestMapping(value="/rest/[modelid]/edit/refresh", method=POST, headers="Content-Type=application/json")

URL例

http://localhost:8921/wagby/rest/customer/edit/refresh

HTTPヘッダ

Content-Type:application/json

リクエスト

プレゼンテーションオブジェクトのJSON表現を指定します。

{
   "customerid":
     "content":"1000"
   }
   "name":
     "content":"Satou"
   }
}

レスポンス

「requestパラメータによる更新リフレッシュ」と同様です。

@RequestMapping(value="/rest/[modelid]/edit", method=PUT, headers="Content-Type=application/x-www-form-urlencoded")

リクエスト

「requestパラメータによる更新リフレッシュ」と同様です。

レスポンス

「requestパラメータによる更新リフレッシュ」と同様です。ただしレスポンスに含まれる entity は更新用の入力値と同じものが返されます。

更新後にデータベースに格納された値を返戻させるように動作を変えることもできます。

レスポンス - ロックエラー

STATUS=409 Conflict

@RequestMapping(value="/rest/[modelid]/edit", method=PUT, headers="Content-Type=application/json")

リクエスト

「JSONオブジェクトによる更新リフレッシュ」と同様です。

レスポンス

「JSONオブジェクトによる更新リフレッシュ」と同様です。

マルチパート形式で送信することで、ファイル型項目を含む新規登録を行うことができます。詳細は "ファイルの扱い" をお読みください。

requestパラメータまたはJSONオブジェクトによる登録、更新処理後に返戻される(レスポンスに含まれる)entity, entityp は登録、更新時に渡した入力値と同じものが返されます。すなわち、entity, entityp はデータベースに格納された値と同一ではありません。具体的には次のような違いがあります。

  • 繰り返しコンテナを含む場合、繰り返しコンテナID項目の値は不正確な値となります。これは繰り返しコンテナID項目の値はデータベースから取得する際に定まるためです。
  • 自動計算や参照連動の値が不正確な値となります。これらの値はデータベースに保存する時点で定まるか、またはデータベースから改めて読み込むときに定まるためです。

このルールはパフォーマンスを優先したものです。一方で登録、更新後に改めてデータを取得して最新の値を利用したいという場合もあります。この場合はもう一度、データ取得のための API 呼び出しを行います。

この手間をなくすため、登録、更新後にデータベースの値を改めて取得した値を entity, entityp として返戻させることができます。つまり登録更新と取得という二回の REST API 呼び出しを一回にまとめます。

方法

呼び出し時にリクエストヘッダ "x-wagby-reload-entity" にtrueを指定します。

図 リクエストヘッダ "x-wagby-reload-entity" の有無で動作が変わる

x-wagby-reload-entity をセットすることでデータベースアクセスのための処理が加わるようになります。参照連動や計算式の処理をすべて終えた状態の値を返戻してほしいという要件の場合、x-wagby-reload-entity を指定してください。

ここでは juser モデルを JSON 形式で更新するときの JSON オブジェクトの扱いを説明します。モデル参照項目 jprincipalId に注目します。

1. 更新開始(主キーパラメータ指定)の手順に従ってプレゼンテーションモデルを取得します。例えばアカウント test1 について、次のURLにGETでアクセスします。

http://localhost:8921/wagby/rest/juser/edit/test1

次のJSONオブジェクトを取得できます。

{
   "entityp": {
       "userid": {
           "content": "test1",
           "formatted": null,
           "errorcode": ""
       },
       "passwdNow": null,
       "passwd2": null,
       "jgroupid": [],
       "passwd": {
           "content": null,
           "formatted": null,
           "errorcode": ""
       },
       "compulsoryChange": [
           {
               "noId": false,
               "priority": 0,
               "content": "次回ログオン時にパスワードを強制変更させる",
               "choose": false,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 1
           }
       ],
       "name": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "valid": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "level": {
           "content": "",
           "formatted": "",
           "errorcode": ""
       },
       "passwdChangeDate": {
           "content": "2019-08-27",
           "formatted": null,
           "errorcode": ""
       },
       "passwdChangeFlag": {
           "content": null,
           "formatted": null,
           "errorcode": ""
       },
       "passwdErrCount": {
           "content": "",
           "formatted": "",
           "errorcode": ""
       },
       "oldPasswds": [
           {
               "id": 1,
               "priority": null,
               "content": null,
               "errorcode": ""
           }
       ],
       "jprincipalId": [
           {
               "noId": false,
               "priority": 0,
               "content": "共通処理",
               "choose": true,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 0
           },
           {
               "noId": false,
               "priority": 0,
               "content": "パスワード変更",
               "choose": true,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 1
           },
           ...(中略)...
           {
               "noId": false,
               "priority": 0,
               "content": "ジョブ専用アカウント",
               "choose": false,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 21
           }
       ],
       "lastLogonDate": {
           "content": null,
           "formatted": null,
           "errorcode": ""
       },
       "avatarImage": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "avatarImage_jshfilename": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "rule": []
   },
   "pkey": null,
   "errors": {
       "jfcerror": [],
       "jfcinfo": [],
       "jfcwarn": [],
       "jfcdebug": []
   },
   "entity": {
   ...(中略)...
   },
   "status": "updateJuser.input"
}

ここで "entityp" に格納されているのがプレゼンテーションモデルです。entityp内のjprincipalIdは、content(内容部)だけでなく、idやchooseといった情報も含まれています。詳細はプレゼンテーションモデルの説明をお読みください。

2. 得られた値を修正し、更新します。次のURLのREST APIをPUTで呼び出します。

http://localhost:8921/wagby/rest/juser/edit

リクエストには次に示すJSONオブジェクトを指定した、とします。これは 1. で取得したJSONオブジェクトの "entityp" の部分です。また、設定したいjprincipalIdのchooseをtrueとします。(今回はjprincipalIdが "0","1","2","9" の選択肢を設定した、としています。)

{
       "userid": {
           "content": "test1",
           "formatted": null,
           "errorcode": ""
       },
       "passwdNow": null,
       "passwd2": null,
       "jgroupid": [],
       "passwd": {
           "content": null,
           "formatted": null,
           "errorcode": ""
       },
       "compulsoryChange": [
           {
               "noId": false,
               "priority": 0,
               "content": "次回ログオン時にパスワードを強制変更させる",
               "choose": false,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 1
           }
       ],
       "name": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "valid": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "level": {
           "content": "",
           "formatted": "",
           "errorcode": ""
       },
       "passwdChangeDate": {
           "content": "2019-08-27",
           "formatted": null,
           "errorcode": ""
       },
       "passwdChangeFlag": {
           "content": null,
           "formatted": null,
           "errorcode": ""
       },
       "passwdErrCount": {
           "content": "",
           "formatted": "",
           "errorcode": ""
       },
       "oldPasswds": [
           {
               "id": 1,
               "priority": null,
               "content": null,
               "errorcode": ""
           }
       ],
       "jprincipalId": [
           {
               "choose": true,
               "id": 0
           },
           {
               "choose": true,
               "id": 1
           },
           {
               "choose": true,
               "id": 2
           },
           {
               "choose": true,
               "id": 9
           }
       ],
       "lastLogonDate": {
           "content": null,
           "formatted": null,
           "errorcode": ""
       },
       "avatarImage": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "avatarImage_jshfilename": {
           "content": "",
           "formatted": null,
           "errorcode": ""
       },
       "rule": []
   }

1. で得られたモデルの項目の値を全て設定します。(設定しない項目は null 扱いで更新されます。)

モデル参照部の表記についての詳細

上では jprincipalId の choose と id だけを指定しましたが、他の値を含めて送信しても問題ありません。

...
       "jprincipalId": [
           {
               "noId": false,
               "priority": 0,
               "content": "共通処理",
               "choose": true,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 0
           },
           {
               "noId": false,
               "priority": 0,
               "content": "パスワード変更",
               "choose": true,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 1
           },
           {
               "noId": false,
               "priority": 0,
               "content": "システム管理者",
               "choose": true,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 2
           },
...
           {
               "noId": false,
               "priority": 0,
               "content": "一般ユーザ",
               "choose": true,
               "invalid": false,
               "errorcode": "",
               "label": "",
               "id": 9
           },
...

すべての項目を設定する

モデルの項目の値を全て設定してください。設定しない項目は null 扱いで更新されます。

自動ログオンには未対応

本方式は更新開始時に更新対象のデータを取得し、セッションに格納します。また、悲観ロックの場合はロックを行います。

更新実行にてセッションに格納されたデータを用いて、更新を実行します。悲観ロックの場合はロックの解放を行います。

ここで自動ログオン機能にて更新開始を行った場合、更新対象のデータをセッションに格納しても、ログオフ時に解放されることになります。そのため自動ログオン機能には対応していません。自動ログオン機能を用いる場合は「簡易制御」方式をご利用ください。

楽観ロックを利用する場合

楽観ロックを利用する場合は、バージョン管理用カラムの設定が必要です。異なる値を指定した場合は 409 Conflictを返します。この場合は更新されません。

詳細

/wagby/rest/[modelid]/entry/[pkey] GETにて、下記のような値が取得されたとします。項目 "optilock" は楽観ロックのためのバージョン管理カラムとします。

{
   "entityp": {
       "pkey": {
           "content": "1008",
           "formatted": null,
           "errorcode": ""
       },
       "item1": {
           "content": "aaaa1",
           "formatted": null,
           "errorcode": ""
       },
       "optilock": null
   },
...
   "entity": {
       "pkey": 1008,
       "item1": "aaaa1",
       "optilock": 3
   },
...
}

このとき、下記のようにバージョン管理用カラムに、取得時のentityに格納されている値をセットしたJSONデータを送信してください。

{
       "pkey": {
           "content": "1008",
           "formatted": null,
           "errorcode": ""
       },
       "item1": {
           "content": "aaaa1a",
           "formatted": null,
           "errorcode": ""
       },
       "optilock": {
           "content": "3"
       }
}

もし取得と更新の間に、別の利用者から更新があった場合、バージョン管理用カラムの番号が進むことになります。この場合は 409 Conflict を返し、データの更新が失敗します。

失敗時のJSONオブジェクトには、下記のようなエラーメッセージが格納されます。

   "errors": {
       "jfcwarn": [],
       "jfcdebug": [],
       "jfcinfo": [],
       "jfcerror": [
           {
               "name": null,
               "content": "データベースの更新処理に失敗しました。このデータは他のユーザーによって更新されているので、そのままでは保存できません。キャンセルボタンをクリックして、再度更新処理をやり直してください。",
               "sanitizeAsBoolean": false,
               "code": "model1.error.dbaccess.update.OptimisticLockingFailure",
               "sanitize": false
           }
       ]
   },