Overview

In the past, I wrote articles about registering data using Drupal’s JSON:API with Python.

The following uses Basic authentication.

And the following uses an API Key.

In addition to these methods, I was able to register data using regular login authentication, so this is a memo of that process.

Code

The code is as follows. It logs in, obtains a CSRF token, and then registers content.

import requests
import json
import os
from dotenv import load_dotenv

class ApiClient:
    def __init__(self):
        load_dotenv(override=True)

        # DrupalサイトのURL(例)
        self.DRUPAL_BASE_URL = os.getenv("DRUPAL_BASE_URL")

        # エンドポイント(JSON:API)
        # self.JSONAPI_ENDPOINT = f"{self.DRUPAL_BASE_URL}/jsonapi/node/article"

        # 認証情報(Basic認証)
        self.USERNAME = os.getenv("USERNAME")
        self.PASSWORD = os.getenv("PASSWORD")

    def login(self):
        # ログインリクエスト
        login_url = f"{self.DRUPAL_BASE_URL}/user/login?_format=json"

        login_response = requests.post(
            login_url,
            json={"name": self.USERNAME, "pass": self.PASSWORD},
            headers={"Content-Type": "application/json"}
        )

        if login_response.status_code == 200:
            self.session_cookies = login_response.cookies

    def get_csrf_token(self):
        # CSRFトークンを取得
        csrf_token_response = requests.get(
            f"{self.DRUPAL_BASE_URL}/session/token",
            cookies=self.session_cookies  # ここでログインセッションを渡す
        )

        if csrf_token_response.status_code == 200:
            # return csrf_token_response.text
            # self.csrf_token = csrf_token_response.text
            self.headers = {
                "Content-Type": "application/vnd.api+json",
                "Accept": "application/vnd.api+json",
                "X-CSRF-Token": csrf_token_response.text,
            }
        else:
            # raise Exception(f"CSRFトークン取得失敗: {csrf_token_response.status_code} {csrf_token_response.text}")
            self.csrf_token = None

    def create_content(self, data: dict):
        # 記事作成リクエスト
        url = f"{self.DRUPAL_BASE_URL}/jsonapi/{data['data']['type'].replace('--', '/')}"
        response = requests.post(
            # self.JSONAPI_ENDPOINT,
            url,
            headers=self.headers,
            cookies=self.session_cookies,
            json=data
        )

        if response.status_code == 201:
            print("コンテンツが作成されました!")
        else:
            print("エラー:", response.status_code, response.text)

With this, content can be registered as follows.

apliClient = ApiClient()
apliClient.login()
apliClient.get_csrf_token()

# 記事データ
data = {
    "data": {
        "type": "node--article",
        "attributes": {
            "title": "新しい記事のタイトル",
            "body": {
                "value": "記事の本文です。",
                "format": "plain_text"
            }
        }
    }
}

apliClient.create_content(data)

Summary

There may be some inaccuracies, but I hope you find this helpful.