<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>てんハロ｜未経験エンジニアのIT学習ログ</title>
	<atom:link href="https://it-bokenki.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://it-bokenki.com</link>
	<description>Hello Worldから、今日も生きてる</description>
	<lastBuildDate>Tue, 22 Jul 2025 14:22:04 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://it-bokenki.com/wp-content/uploads/2025/06/cropped-ブログ　アイコン-32x32.png</url>
	<title>てんハロ｜未経験エンジニアのIT学習ログ</title>
	<link>https://it-bokenki.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>【初心者向け】Pay.jpとは？クレカ決済を爆速導入できるサービスを解説！特徴・使い方・実装例まとめ</title>
		<link>https://it-bokenki.com/2025/07/22/pay-jp/</link>
					<comments>https://it-bokenki.com/2025/07/22/pay-jp/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Tue, 22 Jul 2025 14:22:03 +0000</pubDate>
				<category><![CDATA[Next.js]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[バックエンド]]></category>
		<category><![CDATA[Pay.jp]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=5089</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 「クレジットカード決済をサ [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/22/pay-jp/">【初心者向け】Pay.jpとは？クレカ決済を爆速導入できるサービスを解説！特徴・使い方・実装例まとめ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img fetchpriority="high" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>「クレジットカード決済をサイトに組み込みたい…でも難しそう」<br>いざ調べてみると、知らない英語・セキュリティの話・カード情報の取り扱いなど、何をどうすればいいか混乱…。</p>



<p><br>そんなときに出会ったのが <strong>「Pay.jp（ペイジェーピー）」</strong>。<br>コード数行で決済ができるようになり、「え、こんなに簡単でいいの？」と驚き。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">Pay.jpとは？</span></h2>



<p><strong>Pay.jp</strong> は、<strong>クレジットカード決済を簡単に導入できる日本発の決済サービス</strong>です。</p>



<ul class="wp-block-list">
<li>Visa / Mastercard / JCB / AMEX などに対応</li>



<li>JavaScriptやAPI経由で簡単に組み込み可能</li>



<li>セキュリティ対策もばっちり（PCI DSS準拠）<br>PCI DSS：クレジットカード情報を安全に扱うための世界共通のルール</li>



<li>日本語ドキュメント完備＆開発者向けにやさしい</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">どんなときに使うの？</span></h2>



<p>たとえばこんな場面で使えます。</p>



<ul class="wp-block-list">
<li>ECサイトで商品を購入するときの決済</li>



<li>サブスク（月額課金）サービスの実装</li>



<li>会員登録＋決済を一括で処理</li>



<li>アプリ内課金のバックエンド処理　など</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">なぜPay.jpが選ばれているのか？</span></h2>



<p>クレジットカード決済サービスはたくさんありますが、「使いやすさ」「サポートの手厚さ」「日本向けかどうか」などで違いがあります。</p>



<p>以下は、Pay.jpと他の代表的なサービスを比較した表です。</p>



<figure class="wp-block-table"><table><thead><tr><th>項目</th><th><strong>Pay.jp</strong></th><th><strong>Stripe</strong></th><th><strong>Square</strong></th><th><strong>Komoju</strong></th></tr></thead><tbody><tr><td>開発元</td><td>日本</td><td>アメリカ</td><td>アメリカ</td><td>日本</td></tr><tr><td>日本語サポート</td><td><span class="bold-red">◎</span>（完全対応）</td><td>△（一部対応）</td><td>△（やや弱め）</td><td>◎（完全対応）</td></tr><tr><td>導入のしやすさ</td><td><span class="red">◎</span>（数行で完結）</td><td>○（高機能だが設定が複雑）</td><td>○（ノーコード寄り）</td><td>○（初期設定が少し複雑）</td></tr><tr><td>カード情報の取り扱い不要</td><td><span class="red">◎</span>（トークン化でOK）</td><td>◎（同様）</td><td>◎（同様）</td><td>◎（同様）</td></tr><tr><td>決済手数料（参考）</td><td>3.0%〜</td><td>3.6%〜</td><td>3.25%〜</td><td>3.6%〜</td></tr><tr><td>定期課金対応</td><td><span class="red">◎</span></td><td>◎</td><td>△（回数券などで代用）</td><td>◎</td></tr><tr><td>日本の決済文化への対応</td><td><span class="red">◎</span>（コンビニ払い・銀行振込など）</td><td>△（海外寄り）</td><td>△（海外寄り）</td><td>◎（多様な支払い手段）</td></tr><tr><td>管理画面の使いやすさ</td><td><span class="red">◎</span>（直感的で見やすいUI）</td><td>○（多機能だがやや複雑）</td><td>○</td><td>○</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">実装内容</span></h2>



<h3 class="wp-block-heading"><span id="toc6">実際の流れ（1回課金）</span></h3>



<ol class="wp-block-list">
<li>ユーザーがカード情報を入力（Pay.jsを使ってトークン化）</li>



<li>トークンをバックエンド（Python/Nodeなど）に送る</li>



<li>バックエンドがトークンを使ってPay.jp APIで課金</li>
</ol>



<p>&#x1f449; <strong>自分のサーバーでカード番号を扱わないから、セキュリティ的にも安心！</strong></p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">Pay.jpを利用するために必要なものは？</span></h3>



<ul class="wp-block-list">
<li>Pay.jpのアカウント：無料で登録OK</li>



<li>公開鍵（フロント用）と秘密鍵（バックエンド用）のAPIキー：Pay.jpのダッシュボードで取得</li>



<li>JavaScript or バックエンド（Python, PHP, Nodeなど）の知識少し</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">デモで見る「1回課金」の実装イメージ</span></h3>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="554" height="296" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-22-22.28.02.png" alt="【初心者向け】Pay.jpとは？クレカ決済を爆速導入できるサービスを解説！" class="wp-image-5094" style="width:322px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-22-22.28.02.png 554w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-22-22.28.02-300x160.png 300w" sizes="(max-width: 554px) 100vw, 554px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f5a5;&#xfe0f; フロントエンドの実装（Next.js）</span></p>



<p>tsxファイルで、トークン作成後にAPI呼び出しを行います。</p>



<p>下記の「&#x2705; 1つ渡せばOK」のコードですが、<code>cardNumber</code> 要素だけを <code>createToken</code> に渡しても、同じ <code>elements</code> インスタンスから作られ、かつ <code>mount()</code> された要素が揃っていれば、Pay.jp 側で裏側で統合されて処理されます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>"use client";
import { useEffect, useRef } from "react";
import { createCharge } from "@/lib/api/charge";

export default function CardForm() {
  const numberRef = useRef&lt;any>(null);
  const expiryRef = useRef&lt;any>(null);
  const cvcRef = useRef&lt;any>(null);

  useEffect(() => {
    const payjp = Payjp("pk_test_********");
    const elements = payjp.elements();

    numberRef.current = elements.create("cardNumber");
    expiryRef.current = elements.create("cardExpiry");
    cvcRef.current = elements.create("cardCvc");

    numberRef.current.mount("#card-number");
    expiryRef.current.mount("#card-expiry");
    cvcRef.current.mount("#card-cvc");
  }, []);

  const handleSubmit = async () => {
    const payjp = Payjp("pk_test_********");
    const result = await payjp.createToken(numberRef.current); // &#x2705; 1つ渡せばOK

    if (result.error) {
      alert("カード情報が正しくありません");
    } else {
      const token = result.id;
      await createCharge({ token, amount: 1000 });
    }
  };

  return (
    &lt;>
      &lt;div id="card-number" />
      &lt;div id="card-expiry" />
      &lt;div id="card-cvc" />
      &lt;button onClick={handleSubmit}>支払う&lt;/button>
    &lt;/>
  );
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useEffect</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useRef</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">createCharge</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/lib/api/charge</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">CardForm</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">numberRef</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useRef</span><span style="color: #ECEFF4">&lt;</span><span style="color: #81A1C1">any</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">null</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">expiryRef</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useRef</span><span style="color: #ECEFF4">&lt;</span><span style="color: #81A1C1">any</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">null</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">cvcRef</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useRef</span><span style="color: #ECEFF4">&lt;</span><span style="color: #81A1C1">any</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">null</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">useEffect</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">payjp</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Payjp</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">pk_test_********</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">elements</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">payjp</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">elements</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">numberRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">elements</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">create</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">cardNumber</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">expiryRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">elements</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">create</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">cardExpiry</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">cvcRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">elements</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">create</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">cardCvc</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">numberRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">mount</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">#card-number</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">expiryRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">mount</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">#card-expiry</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">cvcRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">mount</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">#card-cvc</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> [])</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">handleSubmit</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">payjp</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Payjp</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">pk_test_********</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">payjp</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">createToken</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">numberRef</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// &#x2705; 1つ渡せばOK</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">result</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">error</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">alert</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">カード情報が正しくありません</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">id</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createCharge</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">token</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">amount</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1000</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">card-number</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">card-expiry</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">card-cvc</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">onClick</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleSubmit</span><span style="color: #81A1C1">}&gt;</span><span style="color: #D8DEE9FF">支払う</span><span style="color: #81A1C1">&lt;/button&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>tsファイルで、クライアントコンポーネントで取得したトークンと、金額をFastAPIサーバーへ安全に送信するためのAPI呼び出し関数</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>type ChargePayload = {
  token: string;
  amount: number;
};

export const createCharge = async (
  payload: ChargePayload
): Promise&lt;"ok" | "error"> => {
  try {
    const res = await fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/api/charge`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    });
    return res.ok ? "ok" : "error";
  } catch (e) {
    return "error";
  }
};</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> ChargePayload </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  token</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">string;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  amount</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">number;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createCharge</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">payload</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> ChargePayload</span></span>
<span class="line"><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Promise</span><span style="color: #ECEFF4">&lt;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ok</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">error</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">try</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">`</span><span style="color: #81A1C1">${</span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">NEXT_PUBLIC_BACKEND_URL</span><span style="color: #81A1C1">}</span><span style="color: #A3BE8C">/api/charge</span><span style="color: #ECEFF4">`</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">method</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">POST</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">headers</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Content-Type</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">application/json</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">body</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">JSON</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">stringify</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">payload</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ok</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ok</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">error</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">catch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">error</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f9ea; バックエンドの実装（FastAPI）</span></p>



<p>Pay.jpのPython SDKを使って、受け取ったトークンを使い課金処理をします。<br>事前準備で<strong>Pay.jpが提供しているPython用のSDK（ソフトウェア開発キット）</strong>を <strong><code>pip install payjp</code> </strong>とコマンド実行してインストールしましょう。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import payjp
from fastapi import FastAPI, Request

payjp.api_key = "sk_test_********"  # 秘密鍵を設定

app = FastAPI()

@app.post("/api/charge")
async def charge(request: Request):
    body = await request.json()
    token = body&#91;"token"&#93;
    amount = body&#91;"amount"&#93;

    try:
        charge = payjp.Charge.create(
            amount=amount,
            currency="jpy",
            card=token
        )
        return {"status": "success", "charge_id": charge.id}
    except payjp.error.PayjpError as e:
        return {"status": "error", "message": str(e)}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> payjp</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> fastapi </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> FastAPI</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> Request</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">payjp</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">api_key </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">sk_test_********</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 秘密鍵を設定</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">app </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">FastAPI</span><span style="color: #ECEFF4">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">@</span><span style="color: #D08770">app</span><span style="color: #ECEFF4">.</span><span style="color: #D08770">post</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/api/charge</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">charge</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">request</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> Request</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">    body </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> request</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #ECEFF4">()</span></span>
<span class="line"><span style="color: #D8DEE9FF">    token </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> body</span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">token</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    amount </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> body</span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">amount</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">try</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">        charge </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> payjp</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">Charge</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">create</span><span style="color: #ECEFF4">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">amount</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">amount</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">currency</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">jpy</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">card</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">token</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">status</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">success</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">charge_id</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> charge</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">id</span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">except</span><span style="color: #D8DEE9FF"> payjp</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">error</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">PayjpError </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> e</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">status</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">error</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">message</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">str</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">e</span><span style="color: #ECEFF4">)}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc9">なぜトークン化はフロントで行う？</span></h3>



<ul class="wp-block-list">
<li>クレジットカード番号は<strong>絶対にバックエンドに送ってはいけない</strong>（セキュリティリスク）<br>→クレジットカード番号は PCI DSS などの厳しいルールに則って管理する必要があり、サーバーで直接扱うと大きなセキュリティリスクになります。そのため、Pay.jsを使って<strong>トークン化</strong>（疑似的なカード情報への変換）を行い、サーバーではそのトークンだけを扱うことで、<strong>セキュリティを保ちながら決済処理</strong>ができます。</li>



<li>Pay.jsがカード番号をトークンに変換してくれる（createToken）</li>



<li>自分のサーバーでは<strong>トークンしか扱わない</strong>ため、安心・安全</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc10">実装注意ポイントまとめ</span></h3>



<ul class="wp-block-list">
<li>公開鍵（pk_test_〜）はフロントで使う</li>



<li>秘密鍵（sk_test_〜）はバックエンドで使う</li>



<li>カード番号などはトークン化され、<strong>自分のサーバーでは触れない仕組み</strong>になっている（PCI DSS対応）</li>



<li>開発モードではテストカード <code>4242 4242 4242 4242</code> が使える（有効期限やCVCは適当でOK）<br><a href="https://docs.pay.jp/v1/testcard" title="">テストカード一覧</a></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>他のAPI連携の記事はこちらです！</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/06/26/nextauth-js/" title="Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-15-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-15-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-15-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-15-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Next.jsでログイン機能を実装｜NextAuth.jsでID・パスワード認証対応</div><div class="blogcard-snippet internal-blogcard-snippet">Next.js アプリにログイン機能を追加したい方へ。NextAuth.js を使った ID・パスワード認証、セッション管理、コールバック設定までやさしく解説。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/08/docker-mailpit/" title="【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-22-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-22-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-22-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-22-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-22-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】</div><div class="blogcard-snippet internal-blogcard-snippet">開発中のメール送信テスト、毎回Gmailを使っていませんか？Mailpitを使えば、ローカル環境でメールの送信・確認が簡単＆安全にできます。DockerとNext.jsを使った導入手順を初心者向けに解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">初心者におすすめなのはどれ？</span></h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>条件</th><th>おすすめサービス</th></tr></thead><tbody><tr><td>はじめて決済を導入する人</td><td>&#x2705; Pay.jp</td></tr><tr><td>海外展開も視野に入れている場合</td><td>&#x2705; Stripe</td></tr><tr><td>店舗＋ネットで使いたい</td><td>&#x2705; Square</td></tr><tr><td>コンビニ払いや多様な支払いを取り入れたい</td><td>&#x2705; Komoju</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/22/pay-jp/">【初心者向け】Pay.jpとは？クレカ決済を爆速導入できるサービスを解説！特徴・使い方・実装例まとめ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/22/pay-jp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者向け】現場で役立つGitHubコマンド厳選まとめ｜GUIから卒業したい初心者へ！</title>
		<link>https://it-bokenki.com/2025/07/21/github-commands/</link>
					<comments>https://it-bokenki.com/2025/07/21/github-commands/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Mon, 21 Jul 2025 13:26:49 +0000</pubDate>
				<category><![CDATA[開発ツール（Dev Tools）]]></category>
		<category><![CDATA[GitHub]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=5034</guid>

					<description><![CDATA[<p>プロが教える、業界最前線のノウハウ【Coloso】 困ってた自分に届けたい話 「あのとき、コマンド知っていれば…！」 初めてチーム開発に参加したとき、GitHubの操作に自信がなくて、GUIでぽちぽちと安全そうなボタンを [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/21/github-commands/">【初心者向け】現場で役立つGitHubコマンド厳選まとめ｜GUIから卒業したい初心者へ！</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+601S1">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=250630247739&#038;wid=001&#038;eno=01&#038;mid=s00000026713001008000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www15.a8.net/0.gif?a8mat=457VJB+C7ZCTU+5Q4A+601S1" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+5YRHE">プロが教える、業界最前線のノウハウ【Coloso】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>「あのとき、コマンド知っていれば…！」</p>



<p>初めてチーム開発に参加したとき、GitHubの操作に自信がなくて、GUIでぽちぽちと安全そうなボタンを押すばかり。正直、<strong>黒い画面（CLI）ってプロっぽくてかっこいいけど、自分にはまだ早い</strong>と思ってました。</p>



<p>でも、GUIのツールがアップデートされたり、チームごとに使うツールが違ったりすると、<br>「<strong>え、どこ押せばよかったっけ？</strong>」と、毎回迷子に。</p>



<p>そのうち、</p>



<ul class="wp-block-list">
<li><strong>同じブランチ名で強引にプッシュしてコンフリクトの嵐</strong></li>



<li><strong>コミットメッセージがバラバラで履歴がぐちゃぐちゃ</strong></li>



<li><strong>リモートの変更を取り込まないまま作業を進めて大混乱</strong></li>
</ul>



<p>という、地味だけど痛いトラブルを何度も経験。</p>



<p>「<strong>コマンドで操作できていれば、もっと早く正しく対応できたのに…！</strong>」と何度も後悔しました。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">リポジトリの初期化・クローン</span></h2>



<h3 class="wp-block-heading"><span id="toc3">新しく作るとき（自分でゼロから開発を始めるとき）</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git init</code></pre></div>



<p>自分だけのポートフォリオサイトを作るときや、チームにまだ共有しない段階の個人開発を始めるときに、<strong>すでに作成したフォルダの中でこのコマンドを打つことで、そのフォルダが「Gitで履歴管理できる状態」になります</strong>。その後、GitHubに新しく作ったリモートリポジトリと紐づけるためには、次のようにします。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git remote add origin https://github.com/ユーザー名/リポジトリ名.git</code></pre></div>



<p>これで、ローカルとGitHubの接続が完了します。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc4">他の人のリポジトリやチームのリポジトリを使いたいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git clone https://github.com/チーム/リポジトリ名.git</code></pre></div>



<p>すでにあるプロジェクトを自分のPCに持ってきたいときに使います。GitHubの「Code」ボタンからURLをコピーして、ターミナルでこのコマンドを実行すると、フォルダごと全部ダウンロードされます。履歴も含まれるので、過去の変更もすべて確認できます。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">コミットと履歴管理</span></h2>



<h3 class="wp-block-heading"><span id="toc6">ファイルを追加・変更したら履歴に残すとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git add .
git commit -m &quot;ヘッダーのデザインを調整&quot;</code></pre></div>



<p>コード修正したあと、そのまま次の作業に進むのではなく、まず変更を一つの「区切り」として記録しておきたいときに使います。<br><code>git add .</code> は、全ての変更されたファイルを「記録準備OK」の状態にするコマンドです。<br>その後、<code>git commit -m "..."</code> でメッセージをつけて保存します。<br>ここでのメッセージは「何を」「なぜ」変更したのかをチームがわかるように簡潔に書きましょう。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">直前のコミットを修正したいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git commit --amend</code></pre></div>



<p>「コミットしたあとにファイルの入れ忘れに気づいた」「メッセージに誤字があった」「やっぱりちょっと修正したい」——そんなときに使えるのが <code>git commit --amend</code> です。</p>



<p>このコマンドを実行すると、<strong>直前のコミットを上書きする形で修正</strong>できます。たとえば、ファイルを追加し忘れていたなら、そのファイルを <code>git add</code> でステージングしてから <code>git commit --amend</code> を実行すれば、1つのまとまったコミットにすることができます。</p>



<p>なお、<strong>すでにGitHubにpushしているコミットをamendすると履歴が変わるため注意</strong>が必要です（その場合は <code>--force</code> 付きで再pushが必要になります）。</p>



<p>ローカル作業中に「コミットやり直したい」と思ったら、まず <code>git commit --amend</code> を思い出してみてください</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">過去の履歴をパッと確認したいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git log --oneline --graph --decorate</code></pre></div>



<p>誰がいつどんな変更をしたかを見たいときに使います。<br>長い履歴をだらだらと読むのではなく、1行ずつコンパクトに見られるので視認性がとても良いです。<br><code>--graph</code> をつけることで、どのブランチがどこから分かれて、どこで合流したかもわかりやすくなります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">ブランチ操作</span></h2>



<h3 class="wp-block-heading"><span id="toc10">作業用の新しいブランチを作って、すぐに移動したいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git switch -c 新しいブランチ名</code></pre></div>



<p>最近のGitでは、ブランチの切り替えや作成は <code>git checkout</code> よりも <code>git switch</code> を使うのが主流になっています。たとえば新しいブランチを作ってすぐにそのブランチに移動したいときには、<code>git switch -c feature/新しいブランチ名</code> のように書くと、一発でローカルブランチ作成・切り替えが完了します。<br>すでに作られているブランチに移動したいときは、<code>git switch ブランチ名</code> だけでOKです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc11">今のブランチを確認したいとき・他のブランチを見たいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git branch</code></pre></div>



<p>今までに作成されたローカルブランチが一覧で表示されます。今自分がいるブランチには <code>*</code> がついています。作業の前に「今どこにいるか」を確認する習慣をつけるとミスが減ります。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>異なるローカルブランチで作業していたことがあり、大変な目に何度もあっている主です。この習慣は大切です&#8230; !</p>
</div></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc12">作業が終わったブランチを削除したいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git branch -d feature/完了したブランチ</code></pre></div>



<p>不要になったブランチはこまめに消すことで、ローカルがスッキリします。<br>まだマージしていないのに間違って消そうとすると警告が出ますが、どうしても削除したい場合は <code>-D</code> を使って強制削除もできます。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc13">リモートリポジトリ操作</span></h2>



<h3 class="wp-block-heading"><span id="toc14">自分の作業をGitHubにアップしたいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git push origin feature/新機能名</code></pre></div>



<p>作業した内容をチームに共有したいときには、このコマンドでGitHubにアップします。<code>origin</code> はGitHub側のリポジトリ名を意味し、その後に続くのが自分のブランチ名です。もし初めてのプッシュで「上手くリンクできていない」場合は、次のように書くことで自動的に紐づけされます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git push -u origin feature/新機能名</code></pre></div>



<p>こうしておけば、次回以降は <code>git push</code> だけでOKになります。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc15">他の人の変更を自分の作業に反映させたいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git pull --rebase</code></pre></div>



<p>GitHub上で別の人が更新していた場合、自分のローカルを最新にしてから作業を再開したいときに使います。<code>--rebase</code> をつけることで、マージコミットを発生させずに履歴をキレイな状態に保てます。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc16">マージ・コンフリクト解消</span></h2>



<h3 class="wp-block-heading"><span id="toc17">他のブランチの内容を今のブランチに統合したいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git merge ブランチ名</code></pre></div>



<p>たとえば、現在作業している <code>feature/login-form</code> ブランチに、チームがまとめているメインの開発ブランチ（例：<code>develop</code> や <code>main</code>）の最新変更を取り込みたいときに使います。</p>



<p>この「ブランチ名」の部分には、「取り込みたい変更がある側のブランチ名」を指定します。よくある例としては <code>develop</code> や <code>main</code> ですが、会社やプロジェクトによっては <code>staging</code> や <code>release</code> など別の名前を使っていることもあります。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc18">コンフリクトが起きたとき</span></h3>



<p>ファイルの中に <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code> や <code>=======</code> が現れたら、それがコンフリクトです。<br>自分の変更と他の人の変更がぶつかってしまった状態なので、エディタで手動で「どちらを残すか」「どう融合するか」を判断します。修正したら、次のコマンドでコンフリクトが解消されたことをGitに伝えます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git add コンフリクト解消済みファイル
git commit</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc19">トラブルシュート</span></h2>



<h3 class="wp-block-heading"><span id="toc20">直前のコミットとの差分を見たいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git diff HEAD~1 HEAD</code></pre></div>



<p>「この前のコミットから何を変えたっけ？」という場面で使います。ファイルを開かなくても、ターミナル上で変更点が確認できます。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc21">昔のコミットに戻したいとき（でも履歴は壊したくない）</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git revert &lt;コミットID&gt;</code></pre></div>



<p>「やっぱりこの機能、いらなかったな…」というときに使います。<code>revert</code> を使えば、「そのコミットを取り消すための新しいコミット」を作ってくれるので、履歴はきれいなまま残ります。履歴を壊す <code>reset</code> より安全です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc22">作業中の変更を一時的に退避したいとき</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>git stash</code></pre></div>



<p>今まさにファイルを編集している途中に「緊急で別ブランチに切り替えて修正お願い！」という指示が来たとします。でもまだコミットもしていないし、今の作業内容は残しておきたい…。そんなときに便利なのがこの <code>git stash</code> コマンドです。</p>



<p>これを実行すると、作業中の変更内容を一時的に「しまっておく」ことができます。ブランチを切り替えたあと、元に戻ってから <code>git stash pop</code> を使えば、さっきまでの変更内容がちゃんと復元されます。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/21/github-commands/">【初心者向け】現場で役立つGitHubコマンド厳選まとめ｜GUIから卒業したい初心者へ！</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/21/github-commands/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>as const って何？「値＝型」にできるTypeScriptの型ガード術</title>
		<link>https://it-bokenki.com/2025/07/20/as-const/</link>
					<comments>https://it-bokenki.com/2025/07/20/as-const/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Sun, 20 Jul 2025 07:06:16 +0000</pubDate>
				<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=5021</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 TypeScript定数を定義して、あとからそのまま型にも使いたいとき。 「書いた値を使って型をつくったはずなのに、strin [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/20/as-const/">as const って何？「値＝型」にできるTypeScriptの型ガード術</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>TypeScript定数を定義して、あとからそのまま型にも使いたいとき。</p>



<p>「書いた値を使って型をつくったはずなのに、string型になってる…」<br>「え、これユニオン型じゃないの？なんで？」<br>って何回もなった。</p>



<p>毎回型を別で書き直すの、地味に面倒くさいしミスも増える。<br>そんなときに知った <code>as const</code>、たった一言で「値＝型」になって、ほんとに楽になった。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">as constとは？</span></h2>



<p><code>as const</code> は TypeScript の構文で、<strong>値を“そのまま”の形で型として固定する</strong>ための書き方です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const COLORS = &#91;"red", "blue", "green"&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>このとき、<code>COLORS</code> の型は <code>string[]</code> になります。<br>つまり、 <code>"yellow"</code> など本来想定していない値も通ってしまう可能性があります。</p>



<p>しかし <code>as const</code> を使うと</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const COLORS = &#91;"red", "blue", "green"&#93; as const;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span></code></pre></div>



<p>これだけで、型はこうなります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>readonly &#91;"red", "blue", "green"&#93;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">readonly</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span></span></code></pre></div>



<p>中身の <code>"red" | "blue" | "green"</code> を型として使えるようになります。この状態になると、「この配列の中には、決まった値しか入っていない」と型で表現できるようになります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">「型」ってそもそも何？</span></h2>



<p>TypeScriptでは、以下のような<strong>基本的な型（プリミティブ型）</strong>があります。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>型名</th><th>意味</th><th>例</th></tr></thead><tbody><tr><td><code>string</code></td><td>文字列</td><td><code>"hello"</code></td></tr><tr><td><code>number</code></td><td>数値</td><td><code>42</code></td></tr><tr><td><code>boolean</code></td><td>真偽値</td><td><code>true</code> / <code>false</code></td></tr><tr><td><code>string[]</code></td><td>文字列の配列</td><td><code>["a", "b"]</code></td></tr></tbody></table></figure>



<p>多くの人は「型＝stringやnumberのこと」と思っているはずです。<br>でも、TypeScriptには他にも重要な型の考え方があります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc4">リテラル型とユニオン型の違い</span></h3>



<p><strong>リテラル型</strong>：特定の値だけを許す型</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const color: "red" = "red"; // "red" だけOK</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">color</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// &quot;red&quot; だけOK</span></span></code></pre></div>



<p><strong>ユニオン型</strong>：複数の値の中からどれか1つを許す型</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>type Color = "red" | "blue" | "green";</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Color </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>つまり、リテラル型は1つだけOK、ユニオン型は&#8221;いくつかから1つ選ぶ&#8221;感じです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc5">配列で使う as const</span></h2>



<p>たとえば、次のようなコードがあります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const COLORS = &#91;"red", "blue", "green"&#93; as const;
type Color = typeof COLORS&#91;number&#93;;
// → "red" | "blue" | "green"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">red</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">blue</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">green</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Color </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// → &quot;red&quot; | &quot;blue&quot; | &quot;green&quot;</span></span></code></pre></div>



<p><span class="keyboard-key">&#x1f4d3; 説明</span></p>



<ul class="wp-block-list">
<li><code>as const</code>：配列の中身を変更できないようにし、&#8221;red&#8221; などの固定値として扱う</li>



<li><code>typeof COLORS[number]</code>：配列内の要素を全部取り出して、型にする</li>
</ul>



<p>これで Color型には &#8220;red&#8221;、&#8221;blue&#8221;、&#8221;green&#8221; だけが使えるようになります。</p>



<p><span class="keyboard-key">&#x1f50d; なぜnumberを使うの？</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>type Color = typeof COLORS&#91;number&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Color </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">COLORS</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>この <code>number</code> は「配列の中のすべての値を取り出す」という意味です。配列は <code>COLORS[0]</code>, <code>COLORS[1]</code> のように数字（=number）でアクセスします。</p>



<p>だから <code>COLORS[number]</code> と書くと、「すべてのインデックス番号に対応する値＝全要素」を指すことになります。これは TypeScript の<strong>決まり文句</strong>なので、覚えてしまえばOKです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc6">オブジェクトで使う as const</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const STATUS = {
  OK: 200,
  NOT_FOUND: 404,
} as const;

type StatusCode = typeof STATUS&#91;keyof typeof STATUS&#93;;
// → 200 | 404</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">STATUS</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">OK</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">200</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">NOT_FOUND</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">404</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> StatusCode </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">STATUS</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">keyof</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">STATUS</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// → 200 | 404</span></span></code></pre></div>



<p><span class="keyboard-key">&#x1f4d3; 説明</span></p>



<ul class="wp-block-list">
<li><code>as const</code>：オブジェクトの中身（200 や 404）を固定する</li>



<li><code>typeof STATUS[keyof typeof STATUS]</code>：すべての値をまとめて型にする</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc7">結局何が便利なの？</span></h2>



<p><code>as const</code> を使うと、値と型の“二重管理”が不要になります。<br>たとえば、ボタンの種類を定義しておきたいとき：</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const BUTTON_TYPES = &#91;"primary", "secondary", "danger"&#93; as const;
type ButtonType = typeof BUTTON_TYPES&#91;number&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUTTON_TYPES</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">primary</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">secondary</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">danger</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> ButtonType </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUTTON_TYPES</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>このようにしておけば：</p>



<ul class="wp-block-list">
<li>値としてボタンタイプを配列で定義</li>



<li>型としてもそのまま使える（&#8221;primary&#8221; | &#8220;secondary&#8221; | &#8220;danger&#8221;）</li>
</ul>



<p>あとから値を追加・削除しても、型も一緒に変わるので、<strong>管理がラクになってミスも防げる</strong>んです。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/18/shadcn-ui/" title="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-11-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</div><div class="blogcard-snippet internal-blogcard-snippet">shadcn/uiは、Tailwind CSSベースで使える高品質なReact UIライブラリです。初心者にもわかりやすく、shadcn/uiの特徴や導入手順、使い方、MUIなど他のライブラリとの違いまで徹底解説。カスタマイズしやすくて実務にも最適な理由を紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">as const のメリット</span></h2>



<p><span class="keyboard-key">&#x274c; as const なし</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const roles = &#91;"admin", "user"&#93;;
type Role = typeof roles&#91;number&#93;; // → string</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Role </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// → string</span></span></code></pre></div>



<p><code>"admin"</code> でも 定義していない <code>"manager"</code> でも通ってしまいます。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x2705; as const あり</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const roles = &#91;"admin", "user"&#93; as const;
type Role = typeof roles&#91;number&#93;; // → "admin" | "user"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">admin</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">user</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const;</span></span>
<span class="line"><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> Role </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">typeof</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">roles</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">number</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// → &quot;admin&quot; | &quot;user&quot;</span></span></code></pre></div>



<p>型が限定され、<strong>間違った値を弾ける</strong>ようになります。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/20/as-const/">as const って何？「値＝型」にできるTypeScriptの型ガード術</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/20/as-const/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</title>
		<link>https://it-bokenki.com/2025/07/18/shadcn-ui/</link>
					<comments>https://it-bokenki.com/2025/07/18/shadcn-ui/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 17 Jul 2025 15:36:58 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Next.js]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4973</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 CSSって実装方法いろいろありますよね。 「とりあえず動くけど、チーム開発だとCSSが競合してグチャグチャになる…」「時間かけ [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/18/shadcn-ui/">【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>CSSって実装方法いろいろありますよね。</p>



<ul class="wp-block-list">
<li><code>.css</code> ファイル作ってインポート</li>



<li>タグに <code>style={{}}</code> で直接書く</li>



<li>Sass や CSS Modules、Styled Components などのライブラリも…</li>
</ul>



<p>「とりあえず動くけど、チーム開発だとCSSが競合してグチャグチャになる…」<br>「時間かけてUI組んだのに、おしゃれにならない…」<br>そんな悩みを抱えていた自分が「これだ！」と思えたのが、<strong>shadcn/ui</strong> というUIライブラリでした。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">shadcn/uiとは？</span></h2>



<p><strong>shadcn/ui</strong> は、Tailwind CSS をベースにした、柔軟で拡張可能な UI コンポーネント集です。</p>



<p>よく使うパーツ（ボタン、モーダル、チェックボックスなど）がすぐ使える状態で提供され、しかも<strong>自分のプロジェクトに直接コンポーネントのコードが追加される</strong>のが特徴です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">他のUIライブラリとの比較</span></h2>



<p><span class="keyboard-key">&#x274c; 普通のUIライブラリ（npmパッケージ）</span></p>



<ul class="wp-block-list">
<li><code>npm install</code> で <strong>ライブラリをインストールするだけ</strong></li>



<li>中身（ボタンの見た目など）は <strong>触れない・カスタムしにくい</strong></li>



<li>例：MUI、Chakra UI、Bootstrap</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x2705; shadcn/ui（プロジェクトに直接追加される）</span></p>



<ul class="wp-block-list">
<li>コマンドで UI コンポーネントの<strong>実物のコードを自分のプロジェクトにコピー</strong>してくれる</li>



<li>コピーされたコンポーネントは <code>/components/ui/button.tsx</code> などに置かれる</li>



<li>自分で<strong>見た目や動きを好きに変更できる</strong>（完全に自作と同じ感覚）</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>&#x25b6; UIライブラリの比較表</p>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">ライブラリ</th><th>カスタマイズ性</th><th>スタイリング</th><th>メンテナンス性</th><th class="has-text-align-center" data-align="center">使いやすさ</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center"><strong>shadcn/ui</strong></td><td>◎（自由編集可）</td><td>Tailwind CSS（自由）</td><td>自分で管理（柔軟）</td><td class="has-text-align-center" data-align="center">◯</td></tr><tr><td class="has-text-align-center" data-align="center">MUI</td><td>△（props依存）</td><td>styled-components風</td><td>バージョン依存が強い</td><td class="has-text-align-center" data-align="center">◎</td></tr><tr><td class="has-text-align-center" data-align="center">Chakra UI</td><td>◯（props多い）</td><td>Emotionベース</td><td>安定している</td><td class="has-text-align-center" data-align="center">◎</td></tr><tr><td class="has-text-align-center" data-align="center">Tailwind UI</td><td>△（HTMLベース）</td><td>Tailwind CSS</td><td>商用ライセンス必要</td><td class="has-text-align-center" data-align="center">◯</td></tr><tr><td class="has-text-align-center" data-align="center">Bootstrap</td><td>×（固定）</td><td>独自CSS</td><td>重い＆レガシー</td><td class="has-text-align-center" data-align="center">△</td></tr></tbody></table></figure>



<p><strong>shadcn/uiは「柔軟さ」と「今風の設計」が強み。</strong><br>プロジェクトのデザインや設計方針にこだわりたいチームやエンジニアに向いています。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">shadcn/ui 導入手順</span></h2>



<p>下記の前提条件のもと、shadcn/ui 導入手順をご説明します。</p>



<ul class="wp-block-list">
<li>Next.js（React）プロジェクト</li>



<li>Tailwind CSSがすでに導入済み</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc5">STEP１：初期化</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># 初期セットアップ（初回のみ）
npx shadcn@latest init</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x26a0;&#xfe0f; 注意「shadcn-ui@latest」は非推奨？</span></p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="172" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-1024x172.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4974" style="width:691px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-1024x172.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-300x50.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35-768x129.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.10.35.png 1178w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><code>npx shadcn-ui@latest init</code> のコマンドは古いコマンドです。これを使うと「古い CLI です」とエラーが出ることがあります。<strong>現在は上記のように <code>shadcn</code> に名前が変更されています。</strong></p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">STEP２：初期設定 バージョン</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>Need to install the following packages:
shadcn@2.9.2
Ok to proceed? (y) y</code></pre></div>



<ul class="wp-block-list">
<li><code>shadcn</code> のバージョン <code>2.9.2</code> を一時的にインストールして使ってもいいか？</li>



<li><code>npx</code> は必要なパッケージをその場で取得して実行する</li>
</ul>



<p>という確認です。<br><code>y</code> を入力すれば、そのまま <code>shadcn</code> CLI が使えるようになります。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">STEP３：初期設定 UIの色選択</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>Which color do you want to use as base color?
  - Slate
  - Gray
  - Zinc
  - Neutral
  - Stone
  - Red
  - Blue
  - Green</code></pre></div>



<p>UIのカラー選択について聞かれています。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f4dd; 補足：色選択の戦略</span></p>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">カラー</th><th>特徴・印象</th><th>向いている用途</th><th>傾向・人気度</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center"><strong>Gray</strong></td><td>標準的なグレー。無難で柔軟性が高い</td><td>BtoC向けUI全般。カラフルなアクセントと相性◎</td><td><strong>shadcn初期からの定番</strong></td></tr><tr><td class="has-text-align-center" data-align="center"><strong>Zinc</strong></td><td>クールでメカっぽい無機質な印象</td><td>開発者向けダッシュボード、技術系LPなど</td><td>最近人気上昇中</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>Neutral</strong></td><td>脱色感のある、最も中立的な色合い</td><td>ミニマル・モダンなサイト向け</td><td>人気はやや低め</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>Stone</strong></td><td>わずかに茶系の温かみあり</td><td>雑誌風UI、ナチュラル系、アート系LPなど</td><td>おしゃれ系・差別化目的で選ばれる</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">STEP４：UIコンポーネントを追加</span></h3>



<p>下記のコマンドを実行すると　src/components/ui配下にそれぞれのUIファイルが作成されます。</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="434" height="246" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4975" style="width:300px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33.png 434w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-300x170.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.31.33-376x212.png 376w" sizes="auto, (max-width: 434px) 100vw, 434px" /></figure>



<p>Tailwind CSS のクラスを使ってスタイリングされており、即他のコンポーネントでimportして利用できます。フォルダ移動しても問題ありません。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># ボタンを追加
npx shadcn@latest add button

# inputタグを追加
npx shadcn@latest add input

# チェックボックスを追加
npx shadcn@latest add checkbox</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">shadcn/ui 実装</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/checkbox";
import { Button } from "@/components/ui/button";

export default function Home() {
  return (
      &lt;div className=" flex flex-col items-center space-y-4 mt-10">
        &lt;Input placeholder="メールアドレスを入力" className="w-&#91;18rem&#93;" />

        &lt;div className="flex items-center">
          &lt;Checkbox id="terms" />
          &lt;label htmlFor="terms" className="ml-2 text-sm">
            利用規約に同意する
          &lt;/label>
        &lt;/div>
        
        &lt;Button>送信&lt;/Button>
      &lt;/div>
  );
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Input</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/ui/input</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Checkbox</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/checkbox</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/ui/button</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Home</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C"> flex flex-col items-center space-y-4 mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">placeholder</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">メールアドレスを入力</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">w-&#91;18rem&#93;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">flex items-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Checkbox</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">terms</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">htmlFor</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">terms</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ml-2 text-sm</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            利用規約に同意する</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">送信</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>&#x25b6; 実際に表示されるUI</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="950" height="392" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4977" style="border-width:1px;width:594px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45.png 950w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45-300x124.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.37.45-768x317.png 768w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure>



<p>たった数行のコードで、ここまでスタイリッシュなフォームが作れます！<br>初期化してから10分かからないくらいです。とても簡単です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">知っておきたい実装方法「スタイルの切り替えスイッチ」</span></h2>



<p>CSSを書いていると、同じ見た目のように見えて少しだけスタイルが違う、というパターンが増えてきます。</p>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">たとえば…</span></p>



<ul class="wp-block-list">
<li>青い「送信」ボタン</li>



<li>赤い「削除」ボタン</li>



<li>枠だけの「戻る」ボタン</li>
</ul>



<p>こんなふうに種類を切り替えたい時に、<strong>毎回 className を条件分岐するのって大変です。</strong>そんなときに便利なのが、<strong><code>variant</code> という考え方</strong>です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc11">variant を使うと、スタイルの管理が楽！</span></h3>



<p><code>variant</code> はざっくり言うと、「スタイルの種類をキーワードで切り替える仕組み」です。</p>



<p>ボタンを例にすると、このように実装できます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import { Button } from "@/components/ui/button";

export default function Home() {
  return (
      &lt;div className=" flex flex-col items-center space-y-4 mt-10">
        &lt;Button>デフォルト&lt;/Button>
        &lt;Button variant="destructive">削除&lt;/Button>
        &lt;Button variant="outline">戻る&lt;/Button>
      &lt;/div>
  );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/components/ui/button</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Home</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C"> flex flex-col items-center space-y-4 mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">デフォルト</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">variant</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">destructive</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">削除</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">variant</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">outline</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">戻る</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>&#x25b6; 実際に表示されるUI</p>



<figure class="wp-block-image aligncenter size-full is-resized has-custom-border"><img loading="lazy" decoding="async" width="424" height="388" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.46.27.png" alt="【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ" class="wp-image-4979" style="border-width:1px;width:293px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.46.27.png 424w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-17-23.46.27-300x275.png 300w" sizes="auto, (max-width: 424px) 100vw, 424px" /></figure>



<p>文字列で渡すだけで、見た目がガラッと変わります。<br>この <code>variant="◯◯"</code> がスタイルの切り替えスイッチになるんです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc12">中身はカスタマイズOK！</span></h3>



<p>実はこの <code>variant</code> の仕組みは <code>button.tsx</code> に定義されています。</p>



<p>たとえば以下のように書かれています。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// components/ui/button.tsx の一部
const buttonVariants = cva(
  "inline-flex items-center justify-center text-sm font-medium",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
        destructive:
          "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
        outline:
          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// components/ui/button.tsx の一部</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buttonVariants</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">cva</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">inline-flex items-center justify-center text-sm font-medium</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">variants</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">variant</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">default</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-primary text-primary-foreground shadow-xs hover:bg-primary/90</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">destructive</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">outline</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">defaultVariants</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">variant</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">default</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>つまり、この <code>button.tsx</code> ファイルを<strong>自由に編集</strong>ができます！</p>



<p>たとえば、次のように <code>variant</code> に <code>custom</code> を追加すれば…</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>custom: "bg-purple-500 text-white hover:bg-purple-600"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">custom</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-purple-500 text-white hover:bg-purple-600</span><span style="color: #ECEFF4">&quot;</span></span></code></pre></div>



<p>オリジナルのスタイルが使えるようになります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Button variant="custom">カスタム&lt;/Button></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Button</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">variant</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">custom</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">カスタム</span><span style="color: #81A1C1">&lt;/</span><span style="color: #8FBCBB">Button</span><span style="color: #81A1C1">&gt;</span></span></code></pre></div>



<p>と書くだけで、紫色のカスタムボタンが表示されます。</p>



<p>ライブラリに依存せず、<strong>自分好みのデザインに柔軟にカスタマイズできる</strong>のが shadcn/ui の大きな魅力です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc13">shadcn/ui のメリット・デメリット</span></h2>



<p><span class="keyboard-key">メリット</span></p>



<ul class="wp-block-list">
<li>&#x2705; <strong>自由に編集できる</strong><br>コードがプロジェクトに含まれるため、業務要件に合わせて修正可能</li>



<li>&#x2705; <strong>Tailwindと相性抜群</strong><br>スタイリングが統一され、CSS設計に悩まなくて済む</li>



<li>&#x2705; <strong>導入が簡単</strong><br><code>npx shadcn@latest add xxx</code> でどんどん追加できる</li>



<li>&#x2705; <strong>全てオープンな React コンポーネント</strong><br>依存性を最小限に抑えられる</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">デメリット</span></p>



<ul class="wp-block-list">
<li>&#x274c; <strong>バージョン管理は自己責任</strong><br>一括更新されないのでメンテの工夫が必要</li>



<li>&#x274c; <strong>生成ファイルが増える</strong><br>チーム内で「どこから来たファイルか」把握する工夫が必要</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p>UIライブラリで次におすすめなのはこちらです&#x1f91e;</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/06/14/mui/" title="MUIとは？ReactでおしゃれなUIがすぐ作れるライブラリを解説！" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/06/２行-5-160x90.png 160w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">MUIとは？ReactでおしゃれなUIがすぐ作れるライブラリを解説！</div><div class="blogcard-snippet internal-blogcard-snippet">MUIはReactで美しいUIを簡単に作れるライブラリ。豊富なコンポーネントと柔軟なカスタマイズが魅力です。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc14">どんなプロジェクトに向いてる？</span></h2>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">向いているプロジェクト</th><th>理由</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center">BtoB SaaS系</td><td>UIに一貫性が必要で、カスタマイズ性が重要</td></tr><tr><td class="has-text-align-center" data-align="center">スタートアップ</td><td>開発速度が早く、軽量で変更に強い構成が求められる</td></tr><tr><td class="has-text-align-center" data-align="center">小〜中規模チーム開発</td><td>全員が同じUIスタイルを使いやすくなる</td></tr><tr><td class="has-text-align-center" data-align="center">Tailwindを使っている</td><td>スタイリングが完全に統一できる</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/18/shadcn-ui/">【初心者向け】shadcn/uiとは？導入方法・使い方・メリットを徹底解説｜Tailwind対応のUIライブラリ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/18/shadcn-ui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>UUIDとは？主キーに使われる理由と連番との違いをわかりやすく解説</title>
		<link>https://it-bokenki.com/2025/07/10/uuid/</link>
					<comments>https://it-bokenki.com/2025/07/10/uuid/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Wed, 09 Jul 2025 15:31:55 +0000</pubDate>
				<category><![CDATA[IT基礎知識]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4612</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 「UUIDってなに？ただの英数字の羅列でしょ？主キーなら 1, 2, 3, ... の連番でいいじゃん。これ間違いのコードだな [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/uuid/">UUIDとは？主キーに使われる理由と連番との違いをわかりやすく解説</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>「UUIDってなに？ただの英数字の羅列でしょ？主キーなら <code>1, 2, 3, ...</code> の連番でいいじゃん。これ間違いのコードだな」と思って、<strong>自信満々に連番に直したら</strong>……</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/themes/cocoon-master/images/man.png" alt="上司" class="speech-icon-image"/></figure><div class="speech-name">上司</div></div><div class="speech-balloon">
<p>それ、意図的にUUID使ってるやつだから！</p>
</div></div>



<p>コードレビューで盛大に恥をかいたのは、まぎれもない私です。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<h2 class="wp-block-heading"><span id="toc2">UUIDとは？世界で一意なIDを自動で発行する仕組み</span></h2>



<p><strong>UUID</strong>（Universally Unique Identifier：ユニバーサルユニークアイデンティファイア）とは、<strong>重複しないIDを自動生成するための仕組み</strong>です。</p>



<p>たとえば以下のような形式です</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>550e8400-e29b-41d4-a716-446655440000</code></pre></div>



<p>Pythonでは <code>uuid4()</code> を使えば、ランダムなUUID（バージョン4）を簡単に作成できます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from uuid import uuid4

print(str(uuid4()))
// 出力例: 9b9f8c2b-3b33-4d89-9a5b-b5bfb17906f2
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uuid</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">uuid4</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">print</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">str</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">uuid4</span><span style="color: #D8DEE9FF">()))</span></span>
<span class="line"><span style="color: #616E88">// 出力例: 9b9f8c2b-3b33-4d89-9a5b-b5bfb17906f2</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc3">UUIDのバージョン一覧</span></h3>



<figure class="wp-block-table"><table><thead><tr><th class="has-text-align-center" data-align="center">Ver</th><th>どうやって作られる？</th><th>どんなときに使う？</th><th>イメージ</th></tr></thead><tbody><tr><td class="has-text-align-center" data-align="center"><strong>v1</strong></td><td>作成した時間＋パソコンの情報</td><td>データを時間順に並べたいとき</td><td>タイムスタンプ付きのID</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>v2</strong></td><td>OSのユーザー情報などを追加（特殊）</td><td>特別なシステムでのみ使用（一般では使わない）</td><td>普段は使わなくてOK</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>v3</strong></td><td>入力した文字列から<strong>毎回同じID</strong>を作る（古い方式）</td><td>「同じ名前」に対して「毎回同じID」を作りたいとき</td><td>名前にひもづくID</td></tr><tr><td class="has-text-align-center" data-align="center"><strong><span class="red">v4</span></strong></td><td><strong>完全にランダム</strong>な文字列</td><td>一意なIDがほしいとき全般</td><td>サイコロで作るID（これが定番）</td></tr><tr><td class="has-text-align-center" data-align="center"><strong>v5</strong></td><td>v3と同じだが、より安全に作られる</td><td>v3と同様。URLやドメイン名に対応した固定IDを作りたいとき</td><td>v3の強化版</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4"> なぜ連番ではダメなの？UUIDが選ばれる理由</span></h2>



<h3 class="wp-block-heading"><span id="toc5">理由１： セキュリティが高い</span></h3>



<p><code>/users/3</code> のあとに <code>/users/4</code> が見れてしまうようなアプリ、実際にあります。<br>連番だと「次のID」が簡単に予測されてしまい、<br><strong>個人情報の漏洩やなりすましの原因にもなりかねません。</strong>UUIDならこのような推測が非常に困難になります。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">理由２：分散システムでも安心</span></h3>



<p>複数のサーバー・アプリで同時にデータを保存するとき、連番ではIDがぶつかるリスクがあります。UUIDは<strong>それぞれのシステムが独立して発行しても衝突しない</strong>ので、分散構成との相性が抜群です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">理由３： 一意性が保証されている</span></h3>



<p>UUIDは世界中で唯一のIDになるように設計されています。<br>ユーザーID、ファイル名、セッションID、APIキー…「他とかぶってはいけないID」に最適です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p>UUIDを使用した実装が知りたい！という方は記事はこちらです&#x1f91e;</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/10/fastapi/" title="【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法</div><div class="blogcard-snippet internal-blogcard-snippet">初心者でも安心！FastAPIとMySQL、Dockerを使ってユーザー登録APIを構築する手順をわかりやすく解説。Next.jsとの連携方法や環境構築、登録フォームの実装まで丁寧に紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">でもUUIDにもデメリットはある</span></h2>



<ul class="wp-block-list">
<li>読みにくい：長くて人間には読みにくい文字列</li>



<li>やや遅い場合あり：連番よりもデータベースの処理が遅くなることがある</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">じゃあ結局、UUIDと連番どっちを使えばいいの？</span></h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>シーン</th><th>おすすめの主キー</th></tr></thead><tbody><tr><td>ローカルでしか使わないID</td><td>AUTO_INCREMENT でOK</td></tr><tr><td>公開URLで扱うID</td><td>UUIDの方が安全</td></tr><tr><td>データを他サービスと連携する可能性あり</td><td>UUID推奨</td></tr><tr><td>すべてが単一DBで完結している</td><td>連番でもOK（だが将来拡張に備えるならUUIDも可）</td></tr></tbody></table></figure>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/10/uuid/">UUIDとは？主キーに使われる理由と連番との違いをわかりやすく解説</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/uuid/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>辞書化とは？プログラミング初心者が必ず覚える「キーと値」の考え方</title>
		<link>https://it-bokenki.com/2025/07/10/dictionary/</link>
					<comments>https://it-bokenki.com/2025/07/10/dictionary/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Wed, 09 Jul 2025 15:31:22 +0000</pubDate>
				<category><![CDATA[IT基礎知識]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4598</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 PHPでは「連想配列」って言ってたけど、Pythonでは「辞書」？JavaScriptでは「オブジェクト」？……それって全部同 [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/dictionary/">辞書化とは？プログラミング初心者が必ず覚える「キーと値」の考え方</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>PHPでは「<strong>連想配列</strong>」って言ってたけど、Pythonでは「<strong>辞書</strong>」？<br>JavaScriptでは「<strong>オブジェクト</strong>」？……それって全部同じもの？違うの？</p>



<p>最初はその違いがわからなくて、APIから返ってきたレスポンスを読み間違えそうになりました。<br>指定の値を取り出そうとしても、「user[0]」「user.name」など書き方がバラバラで混乱。</p>



<p>「<strong>結局、辞書化ってなに？</strong>」<br>ちゃんと理解しておかないと、中身の意味を間違えて使ってしまうかも…と不安になりました。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">辞書化とは「キーと値のセット」にすること</span></h2>



<p>辞書化とは、データを<strong>「キー（名前）」と「値（データ）」のペア</strong>で管理すること。<br>これにより、意味のある形でデータを整理できます。</p>



<p>※ 下記の説明コードはPythonです。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">配列と辞書の違い</span></h2>



<p>このように配列では<strong>データの意味が不明確</strong>になりがち。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>user = &#91;"田中", 28, "エンジニア"&#93;

print(user&#91;0&#93;)  # 名前の項目が入っているが、これだけでは見てもわからない</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">user </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">田中</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">28</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エンジニア</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 名前の項目が入っているが、これだけでは見てもわからない</span></span></code></pre></div>



<p>下記のように、辞書化すると読みやすくなります。<br>キーで意味を伝えられるため、<strong>保守性・可読性が大きく向上</strong>します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>user = {
    "名前": "田中",
    "年齢": 28,
    "職業": "エンジニア"
}

print(user&#91;"名前"&#93;)  # キーが「名前」だと"田中"とかが入っているとすぐわかる</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">user </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">名前</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">田中</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">年齢</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">28</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">職業</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エンジニア</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">名前</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># キーが「名前」だと&quot;田中&quot;とかが入っているとすぐわかる</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">辞書化するメリット</span></h2>



<h3 class="wp-block-heading"><span id="toc5">① 変数名でデータの意味がすぐわかる</span></h3>



<p>配列では、インデックス番号（0番目、1番目など）でしかアクセスできないため、<strong>その値が何を表しているかが不明確</strong>です。辞書型にすることで、<strong>名前でアクセスできる</strong>ようになり、<strong>読みやすくミスが減る</strong>コードになります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># 配列だと
user = &#91;"田中", 28, "エンジニア"&#93;
print(user&#91;1&#93;)  # これは「年齢」だけど、見ただけではわからない

# 辞書化すれば
user = {"名前": "田中", "年齢": 28, "職業": "エンジニア"}
print(user&#91;"年齢"&#93;)  # 28（意味が明確）</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># 配列だと</span></span>
<span class="line"><span style="color: #D8DEE9FF">user </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">田中</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">28</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エンジニア</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;</span></span>
<span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># これは「年齢」だけど、見ただけではわからない</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88"># 辞書化すれば</span></span>
<span class="line"><span style="color: #D8DEE9FF">user </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">名前</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">田中</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">年齢</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">28</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">職業</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エンジニア</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">年齢</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># 28（意味が明確）</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">② 値の追加・変更が簡単</span></h3>



<p>キーを指定して値を直接書き換えることができるため、<strong>データの更新がシンプル</strong>です。<br>配列だと、インデックスを探して書き換える必要があり、<strong>ミスが起こりやすい</strong>です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># 年齢を29歳に更新
user&#91;"年齢"&#93; = 29</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># 年齢を29歳に更新</span></span>
<span class="line"><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">年齢</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">29</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">③ キーを使って素早くデータを探せる</span></h3>



<p>辞書型は、<strong>キーを使って直接アクセス</strong>するため、検索が高速です。<br>配列のように「どこにあるかな」と探す必要がありません。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># すぐに「職業」を取得できる
print(user&#91;"職業"&#93;)  # "エンジニア"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># すぐに「職業」を取得できる</span></span>
<span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">職業</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># &quot;エンジニア&quot;</span></span></code></pre></div>



<p>さらに、<code>.get()</code> を使えば「キーがあるかどうか」のチェックも簡単にできます：</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>print(user.get("趣味", "情報なし"))  # → "情報なし"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">user</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">趣味</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">情報なし</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88"># → &quot;情報なし&quot;</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">④ JSON形式と相性が良く、Web開発に必須</span></h3>



<p>Webアプリケーションでは、APIのリクエストやレスポンスでJSON形式（＝辞書化された構造）がよく使われます。そのため、辞書型に慣れておくとフロントエンド⇔バックエンド間のデータのやりとりがスムーズになります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>{
  &quot;name&quot;: &quot;田中&quot;,
  &quot;email&quot;: &quot;tanaka@example.com&quot;
}</code></pre></div>



<p>このレスポンスを受け取ったフロント側の処理は、たとえば JavaScript なら下記のコード簡単で指定できます。辞書化されていることで、<strong>シンプルかつ直感的に扱える</strong>のが大きなメリットです。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>console.log(data.name);  //  "田中"</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">log</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">name</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">//  &quot;田中&quot;</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">各言語の「辞書化」例</span></h2>



<figure class="wp-block-table"><table><thead><tr><th>言語</th><th>書き方</th><th>構造の名前</th></tr></thead><tbody><tr><td>Python</td><td><code>dict = {"key": "value"}</code></td><td>辞書（dictionary）</td></tr><tr><td>JavaScript</td><td><code>const obj = { key: "value" }</code></td><td>オブジェクト（object）</td></tr><tr><td>PHP</td><td><code>$arr = ["key" =&gt; "value"];</code></td><td>連想配列（associative array）</td></tr></tbody></table></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">応用：辞書の中にリスト・辞書を入れることもできる</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>user = {
    "名前": "田中",
    "スキル": &#91;"Python", "Django"&#93;,
    "連絡先": {
        "メール": "tanaka@example.com",
        "電話": "090-XXXX-XXXX"
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">user </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">名前</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">田中</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">スキル</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Python</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Django</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">&#93;,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">連絡先</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">メール</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">tanaka@example.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">電話</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">090-XXXX-XXXX</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/09/uuid/" title="404 NOT FOUND  |  てんハロ｜未経験エンジニアのIT学習ログ" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://it-bokenki.com/wp-content/uploads/cocoon-resources/blog-card-cache/2a4ac94c3ab58a282f9d9cda62d777c9.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">404 NOT FOUND  |  てんハロ｜未経験エンジニアのIT学習ログ</div><div class="blogcard-snippet external-blogcard-snippet">Hello Worldから、今日も生きてる</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com/404/" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div><p>The post <a href="https://it-bokenki.com/2025/07/10/dictionary/">辞書化とは？プログラミング初心者が必ず覚える「キーと値」の考え方</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/dictionary/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法</title>
		<link>https://it-bokenki.com/2025/07/10/fastapi/</link>
					<comments>https://it-bokenki.com/2025/07/10/fastapi/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Wed, 09 Jul 2025 15:32:30 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[バックエンド]]></category>
		<category><![CDATA[開発事例]]></category>
		<category><![CDATA[Docker]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4594</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 ・・・いや、はじめてのPython開発でそれ言う！？フォルダ構成？DB接続？何もわからん！ でも、調べまくって、なんとか Fa [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/fastapi/">【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/themes/cocoon-master/images/man.png" alt="上司" class="speech-icon-image"/></figure><div class="speech-name">上司</div></div><div class="speech-balloon">
<p>FastAPIで、フロントから送られた<br>名前・メールアドレス・パスワードをMySQLに登録しておいて</p>
</div></div>



<p>・・・いや、<strong>はじめてのPython開発でそれ言う！？</strong><br>フォルダ構成？DB接続？何もわからん！</p>



<p>でも、調べまくって、なんとか <strong>FastAPI × MySQL × Docker</strong> で爆速開発できました。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">使用した技術スタック</span></h2>



<ul class="wp-block-list">
<li><strong>FastAPI</strong>（Python製の軽量Webフレームワーク）</li>



<li><strong>MySQL</strong>（データベース）</li>



<li><strong>Docker Compose</strong>（複数のコンテナをまとめて起動）</li>



<li><strong>Next.js</strong>（フロントエンド／フォーム送信で使用）</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">プロジェクト構成</span></h2>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="940" height="640" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.18.48.png" alt="【初心者OK】FastAPI×MySQLをDockerで連携！Python開発環境を最速構築する方法" class="wp-image-4624" style="width:760px;height:auto" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.18.48.png 940w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.18.48-300x204.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.18.48-768x523.png 768w" sizes="auto, (max-width: 940px) 100vw, 940px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">FastAPI × Docker 開発環境のセットアップ</span></h2>



<h3 class="wp-block-heading"><span id="toc5">環境変数（.env.local）の設定方法</span></h3>



<p>環境変数をルート直下に <code>.env.local</code> として作成します。（開発環境で実行するため）<br>Dockerコンテナ間通信では <code>DB_HOST</code> を MySQL サービス名にします。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>DB_HOST=
DB_PORT=
DB_NAME=
DB_USER=
DB_PASSWORD=</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">DB_HOST</span><span style="color: #81A1C1">=</span></span>
<span class="line"><span style="color: #D8DEE9">DB_PORT</span><span style="color: #81A1C1">=</span></span>
<span class="line"><span style="color: #D8DEE9">DB_NAME</span><span style="color: #81A1C1">=</span></span>
<span class="line"><span style="color: #D8DEE9">DB_USER</span><span style="color: #81A1C1">=</span></span>
<span class="line"><span style="color: #D8DEE9">DB_PASSWORD</span><span style="color: #81A1C1">=</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">Docker（MySQL × FastAPI 連携）の書き方</span></h3>



<p><span class="keyboard-key">対象ファイル</span>：docker/docker-compose.yml</p>



<p>MySQLとFastAPIを同時に立ち上げるDocker Compose設定です。</p>



<p>すでにMySQLの設定がある場合は、FastAPIの定義だけ追加してください。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>version: '3'
services:
  mysql:
    image: mysql:8.0
    ... # 詳細は別記事へ

  FastAPI:
    build:
      context: ..　　// Dockerfile がある位置を指定
      dockerfile: docker/Dockerfile
    container_name: 任意のコンテナ名
    ports:
      - "8000:8000"
    volumes:
      - ../backend:/app
    env_file:
      - ../.env.local
    depends_on:　　// 「このアプリは mysql が先に起動していないとダメだよ」という意味
      - mysql</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">version</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">3</span><span style="color: #ECEFF4">&#39;</span></span>
<span class="line"><span style="color: #D8DEE9FF">services</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">  mysql</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    image</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> mysql</span><span style="color: #ECEFF4">:</span><span style="color: #B48EAD">8.0</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">...</span><span style="color: #D8DEE9FF"> # </span><span style="color: #D8DEE9">詳細は別記事へ</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  FastAPI</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    build</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      context</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">..</span><span style="color: #D8DEE9FF">　　</span><span style="color: #616E88">// Dockerfile がある位置を指定</span></span>
<span class="line"><span style="color: #D8DEE9FF">      dockerfile</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">docker</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">Dockerfile</span></span>
<span class="line"><span style="color: #D8DEE9FF">    container_name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">任意のコンテナ名</span></span>
<span class="line"><span style="color: #D8DEE9FF">    ports</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">8000:8000</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    volumes</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">..</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">backend</span><span style="color: #ECEFF4">:</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">app</span></span>
<span class="line"><span style="color: #D8DEE9FF">    env_file</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">..</span><span style="color: #81A1C1">/</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">local</span></span>
<span class="line"><span style="color: #D8DEE9FF">    depends_on</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">　　</span><span style="color: #616E88">// 「このアプリは mysql が先に起動していないとダメだよ」という意味</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mysql</span></span></code></pre></div>



<p>MySQLの設定方法は下記の記事をチェックしてください。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/03/docker-mysql/" title="DockerでMySQLをローカル構築｜Mac対応・CLI操作と文字化け対策も解説" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">DockerでMySQLをローカル構築｜Mac対応・CLI操作と文字化け対策も解説</div><div class="blogcard-snippet internal-blogcard-snippet">DockerでMacにMySQLの開発環境を一瞬で構築！Apple Silicon対応のインストール手順、docker-compose.ymlと.env連携、utf8mb4設定、ターミナル操作でのDB作成まで初心者にもわかりやすく解説しています。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">FastAPIアプリ起動設定</span></h3>



<p><span class="keyboard-key">対象ファイル</span>：docker/ Dockerfile</p>



<p>FastAPIアプリの<strong>起動手順を定義</strong>する Dockerfile を用意します。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x26a0;&#xfe0f; 注意点</span></p>



<ul class="wp-block-list">
<li>大文字スタートの <code>Dockerfile</code> というファイル名でなければいけない</li>



<li>拡張子は <strong>不要・つけてはいけない</strong>（<code>.txt</code>や<code>.py</code>などはNG）</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Pythonの軽くて早いバージョンを指定
FROM python:3.10-slim

// 実行時に.pycファイルを作らないように設定（大量にできてGitに上げれなくなる）
ENV PYTHONDONTWRITEBYTECODE=1

// コンテナ内で作業するディレクトリを作成
WORKDIR /app

// ホスト側の ./backend フォルダを、コンテナ内の /app に丸ごとコピー
COPY ./backend /app

// requirements.txt をコピーして、必要なライブラリをインストール
COPY ./backend/requirements.txt .

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

// アプリを起動
CMD &#91;"uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"&#93;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Pythonの軽くて早いバージョンを指定</span></span>
<span class="line"><span style="color: #D8DEE9">FROM</span><span style="color: #D8DEE9FF"> python</span><span style="color: #ECEFF4">:</span><span style="color: #B48EAD">3.10</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">slim</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// 実行時に.pycファイルを作らないように設定（大量にできてGitに上げれなくなる）</span></span>
<span class="line"><span style="color: #D8DEE9">ENV</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PYTHONDONTWRITEBYTECODE</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// コンテナ内で作業するディレクトリを作成</span></span>
<span class="line"><span style="color: #D8DEE9">WORKDIR</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">app</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// ホスト側の ./backend フォルダを、コンテナ内の /app に丸ごとコピー</span></span>
<span class="line"><span style="color: #D8DEE9">COPY</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">.</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">backend</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">app</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// requirements.txt をコピーして、必要なライブラリをインストール</span></span>
<span class="line"><span style="color: #D8DEE9">COPY</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">.</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">backend</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">requirements</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">txt</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">.</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">RUN</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pip</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">install</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">upgrade</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pip</span></span>
<span class="line"><span style="color: #D8DEE9">RUN</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pip</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">install</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">r</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">requirements</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">txt</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// アプリを起動</span></span>
<span class="line"><span style="color: #D8DEE9">CMD</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">uvicorn</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">main:app</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">--host</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">0.0.0.0</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">--port</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">8000</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">--reload</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">requirements.txt の作成とバージョン管理</span></h3>



<p><span class="keyboard-key">対象ファイル</span>：backend/requirements.txt</p>



<p>Pythonパッケージの<strong>インストール一覧</strong>を記述します。</p>



<p>下記のコマンドで、Dockerで一括で自動インストールすることができます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>pip install -r requirements.txt </code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f331; 豆知識</span></p>



<p><strong>パッケージ名しか書いていない場合</strong>：常に最新バージョンがインストールされる（試作段階・練習中向け）</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>fastapi
uvicorn
SQLAlchemy
PyMySQL
python-dotenv</code></pre></div>



<p><strong>バージョンを指定している場合</strong>：誰が使っても同じ環境になる（チーム開発・本番運用向け）</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>fastapi==0.116.0
uvicorn==0.35.0
SQLAlchemy==2.0.41
PyMySQL==1.1.1
python-dotenv==1.1.1</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">.gitignore の設定でGitをクリーンに保つ</span></h2>



<p><span class="keyboard-key">対象ファイル</span>：.gitignore</p>



<p>Pythonのをインストールすると自動生成ファイルができて、Gitにそのまま上げると大変なことになります。<br>下記のように設定すると、Gitに不要なファイルが混ざらなくなります。おすすめです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># バーチャル環境除外
venv/

# Pythonのバイトコードキャッシュを無視
__pycache__/
*.pyc
*.pyo
*.pyd</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">テーブル作成</span></h2>



<p>事前に <code>users</code> テーブルを作っておきましょう。DockerのMySQL内で作成できます。</p>



<p>作成方法については、下記の記事をご覧ください。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/03/drizzle/" title="Drizzleとは？TypeScriptで型安全にSQL・マイグレーションを管理する方法" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/1-1-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/1-1-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/1-1-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/1-1-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/1-1-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Drizzleとは？TypeScriptで型安全にSQL・マイグレーションを管理する方法</div><div class="blogcard-snippet internal-blogcard-snippet">Drizzle ORMを使って、TypeScriptで型安全にSQLやマイグレーションを管理する方法をわかりやすく解説。初期設定からスキーマ定義、リレーション設定まで丁寧に紹介！</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/03/docker-mysql/" title="DockerでMySQLをローカル構築｜Mac対応・CLI操作と文字化け対策も解説" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">DockerでMySQLをローカル構築｜Mac対応・CLI操作と文字化け対策も解説</div><div class="blogcard-snippet internal-blogcard-snippet">DockerでMacにMySQLの開発環境を一瞬で構築！Apple Silicon対応のインストール手順、docker-compose.ymlと.env連携、utf8mb4設定、ターミナル操作でのDB作成まで初心者にもわかりやすく解説しています。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">Next.jsで登録フォームを作成</span></h2>



<p>下記は登録フォームの <code>registerForm.tsx</code> の内容の内容です。<br><code>register/page.tsx</code> で呼び出すと、下記の画像のような登録フォームになります。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>"use client";

import { useState } from "react";

export default function RegisterForm() {
  const &#91;form, setForm&#93; = useState({
    name: "",
    email: "",
    password: "",
  });

  const &#91;message, setMessage&#93; = useState("");

  const handleChange = (e: React.ChangeEvent&lt;HTMLInputElement>) => {
    setForm({ ...form, &#91;e.target.name&#93;: e.target.value });
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      const res = await fetch("http://localhost:8000/registration", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(form),
      });

      const data = await res.json();
      if (res.ok) {
        setMessage("登録成功！ ユーザーID: " + data.user_id);
      } else {
        setMessage("登録失敗: " + (data.detail || "エラーが発生しました"));
      }
    } catch (error) {
      console.error("エラー:", error);
      setMessage("通信エラーが発生しました");
    }
  };

  return (
    &lt;form onSubmit={handleSubmit} className="space-y-4 max-w-md mx-auto mt-10">
      &lt;div>
        &lt;label htmlFor="name" className="block font-medium mb-1">
          お名前
        &lt;/label>
        &lt;input
          id="name"
          name="name"
          placeholder="例：山田 太郎"
          value={form.name}
          onChange={handleChange}
          required
          className="border px-3 py-2 w-full"
        />
      &lt;/div>

      &lt;div>
        &lt;label htmlFor="email" className="block font-medium mb-1">
          メールアドレス
        &lt;/label>
        &lt;input
          id="email"
          name="email"
          placeholder="例：taro@example.com"
          type="email"
          value={form.email}
          onChange={handleChange}
          required
          className="border px-3 py-2 w-full"
        />
      &lt;/div>

      &lt;div>
        &lt;label htmlFor="password" className="block font-medium mb-1">
          パスワード
        &lt;/label>
        &lt;input
          id="password"
          name="password"
          placeholder="半角英数字8文字以上"
          type="password"
          value={form.password}
          onChange={handleChange}
          required
          className="border px-3 py-2 w-full"
        />
      &lt;/div>

      &lt;button
        type="submit"
        className="bg-blue-600 text-white px-4 py-2 rounded w-full"
      >
        ユーザー登録
      &lt;/button>

      {message &amp;&amp; &lt;p className="mt-4 text-sm text-gray-700">{message}&lt;/p>}
    &lt;/form>
  );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useState</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">RegisterForm</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9">form</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setForm</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">email</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">password</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9">message</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setMessage</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">handleChange</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> React</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">ChangeEvent</span><span style="color: #ECEFF4">&lt;</span><span style="color: #D8DEE9FF">HTMLInputElement</span><span style="color: #ECEFF4">&gt;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">setForm</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">...</span><span style="color: #D8DEE9">form</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">&#91;</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">target</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">name</span><span style="color: #88C0D0">&#93;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">target</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">value</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">handleSubmit</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> React</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">FormEvent</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">preventDefault</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">try</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">http://localhost:8000/registration</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">method</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">POST</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">headers</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Content-Type</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">application/json</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">body</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">JSON</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">stringify</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">form</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ok</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">setMessage</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">登録成功！ ユーザーID: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">user_id</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">setMessage</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">登録失敗: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">detail</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エラーが発生しました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">catch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">error</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">エラー:</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">error</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">setMessage</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">通信エラーが発生しました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;form</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">onSubmit</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleSubmit</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">space-y-4 max-w-md mx-auto mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">htmlFor</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">name</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block font-medium mb-1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          お名前</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;input</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">name</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">name</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">name</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">placeholder</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">例：山田 太郎</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">value</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">form</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">name</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">onChange</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleChange</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">required</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">border px-3 py-2 w-full</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">htmlFor</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">email</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block font-medium mb-1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          メールアドレス</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;input</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">email</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">name</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">email</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">placeholder</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">例：taro@example.com</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">email</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">value</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">form</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">email</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">onChange</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleChange</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">required</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">border px-3 py-2 w-full</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">htmlFor</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">block font-medium mb-1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          パスワード</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/label&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;input</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">id</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">name</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">placeholder</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">半角英数字8文字以上</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">value</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">form</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">password</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">onChange</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleChange</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">required</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">border px-3 py-2 w-full</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;button</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">submit</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-blue-600 text-white px-4 py-2 rounded w-full</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        ユーザー登録</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/button&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">{</span><span style="color: #D8DEE9">message</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;p</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">mt-4 text-sm text-gray-700</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;{</span><span style="color: #D8DEE9">message</span><span style="color: #81A1C1">}&lt;/p&gt;}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/form&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="575" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-1024x575.png" alt="【初心者OK】FastAPI×MySQLをDockerで連携！Python開発環境を最速構築する方法" class="wp-image-4625" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-1024x575.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-300x168.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-768x431.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-376x212.png 376w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03-1320x741.png 1320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-09-18.29.03.png 1340w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc12">FastAPIのバックエンド側の実装</span></h2>



<h3 class="wp-block-heading"><span id="toc13">各ファイルの役割</span></h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>ファイル</th><th>内容</th></tr></thead><tbody><tr><td><code>backend/db.py</code></td><td>DB接続の設定を記述</td></tr><tr><td><code>backend/main.py</code></td><td>FastAPIの本体とCORS、ルーティング設定</td></tr><tr><td><code>backend/models/user.py</code></td><td>usersテーブル定義（UUID、カラムなど）</td></tr><tr><td><code>backend/schemas/user.py</code></td><td>Pydanticで受け取りバリデーション</td></tr><tr><td><code>backend/utils/common_fields.py</code></td><td>登録時の共通フィールドを自動付与</td></tr><tr><td><code>backend/routers/registration.py</code></td><td>POSTでデータ受取→DB保存処理</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc14">db.py：DB接続設定</span></h3>



<p><code>.env.local </code>を読み込んで DB に接続する準備をする</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from sqlalchemy import create_engine // DBとの接続エンジンを作るための関数
from sqlalchemy.orm import sessionmaker, declarative_base
from dotenv import load_dotenv  // .envファイルから環境変数を読み込むための関数
import os // 環境変数を取得するための標準ライブラリ

// ルートの.env読み込み
load_dotenv(dotenv_path=".env.local")

DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT")
DB_NAME = os.getenv("DB_NAME")
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")

// データベース接続用のURLを作成
DB_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8mb4"

// 接続準備
engine = create_engine(DB_URL)
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
Base = declarative_base()</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sqlalchemy</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">create_engine</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// DBとの接続エンジンを作るための関数</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sqlalchemy</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">orm</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sessionmaker</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">declarative_base</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">dotenv</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">load_dotenv</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// .envファイルから環境変数を読み込むための関数</span></span>
<span class="line"><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">os</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// 環境変数を取得するための標準ライブラリ</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// ルートの.env読み込み</span></span>
<span class="line"><span style="color: #8FBCBB">load_dotenv</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">dotenv_path</span><span style="color: #D8DEE9FF">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">.env.local</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">DB_HOST</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">os</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">getenv</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">DB_HOST</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">DB_PORT</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">os</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">getenv</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">DB_PORT</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">DB_NAME</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">os</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">getenv</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">DB_NAME</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">DB_USER</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">os</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">getenv</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">DB_USER</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">DB_PASSWORD</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">os</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">getenv</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">DB_PASSWORD</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// データベース接続用のURLを作成</span></span>
<span class="line"><span style="color: #8FBCBB">DB_URL</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">f</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8mb4</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// 接続準備</span></span>
<span class="line"><span style="color: #8FBCBB">engine</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">create_engine</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">DB_URL</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">SessionLocal</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">sessionmaker</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">bind</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">engine</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">autocommit</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">False</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">autoflush</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">False</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">Base</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">declarative_base</span><span style="color: #D8DEE9FF">()</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc15">main.py：アプリ起動とCORS設定</span></h3>



<p>FastAPIアプリを起動し、CORS設定とルーター登録を行います。</p>



<p>Next.js開発環境で実行しているので、今回は<code>http://localhost:3000</code>を指定（ここは環境変数設定にしたほうがいいかもです）</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware 　// 別ドメインからのアクセスを許可するための設定
from routers import registration

// FastAPIアプリケーションの本体を作成
app = FastAPI()

// CORS（クロスオリジン）設定を追加：別のドメインからアクセスを許可する
app.add_middleware(
    CORSMiddleware,
    allow_origins=&#91;"http://localhost:3000"&#93;,  // フロントエンド（Next.js）からのアクセスを許可
    allow_credentials=True,  // クッキーなどの認証情報を含めた通信を許可
    allow_methods=&#91;"*"&#93;,  // GETやPOSTなど、すべてのHTTPメソッドを許可
    allow_headers=&#91;"*"&#93;,  // すべてのリクエストヘッダーを許可（認証トークンなど）
)

// APIの処理を追加（今回はregistration.pyのルーター）
app.include_router(registration.router)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fastapi</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">FastAPI</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">fastapi</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">middleware</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">cors</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">CORSMiddleware</span><span style="color: #D8DEE9FF"> 　</span><span style="color: #616E88">// 別ドメインからのアクセスを許可するための設定</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">routers</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">registration</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// FastAPIアプリケーションの本体を作成</span></span>
<span class="line"><span style="color: #8FBCBB">app</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">FastAPI</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// CORS（クロスオリジン）設定を追加：別のドメインからアクセスを許可する</span></span>
<span class="line"><span style="color: #8FBCBB">app</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">add_middleware</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">CORSMiddleware</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">allow_origins</span><span style="color: #D8DEE9FF">=&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">http://localhost:3000</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// フロントエンド（Next.js）からのアクセスを許可</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">allow_credentials</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">True</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// クッキーなどの認証情報を含めた通信を許可</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">allow_methods</span><span style="color: #D8DEE9FF">=&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">*</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// GETやPOSTなど、すべてのHTTPメソッドを許可</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">allow_headers</span><span style="color: #D8DEE9FF">=&#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">*</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// すべてのリクエストヘッダーを許可（認証トークンなど）</span></span>
<span class="line"><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// APIの処理を追加（今回はregistration.pyのルーター）</span></span>
<span class="line"><span style="color: #8FBCBB">app</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">include_router</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">registration</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">router</span><span style="color: #D8DEE9FF">)</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc16">models/user.py：ユーザーテーブル定義</span></h3>



<p>SQLAlchemyで <code>userテーブル</code> 構造を定義します。主キーは <code>UUID</code> を自動生成。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import uuid
from sqlalchemy import Column, String, Boolean, DateTime
from db import Base

class Users(Base):
    __tablename__ = "users"

    user_id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    name = Column(String(100), nullable=False)
    email = Column(String(100), nullable=False, unique=True)
    password = Column(String(255), nullable=False)
    updated_by = Column(String(100))
    updated_at = Column(DateTime)
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">uuid</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sqlalchemy</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Column</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">String</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Boolean</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">DateTime</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Base</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Users</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">Base</span><span style="color: #D8DEE9FF">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">__tablename__</span><span style="color: #D8DEE9FF"> = </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">users</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">user_id</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Column</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF">(36)</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">primary_key</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">True</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">lambda</span><span style="color: #D8DEE9FF">: </span><span style="color: #8FBCBB">str</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">uuid</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">uuid4</span><span style="color: #D8DEE9FF">()))</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">name</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Column</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF">(100)</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">nullable</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">False</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">email</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Column</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF">(100)</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">nullable</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">False</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">unique</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">True</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">password</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Column</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF">(255)</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">nullable</span><span style="color: #D8DEE9FF">=</span><span style="color: #8FBCBB">False</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">updated_by</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Column</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">String</span><span style="color: #D8DEE9FF">(100))</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">updated_at</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Column</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">DateTime</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span></code></pre></div>



<p>uuidについて、もっと知りたい方は下記の記事をどうぞ！</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/10/uuid/" title="UUIDとは？主キーに使われる理由と連番との違いをわかりやすく解説" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-1-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-1-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-1-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-1-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-1-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">UUIDとは？主キーに使われる理由と連番との違いをわかりやすく解説</div><div class="blogcard-snippet internal-blogcard-snippet">UUIDはなぜ主キーに使われるのか？連番との違いやメリット・デメリット、UUIDの種類（v1〜v5）まで初心者向けにやさしく解説。PythonでのUUIDの生成方法も紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc17">schemas/user.py：バリデーション用スキーマ定義</span></h3>



<p>フロントから送られてくる入力値（name, email, password）をバリデーションします。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from pydantic import BaseModel

class UserCreate(BaseModel):
    name: str
    email: str
    password: str</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pydantic</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">BaseModel</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">UserCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">BaseModel</span><span style="color: #D8DEE9FF">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">name</span><span style="color: #D8DEE9FF">: </span><span style="color: #8FBCBB">str</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">email</span><span style="color: #D8DEE9FF">: </span><span style="color: #8FBCBB">str</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">password</span><span style="color: #D8DEE9FF">: </span><span style="color: #8FBCBB">str</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc18">utils/common_fields.py：共通項目の自動付与</span></h3>



<p><code>updated_by</code> や <code>updated_at</code> などの共通項目を自動で付与します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from datetime import datetime, timezone, timedelta

def generate_common_fields():
    jst_now = datetime.now(timezone(timedelta(hours=9)))
    return {
        "updated_by": "system",
        "updated_at": jst_now,
    }
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">datetime</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">datetime</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">timezone</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">timedelta</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">generate_common_fields</span><span style="color: #D8DEE9FF">():</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">jst_now</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">datetime</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">now</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">timezone</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">timedelta</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">hours</span><span style="color: #D8DEE9FF">=9)))</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        &quot;</span><span style="color: #8FBCBB">updated_by</span><span style="color: #D8DEE9FF">&quot;: &quot;</span><span style="color: #8FBCBB">system</span><span style="color: #D8DEE9FF">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        &quot;</span><span style="color: #8FBCBB">updated_at</span><span style="color: #D8DEE9FF">&quot;: </span><span style="color: #8FBCBB">jst_now</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc19">routers/registration.py：登録処理ルーターの作成</span></h3>



<p>POSTされた情報をDBに保存するルーターです。辞書展開でスキーマ＋共通フィールドを結合します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session　　// DBとのやりとりの型（Session）を指定
from db import SessionLocal
from models.user import Users
from schemas.user import UserCreate
from utils.common_fields import generate_common_fields

router = APIRouter()

// データベースとの接続を一時的に確立して、使い終わったら自動で切るための仕組み
def get_db():
    db = SessionLocal()  // DB接続を開始
    try:
        yield db　　 // データを登録・検索
    finally:
        db.close()　// DB接続を終了
        
@router.post("/registration")
def create_user(user: UserCreate, db: Session = Depends(get_db)):
    common_fields = generate_common_fields()

    db_user = Users(
        **user.dict(),
        **common_fields
    )

    db.add(db_user)
    db.commit()

    return {"message": "登録成功"}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fastapi</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">APIRouter</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Depends</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sqlalchemy</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">orm</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Session</span><span style="color: #D8DEE9FF">　　</span><span style="color: #616E88">// DBとのやりとりの型（Session）を指定</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">SessionLocal</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">models</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Users</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">schemas</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">user</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">UserCreate</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">utils</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">common_fields</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">generate_common_fields</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">router</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">APIRouter</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// データベースとの接続を一時的に確立して、使い終わったら自動で切るための仕組み</span></span>
<span class="line"><span style="color: #8FBCBB">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">get_db</span><span style="color: #D8DEE9FF">():</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">SessionLocal</span><span style="color: #D8DEE9FF">()  </span><span style="color: #616E88">// DB接続を開始</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">try</span><span style="color: #D8DEE9FF">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">yield</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF">　　 </span><span style="color: #616E88">// データを登録・検索</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">finally</span><span style="color: #D8DEE9FF">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">close</span><span style="color: #D8DEE9FF">()　</span><span style="color: #616E88">// DB接続を終了</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">@</span><span style="color: #8FBCBB">router</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">post</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/registration</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">create_user</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">user</span><span style="color: #D8DEE9FF">: </span><span style="color: #8FBCBB">UserCreate</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF">: </span><span style="color: #8FBCBB">Session</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Depends</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">get_db</span><span style="color: #D8DEE9FF">)):</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">common_fields</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">generate_common_fields</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">db_user</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">Users</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">**</span><span style="color: #8FBCBB">user</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">dict</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">**</span><span style="color: #8FBCBB">common_fields</span></span>
<span class="line"><span style="color: #D8DEE9FF">    )</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">add</span><span style="color: #D8DEE9FF">(</span><span style="color: #8FBCBB">db_user</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">db</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">commit</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF">&quot;</span><span style="color: #8FBCBB">message</span><span style="color: #D8DEE9FF">&quot;: &quot;</span><span style="color: #8FBCBB">登録成功</span><span style="color: #D8DEE9FF">&quot;</span><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>※ここで辞書化の記事をつくっていれよう！</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc20">トラブル対応：ログでFastAPIのエラーを確認する方法</span></h2>



<p>ログをリアルタイムで監視するには、以下のコマンドを使いましょう。</p>



<p><code>-f</code> は <code>--follow</code> の略で「ログを継続して追いかける」オプションです。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>docker logs -f コンテナ名</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">docker</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">logs</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">f</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">コンテナ名</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/10/fastapi/">【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/fastapi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>初心者向け：FastAPIの環境構築ガイド【5分でAPIが動く】</title>
		<link>https://it-bokenki.com/2025/07/10/fastapi-setup/</link>
					<comments>https://it-bokenki.com/2025/07/10/fastapi-setup/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 10 Jul 2025 11:48:30 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[バックエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4580</guid>

					<description><![CDATA[<p>未経験でも気軽に！サブスク型プログラミングスクール【Freeks】 困ってた自分に届けたい話 ・・・いや、FastAPIって何？PythonでWebサーバー作ったことないけど！？何から始めればいいの…？ でも、調べてみた [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/fastapi-setup/">初心者向け：FastAPIの環境構築ガイド【5分でAPIが動く】</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BXQOH">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www20.a8.net/svt/bgt?aid=250611125612&#038;wid=001&#038;eno=01&#038;mid=s00000025904002005000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+A4DB02+5JVK+BXQOH" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+A4DB02+5JVK+BX3J6">未経験でも気軽に！サブスク型プログラミングスクール【Freeks】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/themes/cocoon-master/images/man.png" alt="上司" class="speech-icon-image"/></figure><div class="speech-name">上司</div></div><div class="speech-balloon">
<p>FastAPIでAPIサーバー立てて。仮想環境つくって、動かして。</p>
</div></div>



<p>・・・いや、<strong>FastAPIって何？PythonでWebサーバー作ったことないけど！？</strong><br>何から始めればいいの…？</p>



<p>でも、調べてみたら、意外とコマンドだけでサクサク環境構築できる。<br><strong>「さすが爆速APIフレームワーク」って言われるだけある！</strong></p>



<p>環境構築に不安がある方でも、<strong>手順どおりに進めれば5分でAPIが動く</strong>はず。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">FastAPIとは？</span></h2>



<p><strong>ひとことで言うと、「爆速でAPIが作れるPython製フレームワーク」です。</strong></p>



<p><span class="keyboard-key">&#x1f9e9; 特徴</span></p>



<ul class="wp-block-list">
<li><strong>少ないコードで、読みやすく整理されたAPIが作れる</strong></li>



<li><strong>自動でAPIの説明書（ドキュメント）を作成してくれる</strong></li>



<li><strong>入力ミスを事前にチェックできる仕組みがある</strong></li>



<li><strong>処理速度が速く、ストレスが少ない</strong></li>



<li><strong>書き方が直感的で覚えやすい</strong></li>



<li><strong>機能を後から追加しやすく、拡張性が高い</strong></li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">前提：Pythonがインストールされていること</span></h2>



<p>まず、ターミナルで以下のコマンドを実行し、Pythonが使える状態か確認しましょう。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>python3 --version

# 実行結果
Python 3.9.6</code></pre></div>



<p>バージョンが 3.x 系であればOKです。<br>もし <code>command not found</code> と出る場合は、MacにPythonをインストールする手順を先に確認してください。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">FastAPI 環境構築手順</span></h2>



<h3 class="wp-block-heading"><span id="toc5">STEP 1：VSCodeで拡張機能をインストール</span></h3>



<p>以下の2つの拡張機能をインストールしておくと、開発がスムーズになります。</p>



<ul class="wp-block-list">
<li><strong>Python</strong>：Microsoft公式のPython拡張機能</li>



<li><strong>Pylance</strong>：コード補完とエラーチェックを強化する拡張機能</li>
</ul>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">STEP 2：プロジェクトフォルダを作成</span></h3>



<p>例として、<code>backend/</code> フォルダ内で作業を進めます。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>mkdir backend
cd backend</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">STEP 3：仮想環境を作成＆有効化（Macの場合）</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># 仮想環境作成
python3 -m venv venv

# 仮想環境の有効化
source venv/bin/activate</code></pre></div>



<p>プロンプトが <code>(venv)</code> と表示されれば、仮想環境が有効になっています。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc8">STEP 4：FastAPIと実行サーバーをインストール</span></h3>



<p>FastAPIを実際に動かすには、まず2つのパッケージをインストールするだけでOKです。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>pip install fastapi uvicorn</code></pre></div>



<p>このコマンドを実行するだけで、FastAPIを動かすのに必要な最低限の環境が整います。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f449; インストールされる主なパッケージ</span></p>



<p>① <code>fastapi</code>：PythonでAPIを簡単に作るためのツール</p>



<ol class="wp-block-list">
<li>「こういうURLにアクセスされたら、こう返すよ！」っていうルールを書く</li>



<li>入力ミスがあったら、自動で「それ間違ってるよ」って教えてくれる</li>



<li>作ったAPIの説明書を自動でつくってくれる</li>
</ol>



<p>② <code>uvicorn</code>：FastAPIを動かすサーバー</p>



<ol class="wp-block-list">
<li>作ったAPIを動かすための土台（サーバー）になる</li>



<li>サーバーを起動すると、<strong>ブラウザで <code>http://localhost:8000</code> を開くだけで結果を見られる</strong></li>



<li><code>http://localhost:8000/docs</code> にアクセスすれば、<strong>ボタン付きのテスト画面でAPIを試せる</strong></li>
</ol>



<div style="height:5px" aria-hidden="true" class="wp-block-spacer"></div>



<p>FastAPIを実行するにはこの2つだけで<strong>一通りの動作確認が可能</strong>です。<br>データベース連携やセキュリティ対策などをする場合は、追加でパッケージを入れていきます<br>（例：<code>sqlalchemy</code>, <code>pydantic[email]</code>, <code>python-jose</code> など）。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc9">STEP 5：main.py を作成してAPI定義</span></h3>



<p>このコードは「ルートURLにアクセスしたらJSONでメッセージを返すだけ」の最小APIです。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello FastAPI!"}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fastapi</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">FastAPI</span></span>
<span class="line"></span>
<span class="line"><span style="color: #8FBCBB">app</span><span style="color: #D8DEE9FF"> = </span><span style="color: #8FBCBB">FastAPI</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">@</span><span style="color: #8FBCBB">app</span><span style="color: #D8DEE9FF">.</span><span style="color: #8FBCBB">get</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #8FBCBB">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">read_root</span><span style="color: #D8DEE9FF">():</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF">&quot;</span><span style="color: #8FBCBB">message</span><span style="color: #D8DEE9FF">&quot;: &quot;</span><span style="color: #8FBCBB">Hello</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">FastAPI</span><span style="color: #D8DEE9FF">!&quot;</span><span style="color: #ECEFF4">}</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc10">STEP 6：APIを起動</span></h3>



<p>以下のコマンドで開発サーバーを起動します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>uvicorn main:app --reload</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc11">STEP 7：動作確認リンク</span></h3>



<p>以下のURLにアクセスして、FastAPIが動いているか確認しましょう。</p>



<figure class="wp-block-table"><table><thead><tr><th>URL</th><th>内容</th></tr></thead><tbody><tr><td><a href="http://localhost:8000" title="">http://localhost:8000</a></td><td><code>{"message": "Hello FastAPI!"}</code> が表示される</td></tr><tr><td><a class="" href="http://localhost:8000/docs">http://localhost:8000/docs</a></td><td><strong>ボタンでAPIを試せる画面</strong><br>開発中に「このAPIちゃんと動くかな？」って確認するときに使う</td></tr><tr><td><a class="" href="http://localhost:8000/redoc">http://localhost:8000/redoc</a></td><td><strong>読む専用のAPI説明ページ</strong><br>「どんなAPIがあるか知りたいな〜」って一覧で見たいときに使う</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">実際の画面</span></p>



<p>&#x25b6; <a href="http://localhost:8000" title="">http://localhost:8000</a> の表示画面</p>



<figure class="wp-block-image aligncenter size-full has-custom-border"><img loading="lazy" decoding="async" width="700" height="186" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-08-15.09.17.png" alt="初心者向け：FastAPIの環境構築ガイド【5分でAPIが動く】" class="wp-image-4581" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-08-15.09.17.png 700w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-08-15.09.17-300x80.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /></figure>



<p>&#x25b6; <a href="http://localhost:8000" title="">http://localhost:8000</a><a class="" href="http://localhost:8000/docs">/docs</a> の表示画面</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="223" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-1024x223.png" alt="初心者向け：FastAPIの環境構築ガイド【5分でAPIが動く】" class="wp-image-4823" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-1024x223.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-300x65.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-768x167.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-1536x334.png 1536w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-2048x445.png 2048w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.56.56-1320x287.png 1320w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>&#x25b6; <a href="http://localhost:8000/redoc" title="">http://localhost:8000/redoc</a></p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="270" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.57.29-1024x270.png" alt="初心者向け：FastAPIの環境構築ガイド【5分でAPIが動く】" class="wp-image-4824" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.57.29-1024x270.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.57.29-300x79.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.57.29-768x202.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.57.29-1320x348.png 1320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-10-18.57.29.png 1450w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>ここまでできれば、FastAPIのローカル開発環境は完成です。<br>あとはルーティングを増やしたり、DBとつないだり、自由にAPI開発を進めていけます。<br><br>&#x1f527; 開発に活用する具体的な実装例はこちらで紹介しています</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/10/fastapi/" title="【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-6-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【初心者OK】FastAPI×MySQLをDockerで連携！Pythonで爆速開発する方法</div><div class="blogcard-snippet internal-blogcard-snippet">初心者でも安心！FastAPIとMySQL、Dockerを使ってユーザー登録APIを構築する手順をわかりやすく解説。Next.jsとの連携方法や環境構築、登録フォームの実装まで丁寧に紹介します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
<p></p>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div>



<p></p><p>The post <a href="https://it-bokenki.com/2025/07/10/fastapi-setup/">初心者向け：FastAPIの環境構築ガイド【5分でAPIが動く】</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/fastapi-setup/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】</title>
		<link>https://it-bokenki.com/2025/07/08/docker-mailpit/</link>
					<comments>https://it-bokenki.com/2025/07/08/docker-mailpit/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Tue, 08 Jul 2025 14:31:46 +0000</pubDate>
				<category><![CDATA[開発ツール（Dev Tools）]]></category>
		<category><![CDATA[Docker]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4533</guid>

					<description><![CDATA[<p>IT/Webエンジニア専門の転職エージェント【ユニゾンキャリア】 困ってた自分に届けたい話 これまでずっと、メール送信のテストは自分のアドレスに送って確認していました。それでもなんとかなってはいたのですが、複数のメールア [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/08/docker-mailpit/">【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>どもども<br>今回は「<strong>Mailpit</strong>」について解説します。</p>
</div></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-r sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/5-1-150x150.png" alt="バグヲ" class="speech-icon-image"/></figure><div class="speech-name">バグヲ</div></div><div class="speech-balloon">
<p>Dockerのイメージのひとつだっけ？</p>
</div></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>こんなあなたにピッタリな記事&#x1f447;</p>



<div style="height:15px" aria-hidden="true" class="wp-block-spacer"></div>



<ul class="wp-block-list">
<li>開発環境でメール送信処理をテストしたい</li>



<li>GmailやSendGridの実アカウントは使いたくない</li>



<li>MailpitをDockerで簡単に立ち上げたい</li>
</ul>



<p>がまぁまぁわかります！</p>
</div></div>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457GS5+AF33W2+5F00+HVNAP">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www25.a8.net/svt/bgt?aid=250611125630&#038;wid=001&#038;eno=01&#038;mid=s00000025272003003000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www12.a8.net/0.gif?a8mat=457GS5+AF33W2+5F00+HVNAP" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457GS5+AF33W2+5F00+HV7V6">IT/Webエンジニア専門の転職エージェント【ユニゾンキャリア】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>これまでずっと、メール送信のテストは自分のアドレスに送って確認していました。<br>それでもなんとかなってはいたのですが、<strong>複数のメールアドレスで挙動を確認したいときなど、とにかく手間がかかる…</strong>。</p>



<p>「みんなどうやってるんだろう？」と疑問に思っていたときに、たまたま見つけたのが<strong>Mailpit</strong>というツールでした。</p>



<p>最初は「送信したメールをWeb画面で見るってどういうこと？」と、正直よくわかりませんでした。<br>ですが、実際に使ってみると「こんな便利なものがあったのか！」と衝撃を受けました。</p>



<p>それ以来、<strong>開発中のメール送信テストはMailpit一択</strong>です。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc2">Mailpitとは？</span></h2>



<p><strong>Mailpit</strong> は、開発環境向けの「ローカルメール受信サーバー」です。<br>実際のメールサーバー（Gmailなど）を使わず、<strong>開発中のフォーム送信や通知メールがきちんと送られているかを、ブラウザ上で確認できます。</strong></p>



<p><span class="keyboard-key">メリット</span></p>



<ul class="wp-block-list">
<li>&#x2705; ローカルでメール受信ができる</li>



<li>&#x2705; ブラウザでメールの中身をすぐ確認できる（Web GUI）</li>



<li>&#x2705; SendGridや本物のメールアドレスは不要</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">DockerでMailpitを起動する手順</span></h2>



<h3 class="wp-block-heading"><span id="toc4">STEP１：docker-compose.yml の記載</span></h3>



<p>まずは、以下のように <code>docker-compose.yml</code> を記述します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly> mailpit:
    image: axllent/mailpit:latest
    container_name: 任意のコンテナ名
    ports:
      - "1025:1025" # SMTP受信用
      - "8025:8025" # 管理画面（GUI）</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF"> mailpit</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    image</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">axllent</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF">mailpit</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9">latest</span></span>
<span class="line"><span style="color: #D8DEE9FF">    container_name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">任意のコンテナ名</span></span>
<span class="line"><span style="color: #D8DEE9FF">    ports</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">1025:1025</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> # </span><span style="color: #D8DEE9">SMTP受信用</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">8025:8025</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> # </span><span style="color: #D8DEE9">管理画面</span><span style="color: #D8DEE9FF">（</span><span style="color: #D8DEE9">GUI</span><span style="color: #D8DEE9FF">）</span></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc5">STEP２：コンテナを起動</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>docker compose up -d</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">STEP３：正常にコンテナができたか確認</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>docker compose ps</code></pre></div>



<p>ブラウザで <code>http://localhost:8025</code> にアクセスすると、下記のMailpitの管理画面が表示されます。</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="506" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-1024x506.png" alt="" class="wp-image-4534" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-1024x506.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-300x148.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-768x379.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-1536x759.png 1536w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-2048x1012.png 2048w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.08.13-1320x652.png 1320w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc7">nodemailer + Mailpit の実装（Next.js）</span></h2>



<h3 class="wp-block-heading"><span id="toc8">STEP１：パッケージをインストール</span></h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># メール送信用のライブラリ
npm install nodemailer
npm install nodemailer-sendgrid
npm install @sendgrid/mail

# 入力バリデーションライブラリ
npm install zod

# nodemailer 用の TypeScript 型定義ファイル
npm install --save-dev @types/nodemailer</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc9">STEP２：APIエンドポイントを作成（/api/mail/route.ts）</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import { NextResponse } from "next/server";
import { getTransporter } from "@/lib/mailer";

export async function POST(req: Request) {
  const { email } = await req.json();
  const transporter = getTransporter();

  try {
    await transporter.sendMail({
      from: process.env.MAIL_FROM,
      to: email,
      subject: "自動返信テスト",
      text: "こちらは自動返信メールです。",
    });

    return NextResponse.json({ success: true });
  } catch (err) {
    console.error("メール送信エラー:", err);
    return NextResponse.json({ success: false }, { status: 500 });
  }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextResponse</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next/server</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">getTransporter</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/lib/mailer</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">POST</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">req</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> Request</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">email</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">req</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">transporter</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">getTransporter</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">try</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">transporter</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">sendMail</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">from</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">MAIL_FROM</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">to</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">email</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">subject</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">自動返信テスト</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">text</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">こちらは自動返信メールです。</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NextResponse</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">success</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">catch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">メール送信エラー:</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NextResponse</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">json</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">success</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">status</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">500</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc10">STEP３：メール送信フォームを作る（components/mailer/form.tsx）</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>"use client";

import { useState } from "react";
import { z } from "zod";

const schema = z.object({
  email: z.string().email("正しいメールアドレスを入力してください"),
});

export default function MailForm() {
  const &#91;email, setEmail&#93; = useState("");
  const &#91;error, setError&#93; = useState("");
  const &#91;sent, setSent&#93; = useState(false);

  const handleSubmit = async () => {
    const result = schema.safeParse({ email });
    if (!result.success) {
      setError(result.error.errors&#91;0&#93;.message);
      return;
    }

    try {
      const res = await fetch("/api/mail", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email }),
      });
      if (res.ok) {
        setSent(true);
        setError("");
      } else {
        setError("送信に失敗しました");
      }
    } catch (err) {
      console.error(err);
      setError("通信エラーが発生しました");
    }
  };

  return (
    &lt;div className="p-4 border rounded bg-gray-50 max-w-2xl mx-auto mt-10">
      &lt;div className="flex flex-col gap-4 mt-10">
        &lt;input
          type="email"
          placeholder="メールアドレスを入力"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          className="p-3 border border-gray-300 rounded"
        />

        &lt;div className="text-center">
          &lt;button
            type="button"
            onClick={handleSubmit}
            className="bg-blue-600 text-white px-6 py-2 rounded"
          >
            送信
          &lt;/button>
        &lt;/div>

        {error &amp;&amp; &lt;p className="text-red-600 text-sm text-center">{error}&lt;/p>}
        {sent &amp;&amp; (
          &lt;p className="text-green-600 text-sm text-center">
            自動返信を送信しました
          &lt;/p>
        )}
      &lt;/div>
    &lt;/div>
  );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">use client</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">useState</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">react</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">z</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">zod</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">object</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">email</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">z</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">string</span><span style="color: #D8DEE9FF">()</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">email</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">正しいメールアドレスを入力してください</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MailForm</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9">email</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setEmail</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9">error</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setError</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9">sent</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">setSent</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">useState</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">false</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">handleSubmit</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">result</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">schema</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">safeParse</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">email</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9">result</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">success</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">setError</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">result</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">error</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">errors</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">message</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">return;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">try</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">res</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">await</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fetch</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/api/mail</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">method</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">POST</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">headers</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Content-Type</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">application/json</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">body</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">JSON</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">stringify</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">email</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">res</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">ok</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">setSent</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">true</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">setError</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">setError</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">送信に失敗しました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">catch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #D8DEE9">console</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">error</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">setError</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">通信エラーが発生しました</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">p-4 border rounded bg-gray-50 max-w-2xl mx-auto mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">flex flex-col gap-4 mt-10</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;input</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">email</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">placeholder</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">メールアドレスを入力</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">value</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">email</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">onChange</span><span style="color: #81A1C1">={</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">setEmail</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">e</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">target</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">value</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">p-3 border border-gray-300 rounded</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">/&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;div</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;button</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #8FBCBB">type</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">button</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #8FBCBB">onClick</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">handleSubmit</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bg-blue-600 text-white px-6 py-2 rounded</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            送信</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;/button&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">{</span><span style="color: #D8DEE9">error</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;p</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text-red-600 text-sm text-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;{</span><span style="color: #D8DEE9">error</span><span style="color: #81A1C1">}&lt;/p&gt;}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">{</span><span style="color: #D8DEE9">sent</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> (</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;p</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">className</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">text-green-600 text-sm text-center</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            自動返信を送信しました</span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #81A1C1">&lt;/p&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        )</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/div&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc11">STEP４：nodemailerの設定（lib/mailer.ts）</span></h3>



<p>開発／本番 切り替え対応の内容を記載します。</p>



<p>開発環境と本番環境でメール送信先や処理を切り替える処理は、<strong><code>lib/</code> 配下の共通関数モジュールにまとめておくのが一般的</strong>のようです。</p>



<p>こうすることで、環境ごとの処理分岐を1か所に集約でき、APIエンドポイントやフロントエンド側からは毎回同じ関数を呼び出すだけで済むようになります。<br>結果として、<strong>コードが見やすくなり、保守性も高まります。</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// src/lib/mailer.tsx

import { createTransport } from "nodemailer";
// @ts-expect-error 型定義がないため無視
import sgTransport from "nodemailer-sendgrid";

// 環境切り替え
export const getTransporter = () => {
  if (process.env.NODE_ENV === "production") {
    // 本番：例 SendGrid を使用
    return createTransport(
      sgTransport({
        apiKey: process.env.SENDGRID_API_KEY!,
      })
    );
  } else {
    // 開発：Mailpit を使用
    return createTransport({
      host: process.env.MAIL_HOST,
      port: Number(process.env.MAIL_PORT),
      secure: process.env.MAIL_SECURE === "true",
    });
  }
};
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// src/lib/mailer.tsx</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">createTransport</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">nodemailer</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// @ts-expect-error 型定義がないため無視</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sgTransport</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">nodemailer-sendgrid</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// 環境切り替え</span></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">getTransporter</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">NODE_ENV</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">production</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 本番：例 SendGrid を使用</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createTransport</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">sgTransport</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">apiKey</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">SENDGRID_API_KEY</span><span style="color: #81A1C1">!</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    )</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 開発：Mailpit を使用</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createTransport</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">host</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">MAIL_HOST</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">port</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Number</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">MAIL_PORT</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">secure</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">MAIL_SECURE</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">true</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc12">STEP５：環境変数設定</span></h3>



<p><strong><span class="keyboard-key">.env.local</span></strong> ：開発用.envのこと。mailpitの環境変数設定を記載します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># mailpit設定
MAIL_HOST=
MAIL_PORT=
MAIL_SECURE=</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key"><strong>.env.production</strong></span> ：本番環境用.envのこと。今回はSendGridの環境変数設定を記載しています。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># SendGrid設定
SENDGRID_API_KEY=</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key"><strong>.env</strong></span> ：開発・本番で共通使用.envのこと。今回は、送信者のメールアドレスが該当します。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>FROM_EMAIL=</code></pre></div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc13">STEP６：実行</span></h3>



<p><code>npm run dev</code> で開発環境のNext.jsを起動</p>



<p><code>http://localhost:3000</code> からフォームにアクセス</p>



<p>下記のinputタグにメールアドレスを入力する</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="391" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10-1024x391.png" alt="" class="wp-image-4535" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10-1024x391.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10-300x114.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10-768x293.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10-1536x586.png 1536w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10-1320x504.png 1320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.09.10.png 1646w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc14">STEP７：実行結果</span></h3>



<p>メールを送信すると <code>http://localhost:8025</code> のMailpitにメールが表示される！</p>



<figure class="wp-block-image size-large has-custom-border"><img loading="lazy" decoding="async" width="1024" height="265" src="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.11.45-1024x265.png" alt="" class="wp-image-4536" style="border-width:1px" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.11.45-1024x265.png 1024w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.11.45-300x78.png 300w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.11.45-768x199.png 768w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.11.45-1320x342.png 1320w, https://it-bokenki.com/wp-content/uploads/2025/07/スクリーンショット-2025-07-04-19.11.45.png 1509w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc15">まとめ｜Mailpitは開発中のメール送信テストに最適</span></h2>



<ul class="wp-block-list">
<li>開発中にメールを<strong>安全・手軽に確認したい</strong>なら、Mailpitは超便利</li>



<li>Dockerだけで立ち上がるから<strong>環境構築も簡単</strong></li>



<li>Next.js + nodemailerでも問題なく動作確認が可能</li>
</ul>



<p><strong>Dockerもっと勉強したい！</strong>と思われた方は、こちらの記事もおすすめです。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/03/docker-mysql/" title="DockerでMySQLをローカル構築｜Mac対応・CLI操作と文字化け対策も解説" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-18-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">DockerでMySQLをローカル構築｜Mac対応・CLI操作と文字化け対策も解説</div><div class="blogcard-snippet internal-blogcard-snippet">DockerでMacにMySQLの開発環境を一瞬で構築！Apple Silicon対応のインストール手順、docker-compose.ymlと.env連携、utf8mb4設定、ターミナル操作でのDB作成まで初心者にもわかりやすく解説しています。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-together is-style-normal-card">
<a href="https://it-bokenki.com/2025/07/03/docker-minio/" title="Next.js × Docker MinIO｜S3互換ストレージにファイルを保存する手順" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="320" height="180" src="https://it-bokenki.com/wp-content/uploads/2025/07/２行-17-320x180.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://it-bokenki.com/wp-content/uploads/2025/07/２行-17-320x180.png 320w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-17-120x68.png 120w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-17-160x90.png 160w, https://it-bokenki.com/wp-content/uploads/2025/07/２行-17-376x212.png 376w" sizes="auto, (max-width: 320px) 100vw, 320px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Next.js × Docker MinIO｜S3互換ストレージにファイルを保存する手順</div><div class="blogcard-snippet internal-blogcard-snippet">DockerでMinIOを構築し、Next.jsやNode.jsからS3互換のローカルストレージにファイルを保存・取得する方法を、初心者向けに手順付きでわかりやすく解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://it-bokenki.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">it-bokenki.com</div></div></div></div></a>
</div>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/08/docker-mailpit/">【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/08/docker-mailpit/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【初心者向け】Next.jsの設定ファイル「next.config.js」の使い方と定番設定3つ</title>
		<link>https://it-bokenki.com/2025/07/10/next-config-js/</link>
					<comments>https://it-bokenki.com/2025/07/10/next-config-js/#respond</comments>
		
		<dc:creator><![CDATA[てんハロ運営者]]></dc:creator>
		<pubDate>Thu, 10 Jul 2025 09:42:41 +0000</pubDate>
				<category><![CDATA[Next.js]]></category>
		<category><![CDATA[フロントエンド]]></category>
		<guid isPermaLink="false">https://it-bokenki.com/?p=4531</guid>

					<description><![CDATA[<p>※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。 プロが教える、業界最前線のノウハウ【Coloso】 困ってた自分に届けたい話 Next.jsでWebアプリを作っていると [&#8230;]</p>
<p>The post <a href="https://it-bokenki.com/2025/07/10/next-config-js/">【初心者向け】Next.jsの設定ファイル「next.config.js」の使い方と定番設定3つ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><span class="fz-12px">※当サイトはアフィリエイト広告を利用しています。商品リンクにはプロモーションを含む場合があります。</span></p>



<div style="text-align: center;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+601S1">
<img loading="lazy" decoding="async" border="0" width="300" height="250" alt="" src="https://www27.a8.net/svt/bgt?aid=250630247739&#038;wid=001&#038;eno=01&#038;mid=s00000026713001008000&#038;mc=1"></a>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www15.a8.net/0.gif?a8mat=457VJB+C7ZCTU+5Q4A+601S1" alt=""></div>



<p class="has-text-align-center"><a href="https://px.a8.net/svt/ejp?a8mat=457VJB+C7ZCTU+5Q4A+5YRHE">プロが教える、業界最前線のノウハウ【Coloso】</a></p>



<h2 class="wp-block-heading"><span id="toc1">困ってた自分に届けたい話</span></h2>



<p>Next.jsでWebアプリを作っていると、見かける <code>next.config.js</code> というファイル。</p>



<p>「設定って何をどうすればいいの？」<br>「これはなんのファイル？」<br>「書かないとダメ？」</p>



<p><strong>触らなくても動くから、触らずそっとファイル閉じた。</strong><br>そんな自分が恥ずかしかったため、今回調査しました。</p>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>この記事は、同じように困っていた方への<strong>備忘録兼シェア</strong>として書いています。</p>
</div></div>



<h2 class="wp-block-heading"><span id="toc2">next.config.jsとは？</span></h2>



<p><code>next.config.js</code> は、<strong>Next.jsアプリ全体の動作やビルド設定をカスタマイズするためのファイル</strong>です。<br>プロジェクトのルートに配置し、Next.jsの起動時に読み込まれます。</p>



<p><span class="keyboard-key">主な用途の例</span></p>



<ul class="wp-block-list">
<li>外部ドメインの画像を許可する</li>



<li>URLのリダイレクトやリライトを設定する</li>



<li>Reactの開発用チェックを有効にする</li>
</ul>



<p>つまり、<strong>「Next.jsアプリのグローバルな設定」をまとめる場所</strong>です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc3">初期状態の next.config.js（TypeScriptプロジェクトの場合）</span></h2>



<p>TypeScriptでNext.jsプロジェクトを作った直後は、次のような初期状態になっています。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
};

export default nextConfig;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextConfig</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> NextConfig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">/* config options here */</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<p>これは「設定内容はここに書いてね」という意味です。<br>設定がなければデフォルトの動作で進みます。必要になったら書き足すスタイルでOKです。</p>



<p><span class="keyboard-key">デフォルト設定の内容</span></p>



<ul class="wp-block-list">
<li><code>NextConfig</code> ：設定の書き間違いを防ぐためのヒントを出してくれる型</li>



<li><code>nextConfig</code> ：いろんな設定項目をこの中に追加できる</li>



<li><code>export default</code>：Next.jsに読み込ませる</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc4">よく使うNext.jsの設定3選（2025年版）</span></h2>



<p>設定ファイルにいろいろ書けるのは事実ですが、実際に現場でよく使われているのは以下の3つです。</p>



<h3 class="wp-block-heading"><span id="toc5">① 外部画像のURLを許可する（images）</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>images: {
  domains: &#91;"images.unsplash.com"&#93;,
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">images</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  domains</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">images.unsplash.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>Next.jsの <code>&lt;Image /&gt;</code> コンポーネントで<strong>外部サイトの画像（CDNなど）を使いたいときは、その画像のドメインを事前に許可</strong>しておく必要があります。そのため、<strong>ドメイン部分のみ記載</strong>します。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">ここで言う「外部画像」とは？</span></p>



<p>たとえば、Unsplashの画像をそのままURLで表示したい場合<br>※Unsplash：高品質な写真を無料で使えるサイト</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Image
  src="https://images.unsplash.com/photo-12345"
  width={500}
  height={300}
  alt="風景"
/></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Image</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">src</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://images.unsplash.com/photo-12345</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">width</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">500</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">height</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">300</span><span style="color: #81A1C1">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #8FBCBB">alt</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">風景</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #81A1C1">/&gt;</span></span></code></pre></div>



<p>このような<strong>外部URLから直接読み込む画像</strong>は、Next.jsのセキュリティルール上、<strong>そのままではブロックされます</strong>。そのため、<strong>読み込みを許可するドメインを明示的に指定する必要がある</strong>のです。</p>



<p><span class="keyboard-key">import する画像とはどう違うの？</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import sampleImage from "@/assets/sample.jpg";

&lt;Image 
　src={sampleImage} 
　width={500} 
　height={300} 
　alt="サンプル" 
/></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">sampleImage</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">@/assets/sample.jpg</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">Image</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">src</span><span style="color: #81A1C1">={</span><span style="color: #D8DEE9">sampleImage</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">width</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">500</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">height</span><span style="color: #81A1C1">={</span><span style="color: #B48EAD">300</span><span style="color: #81A1C1">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">　</span><span style="color: #8FBCBB">alt</span><span style="color: #81A1C1">=</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">サンプル</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #81A1C1">/&gt;</span></span></code></pre></div>



<p>このように <code>import</code> した画像は、プロジェクト内にあるファイルなので、<strong>許可設定は不要</strong>です。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc6">② ページのリダイレクト（redirects）</span></h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>async redirects() {
  return &#91;
    {
      source: "/old-page",
      destination: "/new-page",
      permanent: true,
    },
  &#93;;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">redirects</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> &#91;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">source</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/old-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">destination</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/new-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #88C0D0">permanent</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">  &#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>古いURLにアクセスされたとき、自動で別ページへ飛ばしたいときに使います。<br><code>permanent: true</code> にすると、<strong>SEO的にも「ページ移動済み」と評価される</strong>のでおすすめです。</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">なぜ async なの？</span></p>



<p>この関数が <code>async</code> になっているのは、<strong>必要に応じて外部APIなどから転送先リストを取得するなど、非同期処理ができるようにするため</strong>です。<br>（もちろん、今回のように <code>return</code> だけでもOKです）</p>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading"><span id="toc7">③ Reactの厳格モードをONにする（reactStrictMode）</span></h3>



<p>開発中に「Reactの間違いを教えてくれるモード」。初心者ほどONがおすすめ！</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>reactStrictMode: true</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">reactStrictMode</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span></span></code></pre></div>



<p>この設定をしたからといって、アプリの動きが変わるわけではありません。</p>



<figure class="wp-block-table"><table><thead><tr><th>設定</th><th>目的</th><th>利便性の違い</th></tr></thead><tbody><tr><td><code>reactStrictMode: false</code></td><td>普通に動く</td><td>バグに気づきにくい</td></tr><tr><td><code>reactStrictMode: true</code></td><td>バグの芽を早めに見つける開発モード</td><td>開発中にミスを教えてくれる</td></tr></tbody></table></figure>



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">「true」にすると何が起きるの？</span>　</p>



<p>開発中だけ、以下のようなチェックモードが動くようになります。</p>



<ul class="wp-block-list">
<li><code>useEffect</code> などが <strong>2回実行される</strong>（副作用の確認）</li>



<li>非推奨なReactの使い方を <strong>警告してくれる</strong></li>



<li>コンポーネントの<strong>再レンダリングミス</strong>に気づきやすい</li>
</ul>



<p><span class="keyboard-key">本番には関係ないの？</span></p>



<p><strong>本番（build された後のアプリ）では一切影響なし</strong><br>なので、「true にしておいて損はない」設定です。</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc8">よく使う設定を全部まとめるとこうなる</span></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // 開発モードでReactのチェックを強化
  reactStrictMode: true,

  // 外部ドメインからの画像を許可
  images: {
    domains: &#91;"images.unsplash.com"&#93;,
  },

  // ページのリダイレクト設定
  async redirects() {
    return &#91;
      {
        source: "/old-page",
        destination: "/new-page",
        permanent: true,
      },
      {
        source: "/temporary",
        destination: "/maintenance",
        permanent: false,
      },
    &#93;;
  },
};

export default nextConfig;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">NextConfig</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">next</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> NextConfig </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 開発モードでReactのチェックを強化</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">reactStrictMode</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// 外部ドメインからの画像を許可</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">images</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">domains</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> &#91;</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">images.unsplash.com</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">  </span><span style="color: #616E88">// ページのリダイレクト設定</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">async</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">redirects</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> &#91;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">source</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/old-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">destination</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/new-page</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">permanent</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">source</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/temporary</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">destination</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">/maintenance</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">permanent</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    &#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">export</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">default</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">nextConfig</span><span style="color: #81A1C1">;</span></span></code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc9">補足：環境ごとの切り替えは .NODE_ENV でOK！</span></h2>



<p>昔は <code>next.config.js</code> で環境変数を設定していたこともありましたが、コード内で <code>.NODE_ENV</code> を利用して切り替えるのが一般的です。</p>



<p>これは「今が開発環境かどうか」を判定して、使うAPIのURLを分けている例です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const isDev = process.env.NODE_ENV === "development";

const apiUrl = isDev
  ? "http://localhost:3000/api"
  : "https://example.com/api";
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">isDev</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">process</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">env</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">NODE_ENV</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">development</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">apiUrl</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">isDev</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">http://localhost:3000/api</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https://example.com/api</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p><code>NODE_ENV</code> は実行コマンドで自動で決まります。<br><code>.env</code> や <code>.env.production</code> の<strong>ファイル名で決まるわけではなく</strong>、<strong>コマンドによって自動で切り替わる</strong>と覚えましょう。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>実行コマンド</th><th>NODE_ENVの値</th></tr></thead><tbody><tr><td><code>npm run dev</code></td><td><code>"development"</code>（開発）</td></tr><tr><td><code>npm run build &amp;&amp; start</code></td><td><code>"production"</code>（本番）</td></tr></tbody></table></figure>



<div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x1f4a1; 結論</span> ：環境切り替えについて <strong><code>next.config.js</code> に無理に書く必要はありません。</strong></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc10">設定を変えたら再起動を忘れずに</span></h2>



<p><code>next.config.ts</code> を変更したら、<strong>開発サーバーを一度止めて再起動</strong>しないと反映されないことがあります。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code># Ctrl + C で止めてから
npm run dev</code></pre></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading"><span id="toc11">Next.js をもっと詳しく学びたい人へおすすめの本</span></h2>



<p><span class="keyboard-key">&#x25b6; 動かしながら基礎から学びたい人に</span><br>「まずは手を動かしたい！」という人にぴったりの一冊。基本構造から丁寧に解説されており、Next.jsとReactの連携も自然に身につきます。初学者でもステップを追いやすく、サンプルアプリの構築を通して理解を深められる構成です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41IcDiqx7jL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0D9PT5FVJ%2F%3Ftag%3Da8-affi-321185-22">動かして学ぶ！Next.js/React開発入門</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,168<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www10.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; Reactの経験があり、次のステップへ進みたい人に</span><br>「Reactは少し触ったことがあるけど、Next.jsを仕事で使いこなしたい」という人向け。実践を意識した構成で、Webアプリの構造、レンダリング戦略、SEO対応など、現場で必要なノウハウが詰まっています。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/41zubkTAnmL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0F9PXRFHD%2F%3Ftag%3Da8-affi-321185-22">React Next.js 実践プログラミング入門: React Next.js モダンWeb開発実践ガイド</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,300<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:17時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www11.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:10px" aria-hidden="true" class="wp-block-spacer"></div>



<p><span class="keyboard-key">&#x25b6; App Routerを本格的に学びたいエンジニアへ</span><br>App Routerを軸に、最新のNext.js開発に対応した本格派。中級者以上の方が「一歩先へ進みたい」と感じたときに読みたい一冊。デザインパターンや設計の視点もあり、長期的に役立つ内容です。</p>



<table cellpadding="0" cellspacing="0" border="0" style=" border:1px solid #ccc; width:300px;"><tr style="border-style:none;"><td style="vertical-align:top; border-style:none; padding:10px; width:140px;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22"><img decoding="async" border="0" alt="" src="https://m.media-amazon.com/images/I/51SeLrEQrQL._SS160_.jpg" /></a></td><td style="font-size:12px; vertical-align:middle; border-style:none; padding:10px;"><p style="padding:0; margin:0;"><a rel="nofollow" href="https://px.a8.net/svt/ejp?a8mat=459I7K+A7CH0Y+249K+BWGDT&#038;a8ejpredirect=https%3A%2F%2Fwww.amazon.co.jp%2Fdp%2FB0CW1KC9N8%2F%3Ftag%3Da8-affi-321185-22">実践Next.js —— App Routerで進化するWebアプリ開発 エンジニア選書</a></p><p style="color:#cc0000; font-weight:bold; margin-top:10px;">新品価格<br/>￥3,665<span style="font-weight:normal;">から</span><br/><span style="font-size:10px; font-weight:normal;">(2025/7/21 23:18時点)</span></p></td></tr></table>
<img loading="lazy" decoding="async" border="0" width="1" height="1" src="https://www13.a8.net/0.gif?a8mat=459I7K+A7CH0Y+249K+BWGDT" alt="">



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-balloon-ex-box-1 speech-wrap sb-id-1 sbs-stn sbp-l sbis-cb cf block-box"><div class="speech-person"><figure class="speech-icon"><img decoding="async" src="https://it-bokenki.com/wp-content/uploads/2023/05/名称未設定のデザイン-1-1-150x150.png" alt="てんハロ運営者" class="speech-icon-image"/></figure><div class="speech-name">てんハロ運営者</div></div><div class="speech-balloon">
<p>おつかれさまでした！</p>
</div></div><p>The post <a href="https://it-bokenki.com/2025/07/10/next-config-js/">【初心者向け】Next.jsの設定ファイル「next.config.js」の使い方と定番設定3つ</a> first appeared on <a href="https://it-bokenki.com">てんハロ｜未経験エンジニアのIT学習ログ</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://it-bokenki.com/2025/07/10/next-config-js/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
