2022/08/17

Domino REST API のチュートリアルを試してみた

2022年8月の「テクてくLotus技術者夜会」に参加予定なのですが、アジェンダにある「Project KEEP (REST API)」について予習しておこうと思い、この記事「Domino Rest API (KEEP) のチュートリアル」のとおり進めたところ、ハマりどころがいくつかありましたので、ここで共有したいと思います。

これからチュートリアルを進める方の参考になれば幸いです。

このエントリを書いている時点では、Domino REST API は最新ベータ版は 2022年7月版 EAP(Early Access Program)として Docker イメージで提供されています。私はこれを使用しました。


ハマりどころ(1):パーミッション

Docker イメージを使うには、それを動かすホストマシンが必要です。私は自前のPC(Windows 10) に Docker Desktop を導入しているので最初はそちらで進めていました。

ところがチュートリアルの「Domino REST APIの管理画面での操作」でホストマシンにダウンロードした Demo.nsf のパーミッションを変えてコンテナへコピーするところで、ホストマシンが Windows のためにパーミッション変更する方法が分からず一旦中断となりました。結局のところ、WSL2(Windows Subsystem for Linux) に Ubuntu をインストールし、そこに Docker をインストールして Docker イメージを使用することで Demo.nsf のパーミッション変更ができ、先に進むことができました。

実は Docker Desktop 上でパーミッション変更せずに先に進めたところ、問題が発生してしまいました。みなさんはパーミッションを変更できるホストマシンから操作するようにしてほしいと思います。


ハマりどころ(2):誤り

まだベータ版ということであるあるかとも思いますが、チュートリアルに記載のとおりにコマンドを叩いてもエラーになることがあります。

今回はチュートリアルの「curl もしくは postman でREST APIの操作」に誤り(バージョンがあがって仕様が変わったかも?)があり、ハマりました。

「文書を作成する」

チュートリアルには次のように GET と書かれていますが POST が正しいです。

GET /api/v1/document?dataSource=<スコープ名>


「文書を取得する」

チュートリアルには

/api/v1/document/<文書の UNID>/default?dataSource=<スコープ名>

と書かれていますが、これでは「404 This is not the URL you seek」となります。これを

/api/v1/document/<文書の UNID>?dataSource=<スコープ名>

のように "/default" を除去することで文書を取得することができました。


「文書を削除する」

こちらも「文書を取得する」と同じく "/default" を除去することで文書を削除することができました。


ハマりどころ(3):削除権限の反映

チュートリアルでは、「文書を削除する」で文書を削除できる設定に変えるため、Demo.nsf に作成されるリソースファイル「REST/<スキーマ名>.json」を編集するよう指示されています。私はこのとおり編集してみたものの「403 You are not allowed to delete the document at this mode」のエラーが出続けました。私の環境では Docker コンテナを再起動したところ反映されました。コンテナあるいは Domino を再起動するのではないにしろ、変更した設定を反映するのに何かアクションしなければならないのかもしれません。


ハマりどころ(4):リソースファイルにビューが反映されないことがある

チュートリアルの「Domino REST APIの管理画面での操作」に従って操作し、手順16で[Activated Views]にビューが追加されているにもかかわらずリソースファイル「REST/<スキーマ名>.json」に追加した内容が反映されておらず、REST APIでビュー一覧を取得できない、ということがありました。管理画面からビューの追加や削除をしながらリソースファイルの内容を確認する、といったことをしていると反映されることがあり、そのタイミングで REST API を実行すればビュー一覧を取得することができました。変更した設定内容がキチンと反映してほしいな、と思いました。


以上です。

なお、今回の問題解決に大いに役に立ったのは下の情報です。こちらのほうが仕様変更があった場合に速やかに反映されるかもしれません。

https://opensource.hcltechsw.com/domino-keep-docs/


今回のチュートリアルにある文書の操作などを行うため、先に取得した認証トークンを使用します。認証トークンの文字列は長いので覚えることができないし、いちいち控えておくのも面倒ということもあって、下の様な LotusScript でエージェントを作ってテストを進めていました。以下のコードは試行錯誤した履歴を含むので見づらいと思いますが、現時点で(私の環境では)きちんと動作しました。※サーバー停止は動きません

%REM
	Agent DominoRESTAPI
	Created 2022/08/16 by administrator
	Description: Domino Rest API サンプル環境を利用した学習
	
	本エージェント実行前にやる事
	1. Docker Windows の起動、restapiコンテナの起動
		restapiコンテナ以外のコンテナが起動する場合、終了しておく
	2. ipconfig でWSLのIPアドレス確認、HOSTS修正
		REQ_TARGET_HOST のホストのIPアドレスがHOSTSと異なる場合、修正する
	
%END REM
Option Public
Option Declare

Sub Initialize
	Dim ss As New NotesSession
	Dim req As NotesHTTPRequest
	Dim nav As NotesJSONNavigator
	Dim elm As NotesJSONElement
	Dim arr As NotesJSONArray
	Dim obj As NotesJSONObject
	Dim url$, data$, token$, unid$
	Dim headers
	Const USER_NAME = "Administrator"
	Const USER_PASSWORD = "password"
	Const REQ_PROTOCOL = "http://"
	Const REQ_TARGET_HOST = "himawari.noteslab.local:8880"
	Const ADMIN_HOST = "himawari.noteslab.local:8889"
	Const REQ_API = "/api/v1"
	
	Set req = ss.Createhttprequest()
	req.Preferjsonnavigator = True
	
	'認証トークンの取得
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/auth"

	req.Setheaderfield "Content-Type", "application/json"
	data = |{"password":"| & USER_PASSWORD & |","username":"| & USER_NAME & |"}|
	
	Set nav = req.Post( url, data )
	
	If InStr( req.Responsecode, "200" ) = 0 Then Exit Sub
	
	Set elm = nav.Getelementbyname( "bearer" )
	If elm Is Nothing Then Exit sub

	token = elm.Value
	Print "[DEBUG PRINT] token = " & token
	
	
	'DB一覧の取得
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/admin/access"
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token
	data = |{"checkAllNsf": true,"onlyConfigured": false}|

	Set nav = req.Post( url, data )
	
	If InStr( req.Responsecode, "200" ) = 0 Then Exit Sub

	Set arr = nav.Getelementbyname( "databases" ).Value
	Set elm = arr.Getfirstelement()
	While Not elm Is Nothing
		Set obj = elm.Value
		If obj.Getelementbyname( "path" ).Value = "Demo.nsf" Then
			Set obj = obj.Getelementbyname( "activeConfigurations" ).Value
			Print "[DEBUG PRINT] activeConfigurations.demodbscope = " & obj.Getelementbyname( "demodbscope" ).Value
		End If
		Set obj = Nothing

		Set elm = arr.Getnextelement()
	Wend		


	'データベース内のビューを確認する
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/lists?type=views&dataSource=demodbscope"
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token

	Set nav = req.Get( url )

	If InStr( req.Responsecode, "200" ) = 0 Then Exit Sub

	Print nav.Stringify()


	'文書を作成する
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/document?dataSource=demodbscope"
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token
	data = |{"first_name": "George","last_name": "Branthwaite","email": "gbranthwaite0@nba.com","gender": "Male","ip_address": "91.254.204.27","Form": "Customer"}|

	Set nav = req.Post( url, data )

	If InStr( req.Responsecode, "200" ) = 0 Then Exit Sub

	Print nav.Stringify()
	Set elm = nav.Getelementbyname( "@unid" )
	unid = elm.Value


	'文書を取得する
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/document/" & unid & "?dataSource=demodbscope"
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token

	Set nav = req.Get( url )

	If InStr( req.Responsecode, "200" ) = 0 Then
		Print "文書の取得に失敗しました。 responseCode = " & req.Responsecode
		Print nav.Getelementbyname( "message" ).Value
		'Exit Sub
	End If

	Print nav.Stringify()


	'文書を削除する
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/document/" & unid & "?dataSource=demodbscope"

	'※メモ
	'Demo.nsf をDesignerで開き、リソースにあるファイル「REST/demodbschema.json」の
	'「/forms/formModes/deleteAccessFormula/formula」の値を @trueにしたが削除できず、
	'それでも"not allowed to delete"になるので、Dockerコンテナを再起動したところ、削除できた。
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token

	Set nav = req.Deleteresource( url )

	If InStr( req.Responsecode, "200" ) = 0 Then
		Print "文書の削除に失敗しました。 responseCode = " & req.Responsecode
		Print nav.Getelementbyname( "message" ).Value
		'Exit sub
	End If

	Print nav.Stringify()


	'ログアウトする
	url = REQ_PROTOCOL & REQ_TARGET_HOST & REQ_API &_
	"/auth/logout"
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token
	data = |{"logout": "Yes"}|

	Set nav = req.Post( url, data )

	If InStr( req.Responsecode, "200" ) = 0 Then
		Print "ログアウトに失敗しました。 " & req.Responsecode
		Print nav.Stringify()
		'Exit Sub
	End If

	Print nav.Stringify()


	
	'サーバーを停止する
	url = REQ_PROTOCOL & ADMIN_HOST &_
	"/shutdown"

	'bearerトークンを残す意味で直上のログアウトをせずに実行してみたものの動作せず、
	'結果は「401 Unauthorized, boiling TAR」となった。
	
	Call req.Resetheaders()
	req.Setheaderfield "Content-Type", "application/json"
	req.Setheaderfield "Authorization", "Bearer " & token
	data = |{"shutdownkey" : "The End is near!!","StopServer" : true}|

	Set nav = req.Post( url, data )

	If InStr( req.Responsecode, "200" ) = 0 Then
		Print "サーバー停止に失敗しました。 " & req.Responsecode
		'Exit Sub
	End If

	Print nav.Stringify()
End Sub

0 件のコメント:

コメントを投稿