はじめに
hkob の雑記録の第423回目(通算17日目)は、NotionRubyMapping を makedown に対応させます。最初は create a page です。
Notion API の markdown 対応について
昨日紹介したように Notion API が markdown に対応しました。
First seen in @NotionHQ MCP, now in the @NotionAPI! As of today we have support for Markdown in /v1/pages 🎉 pic.twitter.com/CNyx442oZl
— Kenneth Sinder (@KennethSinder) 2026年2月27日
makedown でどんなコンテンツが対応しているかはこちらに書かれています。
テストデータの作成
まず、いつものようにテストのようにスクリプトを作成しました。プロパティで title を指定しない場合は、最初の h1 markdown がページタイトルになるそうです。せっかくなのでそれを試してみます。
curl 'https://api.notion.com/v1/pages' \
-H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
-H "Content-Type: application/json" \
-H "Notion-Version: 2025-09-03" \
--data '{
"parent": {
"data_source_id": "f0a1bf337ff04d24b5b6efb3ea006b15"
},
"markdown": "# New page with markdown\n## Paragraph 2\n- [ ] To Do\n- [x] Checked To Do\n"
}'
実行してみます。
> make
sh create_page_parent_data_source_with_markdown.sh > create_page_parent_data_source_with_markdown.json
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1457 0 1277 100 180 1560 219 --:--:-- --:--:-- --:--:-- 1781
sleep 1
ページが作成されました。Checked の To Do も作成できるのですね。

テストの作成
テストは以下のように作成してみました。build_child_page と create_child_page に markdown キーワード引数を追加してみます。
describe "create with markdown" do markdown = "# New page with markdown\n## Paragraph 2\n- [ ] To Do\n- [x] Checked To Do\n" let(:parent_data_source) { DataSource.new id: TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID } context "when build_child_page" do let(:target) { parent_data_source.build_child_page markdown: markdown } it { expect(target).to be_new_record } it_behaves_like "property values json", { "parent" => { "data_source_id" => TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID, }, "markdown" => markdown, } describe "dry_run" do let(:dry_run) { target.save dry_run: true } it_behaves_like "dry run", :post, :pages_path, json_method: :property_values_json end describe "create" do before { target.save } it_behaves_like "property values json", {} it { expect(target.id).to eq "315d8e4e98ab8108901dcfa2d3993f6e" } it { expect(target).not_to be_new_record } end end context "create_child_page" do context "not dry_run" do let(:target) { parent_data_source.create_child_page markdown: markdown } it_behaves_like "property values json", {} it { expect(target.id).to eq "315d8e4e98ab8108901dcfa2d3993f6e" } it { expect(target).not_to be_new_record } end context "dry_run" do let(:target) { parent_data_source.build_child_page markdown: markdown } let(:dry_run) { parent_data_source.create_child_page markdown: markdown, dry_run: true } it_behaves_like "dry run", :post, :pages_path, json_method: :property_values_json end end end
当然ながら unknown keyword となるので、これを実装してみます。
ArgumentError:
unknown keyword: :markdown
markdown 引数を追加
まず、DataSource#build_child_page と DataSource#create_child_page に markdown 引数を追加します。
# @param [Array<Property, Class, String>] assign # @return [NotionRubyMapping::Base] # @see https://www.notion.so/hkob/DataSource-1462b24502424539a4231bedc07dc2f5#c217ce78020a4de79b720790fce3092d # @param [String, NilClass] template_page # @param [String, NilClass] markdown def build_child_page(*assign, template_page: nil, markdown: nil) assign = properties.map { |p| [p.class, p.name] }.flatten if assign.empty? page = Page.new assign: assign, parent: {"data_source_id" => @id}, template_page: template_page, markdown: markdown pp = page.properties pp.clear_will_update yield page, pp if block_given? page end # @param [Array<Property, Class, String>] assign # @param [String, NilClass] template_page # @param [String, NilClass] markdown # @param [Boolean] dry_run true if dry_run # @return [NotionRubyMapping::Base] # @see https://www.notion.so/hkob/DataSource-1462b24502424539a4231bedc07dc2f5#c217ce78020a4de79b720790fce3092d def create_child_page(*assign, template_page: nil, markdown: nil, dry_run: false) assign = properties.map { |p| [p.class, p.name] }.flatten if assign.empty? page = Page.new assign: assign, parent: {"data_source_id" => @id}, template_page: template_page, markdown: markdown pp = page.properties pp.clear_will_update yield page, pp if block_given? page.save dry_run: dry_run end
この中で Page#new にも markdown 引数が必要となります。これは Page の親クラスである Base の initialize に追加します。
class Base # @param [Hash, nil] json # @param [String, nil] id # @param [Array<Property, Class, String>] assign # @param [Block, nil] parent # @param [String, nil] template_page # @param [String, nil] position # @param [String, nil] markdown def initialize(json: nil, id: nil, assign: [], parent: nil, template_page: nil, position: nil, markdown: nil) @nc = NotionCache.instance @json = json @id = @nc.hex_id(id || @json && @json["id"]) @archived = @json && @json["archived"] @has_children = @json && @json["has_children"] @new_record = true unless parent.nil? raise StandardError, "Unknown id" if !is_a?(List) && !is_a?(Block) && @id.nil? && parent.nil? payload_json = {} payload_json["parent"] = parent if !is_a?(Block) && parent if template_page == "default" payload_json["template"] = {"type" => "default"} elsif template_page payload_json["template"] = {"type" => "template_id", "template_id" => template_page.id} end if %w[page_start page_end].include? position payload_json["position"] = {"type" => position} elsif position payload_json["position"] = {"type" => "after_block", "after_block" => {"id" => position}} end payload_json["markdown"] = markdown if markdown @payload = Payload.new(payload_json) @property_cache = nil @created_time = nil @last_edited_time = nil return if assign.empty? assign.each_slice(2) { |(klass, key)| assign_property(klass, key) } @json ||= {} end
ここまで実装するとテストで WebMock の呼び出しとなります。当然 WebMock に該当する payload を登録していませんので、WebMock のテンプレートエラーになりました。markdown の payload が与えられたら、 create_page_parent_data_source_with_markdown.json が読み込まれるように stubs を設定しました。
def create_page generate_stubs_sub :post, __method__, :pages_path, { (中略) parent_data_source_with_markdown: [nil, 200, { "parent" => { "data_source_id" => TestConnection::TEST_TEMPLATE_DATA_SOURCE_ID, }, "markdown" => "# New page with markdown\n## Paragraph 2\n- [ ] To Do\n- [x] Checked To Do\n", }], } end
テスト結果
テスト結果は以下のようになりました。
(前略)
create with markdown
when build_child_page
is expected to be new record
behaves like property values json
is expected to eq {"markdown" => "# New page with markdown\n## Paragraph 2\n- [ ] To Do\n- [x] Checked To Do\n", "parent" => {"data_source_id" => "293d8e4e98ab80e7842e000befaa8ed5"}}
dry_run
behaves like dry run
is expected to eq "#!/bin/sh\ncurl -X POST 'https://api.notion.com/v1/pages' \\\n -H 'Notion-Version: 2025-09-03' \\\n...\"markdown\":\"# New page with markdown\\n## Paragraph 2\\n- [ ] To Do\\n- [x] Checked To Do\\n\"}'"
create
is expected to eq "315d8e4e98ab8108901dcfa2d3993f6e"
is expected not to be new record
behaves like property values json
is expected to eq {}
create_child_page
not dry_run
is expected to eq "315d8e4e98ab8108901dcfa2d3993f6e"
is expected not to be new record
behaves like property values json
is expected to eq {}
dry_run
behaves like dry run
is expected to eq "#!/bin/sh\ncurl -X POST 'https://api.notion.com/v1/pages' \\\n -H 'Notion-Version: 2025-09-03' \\\n...\"markdown\":\"# New page with markdown\\n## Paragraph 2\\n- [ ] To Do\\n- [x] Checked To Do\\n\"}'"
(後略)
Finished in 0.14716 seconds (files took 0.82486 seconds to load)
139 examples, 0 failures
おわりに
とりあえず、まず data_soruce を親とした create_child_page, build_child_page のテストおよび実装が完了しました。明日はさらに続きの処理をテスト・実装していきます。