AtoM(Access to Memory)のAPIを使って、オブジェクトを登録してみる
概要
AtoM(Access to Memory)のAPIを使って、オブジェクトを登録する方法の備忘録です。
APIの有効化
以下にアクセスします。
/sfPluginAdminPlugin/plugins
arRestApiPlugin
を有効にします。
APIキーの取得
以下に、APIキーを生成する方法が説明されています。
ユーザ名とパスワードでもAPI接続できるようですが、今回はREST API Keyを発行しました。
エンドポイント
AtoMでは、「典拠レコード」や「機能」など、複数のメニューが提供されていますが、APIによって利用できるのは、以下のみのようです。
See the subsequent pages for more details on each endpoint, and available parameters. There are three endpoints available:
Browse taxonomy terms
Browse information objects
Read information object
Download digital objects
Add physical objects
この点は、ArchivesSpaceのほうが豊富なAPIが提供されており、軍配が上がるかもしれません。
また、以下のソースコードを確認すると、CreateAction
が可能なものは、informationobjects
とphysicalobjects
、digitalobjects
に限定されているようでした。
ただ機械的に一括登録を行いたい場面は、主にinformationobjects
だと考えられるため、これらの機能のみで十分かもしれません。
physical objectsの登録
以下のようなクラスを用意します。
#| export
class ApiClient:
def __init__(self):
load_dotenv(override=True)
self.url = os.getenv("atom_url")
username = os.getenv("username")
password = os.getenv("password")
api_key = os.getenv("api_key")
if api_key:
self.headers = {
"REST-API-Key": api_key,
"Content-Type": "application/json"
}
else:
# Basic 認証のヘッダーを作成
auth_string = f"{username}:{password}"
auth_bytes = auth_string.encode('ascii')
auth_b64 = base64.b64encode(auth_bytes).decode('ascii')
self.headers = {
"Authorization": f"Basic {auth_b64}",
"Content-Type": "application/json"
}
def add_physical_objects(self, physical_objects):
url = f"{self.url}/api/physicalobjects"
print(url, self.headers, physical_objects)
response = requests.post(url, headers=self.headers, json=physical_objects)
# レスポンスを確認
if response.status_code in [200, 201]:
print("物理オブジェクトが作成されました!")
print(f"ステータスコード: {response.status_code}")
print(f"レスポンス: {response.text}")
# 作成されたオブジェクトの情報
result = response.json()
print(f"作成された物理オブジェクトID: {result.get('id')}")
print(json.dumps(result, indent=4))
else:
print(f"エラー: {response.status_code}")
print(f"レスポンス: {response.text}")
以下で実行します。
api_client = ApiClient()
# 物理オブジェクトのデータ
physical_data = {
"name": "T-01",
"location": "Example location",
"type": "Shelf"
}
api_client.add_physical_objects(physical_data)
物理オブジェクトが作成されました!
ステータスコード: 201
レスポンス: {"slug":"t-01"}
作成された物理オブジェクトID: None
{
"slug": "t-01"
}
結果、以下のように登録されます。
information objectsの登録
親レコードの登録
def add_information_objects(self, information_objects):
url = f"{self.url}/api/informationobjects"
response = requests.post(url, headers=self.headers, json=information_objects)
if response.status_code in [200, 201]:
print("情報オブジェクトが作成されました!")
print(f"ステータスコード: {response.status_code}")
print(f"レスポンス: {response.text}")
else:
print(f"エラー: {response.status_code}")
print(f"レスポンス: {response.text}")
以下を実行します。
parent_data = {
"title": "親コレクション",
"identifier": "PARENT-001",
"level_of_description": "Collection",
}
api_client.add_information_objects(parent_data)
情報オブジェクトが作成されました!
ステータスコード: 201
レスポンス: {"id":453,"slug":"ftb7-3bzd-8759","parent_id":1}
以下のように登録されました。
identifierを用いた検索
この処理により、登録済みのレコードのslug
を取得することができます。
def find_information_objects(self, identifier):
url = f"{self.url}/api/informationobjects"
params = {
"sq0": identifier,
"sf0": "identifier",
}
response = requests.get(url, headers=self.headers, params=params)
return response.json()
以下のように利用します。
identifier = "PARENT-001"
info_objects = api_client.find_information_objects(identifier)
print(json.dumps(info_objects, indent=4))
{
"total": 1,
"results": [
{
"reference_code": "PARENT-001",
"slug": "ftb7-3bzd-8759",
"title": "\u89aa\u30b3\u30ec\u30af\u30b7\u30e7\u30f3",
"level_of_description": "Collection"
}
]
}
クエリsq0
やsf0
は以下を参考にします。
子レコードの登録
親レコードのslug
がftb7-3bzd-8759
とわかったので、以下により登録します。
# 子の情報オブジェクト
child_data = {
"title": "子レコード",
"identifier": "CHILD-008",
"level_of_description": "File",
"parent_slug": "ftb7-3bzd-8759"
}
api_client.add_information_objects(child_data)
情報オブジェクトが作成されました!
ステータスコード: 201
レスポンス: {"id":471,"slug":"nsaa-ywyw-2sx7","parent_id":453}
結果、以下のように、親レコードの下位レコードとして、子レコードが登録されました。
デジタルオブジェクトの登録
def add_digital_objects(self, slug, file_path):
file_name = os.path.basename(file_path)
# マルチパートフォームデータでファイルをアップロード
with open(file_path, 'rb') as f:
files = {
'file': (file_name, f, 'application/pdf'),
}
data = {
'title': file_name,
'informationObjectSlug': slug,
'usage': 'Reference' # Master または Reference
}
do_response = requests.post(f"{self.url}/api/digitalobjects",
headers=self.headers, # Content-Type は自動設定
files=files,
data=data)
if do_response.status_code in [200, 201]:
do_result = do_response.json()
print(f"デジタルオブジェクト作成成功: ID {do_result.get('id')}")
else:
print(f"デジタルオブジェクトの作成に失敗: {do_response.status_code}")
print(f"エラーメッセージ: {do_response.text}")
ただし、以下のように実行してもエラーが発生してしまいました。
file_path = "_01.pdf"
slug = "nsaa-ywyw-2sx7"
api_client.add_digital_objects(slug, file_path)
この点については、引き続き調査したいと思います。
まとめ
AtoM(Access to Memory)のAPIの使用例について紹介しました。
簡単に調べた限りでは、information objectsのみ、API経由で削除することができるなど、APIによる機能提供が限定的な印象を受けました。
APIによる利用を前提にする場合には、AtoM以外の選択肢を考慮するのもよいかもしれません。
AtoMやArchivesSpaceの導入検討にあたり、参考になりましたら幸いです。
Discussion