Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
サーバーレスAPI(API Gateway+Lambda)とNext.jsで 個人ブログを作ろう!
Search
shuntaka
July 18, 2024
Technology
2.3k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
サーバーレスAPI(API Gateway+Lambda)とNext.jsで 個人ブログを作ろう!
shuntaka
July 18, 2024
More Decks by shuntaka
See All by shuntaka
GitHub Copilot CLI が マッスルに馴染むまで / Until GitHub Copilot CLI Becomes Second Nature
shuntaka
1
15k
Claude Code活用時のつらみと隙間を埋めるツール / Tools to bridge the gaps and pains of using Claude Code
shuntaka
0
16k
CloudFront OAC × Lambda Function URLs で作る認証付き簡易サイト / Simple Authenticated Website Built with CloudFront OAC and Lambda Function URLs
shuntaka
0
4.3k
顧客体験を加速させるチャットボットで始めるAIエージェント入門 / Introduction to AI Agents: Starting with Chatbots to Accelerate Customer Experience
shuntaka
1
4.3k
AI SDKで作るチャットボット開発 / Chatbot Development with AI SDK
shuntaka
0
2k
Claude Codeチーム活用の現在地 〜小さな実践と今後の展望〜 / Current State of Claude Code Team Adoption - Small Practices and Future Prospects
shuntaka
2
9k
Claude Codeをdotfiles管理しよう! / Let's Manage Claude Code with Dotfiles!
shuntaka
8
22k
個人プロジェクトをKiroベースに 乗り換えてみた / I Tried Migrating My Personal Project to Kiro-based
shuntaka
0
3.1k
AI駆動開発がもたらす革新と実践 / Innovation and Practice Brought by AI-Driven Development
shuntaka
2
2.5k
Other Decks in Technology
See All in Technology
Antigravity SDK for the Java Developer
glaforge
0
180
CLIライブラリ開発を支える技術
htnabe
0
150
30座EKS, 180次升級淬煉的EKS Upgrade Skill 的歷程
eric8230
0
210
時うどん〜Socket.getifaddrsで学ぶネットワーク編 / Tokiudon: The Socket.getifaddrs Edition
coe401_
4
220
【技術的負債conf】事業成長に伴う技術的負債の説明責任とAIによるモニタリング、認知的負債について
i35_267
3
2.1k
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
25
17k
ADKで始める業務改善 - AIエージェント開発時の考えと設計
harappa80
2
270
銀行勘定系システムにおける開発プロセス刷新×AIによる環境モダナイゼーション / Development Process Transformation and AI-Driven Environment Modernization
muit
1
2.6k
Von-Neumann Machines, Dreams & The Futures of IT
ufried
0
120
リアーキテクチャ後の障害ゼロを目指したShadow Testingの取り組み
nihonbuson
PRO
1
170
10Xに技術的負債をもたらした「2つの境界の歪み」その構造と解消への営み
10xinc
0
2.4k
ソフトウェアDNAとクラウドエージェントのススメ
cloudace
0
120
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Git: the NoSQL Database
bkeepers
PRO
432
67k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
50
10k
A Tale of Four Properties
chriscoyier
163
24k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
610
Exploring anti-patterns in Rails
aemeredith
4
510
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
Transcript
サーバーレスAPI(API Gateway+Lambda)とNext.jsで 個⼈ブログを作ろう! 2024.7.20 製造ビジネステクノロジー部 髙橋俊⼀ a.k.a. shuntaka
⾃⼰紹介 2 shuntaka/髙橋俊⼀ 19年8⽉クラメソ⼊社 製造ビジネステクノロジー部 基本的にAWSでサーバーサイド開発 ‧IoTバックエンド/エッジソフトウェア開発 ‧サーバレス/コンテナ開発 ‧データ基盤開発 ツール開発:
ddbrew/gh-p2/oax/s3-concat/preview-asciidoc.vim … shuntaka.dev/who
3 「Speakerdeck shuntaka」で検索 or https://spekerdeck.com/shuntaka
ご理解頂きたいこと 4 ‧フロントエンド/デザインは、サーバサイドエンジニアが 頑張ってみた...くらいの温度感で、要素少なめです😿 ‧サーバーレスAPIと表記しているところは、Amazon API Gateway+AWS LambdaのREST APIを指します
⽬次 5 ‧過去の個⼈ブログ ‧現在の個⼈ブログ ‧経験から学んだこと ‧未来へ向けて ‧まとめ
⽬次 6 ‧過去の個⼈ブログ 👈 ‧現在の個⼈ブログ ‧経験から学んだこと ‧未来へ向けて ‧まとめ
作る経緯 7 2018年前職時代 Web企業のミートアップにポツポツ参加し始め、 参加ブログを書きたくなる🐥 当時Goが好きだったので、静的サイトジェネレータのHugoに興味 を持つ
構成 8 静的サイトジェネレーター(Hugo)を使って構築 (独⾃ドメイン、HTTPS) 2. ビルド‧デプロイ 1. push
外観 9 作った当初は書いていたが、しだいに全く書かなくなり、ドメ イン解約😱
ブログ運⽤が続かなかった理由 10 振り返ると感じた続かない理由 ‧サイト⾃体へ愛着がなかった ‧モチベーションに繋がる仕組みを⾃分が作らなかった
⽬次 11 ‧過去の個⼈ブログ ‧現在の個⼈ブログ 👈 ‧経験から学んだこと ‧未来へ向けて ‧まとめ
作る経緯 12 技術ブログといえばZenn!影響をかなり受けてま す。Zennを触り、個⼈ブログに以下の体験を検証 /実装したいと感じた。 ‧Gitプッシュ後のサイトへ反映速度 ‧記事プレビューの体験の良さ
作る経緯 13 プラスで漠然と思っていたこと ‧⾃分がほぼ毎⽇使うWebアプリを作り たかった(改善欲の刺激) ‧業務でサーバーレスAPIを書いているの で趣味で使いたい ‧技術検証できる庭が欲しい ‧業務でありそうな要件で実装したい
構成 14
構成 15 ・お財布に優しい(ほぼ無料枠運用) ・Vercel/Next.jsのISRとの相性(コールドスタート問題の緩和) ・個人でお手軽にクラサバ構成が取れる ・Fly.io, Deno deploy, Cloudflare workerなどの選択肢
→ 自分の業務シナジーを考慮
外観 16 shuntaka.dev
現在のブログで注⼒したこと 17 ‧Gitプッシュ後サイトへ即反映 ‧記事プレビューの体験の良さ ‧サイト⾃体への愛着 ‧ モチベーションに繋がる仕組み
現在のブログで注⼒したこと 18 ‧Gitプッシュ後サイトへ即反映 👈 ‧記事プレビューの体験の良さ ‧サイト⾃体への愛着 ‧ モチベーションに繋がる仕組み
Gitプッシュ後サイトへ即反映 19 GitHub Appsから直接DBにデータを投⼊することで実現 サイトや過去記事ビルドが必要なくなる
WebアプリからのApps連携 20 ※ GIFなのでPDFだ と再⽣できません
Webアプリからの連携シーケンス 21 https://shuntaka.dev/shuntaka/articles/01ezm5k2rt1jm6zbsewm33r0xw
Webhook検証 22 Webhookの検証もしておく と安全 ‧GitHubでwebhookシーク レットを指定 ‧ボディ部を上記を使い HMAC-SHA256でハッシュ ‧X-Hub-Signature-256と⼀ 致検証
Webhookのトラブルシューティング 23 GitHub Apps上からペイロードの確認可能
現在のブログで注⼒したこと 24 ‧Gitプッシュ後サイトへ即反映 ‧記事プレビューの体験の良さ 👈 ‧サイト⾃体への愛着 ‧ モチベーションに繋がる仕組み
記事プレビューの体験の良さ 25 静的サイトジェネレータのファイルシステム変更監視による プレビューは顧客が求めていたもの...⾃作するならどうする か... エディタにより依存させれば、汎⽤性はないが良い体験が⽣ まれそう...
マークダウンパーサー 26 ‧Rustで⾃作を試みるが断念。markdown-itを拡張 ‧困ったらzenn-dev/zenn-editorの実装を参考にさせて頂い ている... ‧独⾃で欲しい機能を拡張できる(PlantUML,SpeakerDeckの 指定スライドプレビューなど) ‧今後⾔語処理系の学習でリベンジしたい...
Vimとの連携 27 denops.vim Vim/NeovimプラグインをTypeScript(deno) で書けるというエコシステム denoはnpmのパッケージと互換性があるた め、前述パーサーを流⽤できる
リアルタイムプレビュー(Vim/Neovim) 28
リアルタイムプレビュー(Vim/Neovim) 29 ※ GIFなのでPDFだ と再生できません
現在のブログで注⼒したこと 30 ‧Gitプッシュ後サイトへ即反映 ‧記事プレビューの体験の良さ ‧サイト⾃体への愛着 👈 ‧ モチベーションに繋がる仕組み
作って気づく愛着 31 結論、⾃分でデザインして時間をかけることで愛着が醸成さ れた。 これは意識して訳ではなく、Next.jsでやると決めた瞬間デザ インは必要に迫られ、やらざるを得なかった。
デザイン 32 Figmaの学習。⾼評価のUdemyの動画を⼿を動かしながら慣 れていく。(※ 2020年時点なので注意)
デザイン 33 オブジェクトコネコネ...⽇曜⼤⼯感...
ダークモード 34 CSS Variablesを使って作成 配⾊はGitHubのダークモー ドを参考に
OGP 35 ‧サムネイル設定 → そのまま表⽰ ‧サムネイル未設定→タイトル⽂字列をCloudinaryのURL/画像 に埋込 → URLは署名を含められる 任意の⼈が⽂字列を埋め込むことはできない
現在のブログで注⼒したこと 36 ‧Gitプッシュ後サイトへ即反映 ‧記事プレビューの体験の良さ ‧サイト⾃体への愛着 ‧ モチベーションに繋がる仕組み 👈
アクセス解析導⼊ 37 ‧Google Analytics ‧Search Console連携
必要なこと 38 静的サイトジェネレータならデフォルトである。流⽯。 ‧sitemap⽣成(->Search Consoleへ登録) ‧RSS⽣成
現在のブログで注⼒したこと 39 ‧Gitプッシュ後サイトへ即反映 ‧記事プレビューの体験の良さ ‧サイト⾃体への愛着 ‧ モチベーションに繋がる仕組み
⽬次 40 ‧過去の個⼈ブログ ‧現在の個⼈ブログ ‧経験から学んだこと 👈 ‧未来へ向けて ‧まとめ
サービス運⽤する楽しさ 41 ‧⾃⼰表現と振り返りの楽しみ ‧特定の⼈にしか⾒られない⼼理的安全性 ‧ちゃんと書いた記事はオーガニック検索流⼊ ‧検索パフォーマンスから読者の興味を分析 ‧意外な⼈気記事の発⾒(例:Zig⾔語、platformio記事)
技術を試す遊び場 42 ‧利害関係者がいないため、新しいライブラリや開発⼿法を 試しやすい ‧既存システムで試すことで、使うだけとは異なった視点(開 発や運⽤に適⽤した場合)の体験が得られる ‧いろんなサイトを参考にするようになる。プラックティス の塊。(今回だとGitHub/Zenn/Qiitaなど...) ‧ある程度⼈にみられることを考慮された動くサンプルが⼿ 元にあるメリット
必要は発明の⺟ 43 ‧無から必要を⽣み出すのは難しい ‧ブログ開発/運⽤することで必要が⽣まれやすい ‧可処分時間やお財布を考えて⼯夫の余地を探す等 通して、様々ブログ記事やCLI開発をした... 詳細は過去記事で
実際作りっぱなし... 44 ‧最初は熱中、その後はライブラリ、ランタイム更新対応 ‧業務や登壇の機会を利⽤してブースト ‧⾃分が興味あること/ないことのメタ認知
SaaS周りの注意は必須... 45 ‧スマホ未圧縮画像配信で、ネットワーク帯域を使いすぎて料 ⾦発⽣経験 ‧クレカ登録不要でもお試し系は、解約忘れ注意。⾃動停⽌ しない場合あり、プロジェクトが消せず、放置期間含めて請求 が発⽣したり、、 → 契約とGoogleカレンダー登録は同時に ‧新興の海外系SaaSだとサポートもあまり期待は出来ない
セッション概要 46 ‧過去の個⼈ブログ ‧現在の個⼈ブログ ‧経験から学んだこと ‧未来へ向けて 👈 ‧まとめ
登場するコードはこちらに 47 https://github.com/shuntaka9576/devio2024-sample-code
試したいこと 48 技術選定をしたのは4年前なのでリプレースするために、技術検 証してみる ‧同じ解決策でも新しいやり⽅へ ‧今⾃分がワクワクする構成へ
試したいこと 49 ‧サーバサイドJSマルチランチタイム ‧エコシステムの成⻑への追従 ‧認証 ‧認知負荷へ対応
試したいこと 50 ‧サーバサイドJSマルチランチタイム 👈 ‧エコシステムの成⻑への追従 ‧認証 ‧認知負荷へ対応
JSランタイムの選択肢 51 WinterCGによる⾮Webブラウ ザJSランタイム標準化の流れ Deno/Bun/Node.jsの三つ巴 開発者体験はまだNode.jsの印 象。今後は分からない。 Node.jsを使いつつ、乗り換え 可能な選択肢を持つ。
HTTPサーバー/ルーティング 52 Honoを利⽤(Lambda⽬線だとHTTPサーバー部分は含まない) ‧作ったアプリがコンテナや別JSランタイム上で検証可 ‧活発なコミュニティ ‧Web標準API/マルチランタイム → ミドルウェア含めランタイム互換性が⾼い → 利⽤者‧開発者⼈⼝が多くなりそう(?)
→ エコシステムが充実しそう!
試したいこと 53 ‧サーバサイドJSマルチランチタイム ‧エコシステムの成⻑への追従 👈 ‧認証 ‧認知負荷へ対応 ‧その他
Nodeエコシステム 54 ⾼速なツールチェインの採⽤ ‧pnpm → 並列実⾏ヘルパー不要なので使っているが、拘りなし(多様 性がありそう) ‧Biome(Rust製で⾼速) → 異次元な速さ+LSPで最⾼。BE的には⼗分。
ESMを使う 55 ESMしかサポートしないライブラリも少なくない CDKもtsx経由で実⾏すればESMで実⾏可能 // cdk.json { "app": "pnpm tsx
bin/cdk.ts" … }
56 const getConfig = async (): Promise<Config> => { const
secretsAndVariables = await getVariablesAndSecrets(); const parseResult = configSchema.safeParse({ auth: { rpID: secretsAndVariables.variables.rpId, rpName: secretsAndVariables.variables.cookieDomain, }, ... }); ... return parseResult.data; }; export const config = await getConfig(); ESMを使う to level awaitの活⽤ ‧起動時環境変数 /SSM取得&バリデー ション(設定し忘れ防 ⽌) ‧以後config変数を Lambdaでグローバル 変数キャッシュ
モノレポ構成 57 CIの⼀部共通化やリポジ トリ間のCDが少なくな り良い。 GHAは数年で共通化の余 地が増えた。横展可能な 秘伝タレを作ると良い。 ‧Reusing workflows
‧Composite action name: Setup node description: Setup Node and restore cache runs: using: 'composite' steps: - uses: actions/setup-node@v4 with: node-version-file: './.node-version' - uses: pnpm/action-setup@v4 - name: Restore node modules uses: actions/cache@v4 id: cache_dependency env: cache-name: cache-dependency with: path: '**/node_modules' key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Install node modules
試したいこと 58 ‧サーバサイドJSマルチランチタイム ‧エコシステムの成⻑への追従 ‧認証 👈 ‧認知負荷へ対応 ‧その他
認証 59 ‧Firebase Authenticationを採⽤ ‧⾃分⽤にダッシュボードが欲しくて実装
認証 60 パスワード⼊れるの⾯倒問題
パスキーの検証 61 技術検証でWebAuthnの仕様を使ったパスキー認証を試す ライブラリは以下を利⽤ ‧hono_session(Honoミドルウェア) ‧SimpleWebAuthn SimpleWebAuthnのexampleを動かしつつ流れを把握... ただ、永続化していないので、DynamoDBで永続化
パスキーの検証 62 ‧challengeをユーザーのデバイ ス(認証器)に 保存された秘密鍵で 署名を作成 ‧サービス側で保存された公開鍵 を⽤いて認証
パスキーの検証 63 ※ GIF iCloudキーチェーンを使って、 ⽣体認証でサインアップ/ログイン デモ iCloudキーチェーンで同期される ため、Mac/iPhoneでログイン可
試したいこと 64 ‧サーバサイドJSマルチランチタイム ‧エコシステムの成⻑への追従 ‧認証 ‧認知負荷へ対応 👈 ‧その他
⾃作ブログは開発頻度にムラあり 65 実際に⾃作ブログの開発頻度はときどきになるので、できれ ば認知負荷を下げたい... try! catch! error! unknown! 😱
関数型スタイルTypeScript 66
関数型スタイルTypeScript 67 ‧neverthrow ‧fp-ts(Effectと統合) ‧Effect → Effectを試す
Effectとは 68 関数型プログラミングの影響を受けて以下をサポート ‧最⼤限の型安全性(エラー処理を含む) ‧テストユーテリティ ‧o11y機能 エコシステムが重厚⻑⼤
69 Effectを試す interface Effect<Success, Failure = never, Requirements = never>
成功時の型 依存するデータ型 (本セッションでは割 愛) 失敗時の型 Effect型について。近いのがRustのResult型。
70 Effectを試す 関数の合成 1 つの関数の出力を受け取り、それをパイプライン内の次の関 数の入力として渡します。これにより、複数の関数を連結して複 雑な変換を構築
71 Effectを試す const effects = pipe( { isLoggedIn: session.get('isLoggedIn'), userID:
session.get('userID'), }, Schema.decodeUnknownEither(toValidSchema), Effect.flatMap(workflow) ); const result = await Effect.runPromise(effects); pipeを使って関数を合成する
72 const effects: Effect.Effect<{ isLoggedIn: boolean; user: { userName: string;
}; }, DataBaseUnknownError | ParseError | NotFoundUserError, never> 先ほどのeffects変数の型推論。赤枠がハンドリングされていない ことが自明。副作用の存在が分かる。 Effectを試す
73 関数の振る舞いを予測可能に 関数ができることはすべて、その シグネチャに書かれている。関数 は引数を受け取り、値を返す。そ れ以外は特にないもしない。/ (2.12. 信頼される純粋関数より) → 関数の振る舞いを予測可能に
し、副作用を避ける
74 const effects = pipe( ... Effect.match({ onSuccess: (result) =>
({ status: 200, body: { isLoggedIn: result.isLoggedIn, user: result.user }, }), onFailure: (error) => { switch (error._tag) { case 'ParseError': return { status: 200, body: { isLoggedIn: false } }; case 'NotFoundUserError': return { status: 400, body: { isLoggedIn: false } }; case 'DataBaseUnknownError': return { status: 500, body: { code: 'InternalServerError' } }; } }, }) ); エラーハンドリング漏れを防ぐことができる。日曜大工も安心。 ハンドリングをすれば、 第⼆引数はnever型に Effectを試す
試したいこと 75 ‧サーバサイドJSマルチランチタイム ‧エコシステムの成⻑への追従 ‧認証 ‧認知負荷へ対応 ‧その他 👈
76 その他やってみたいこと ‧画像の最適化をしてネットワーク帯域を減らしたい ‧スライド機能 ‧全⽂検索(meilisearch, algoria)
77 その他やってみたいこと ベアメタルk8sに載せたい →
⽬次 78 ‧過去の個⼈ブログ ‧現在の個⼈ブログ ‧経験から学んだこと ‧未来へ向けて ‧まとめ 👈
まとめ 79 過去 現在 未来?
まとめ 80 ‧ブログの運⽤(アクセス解析/SEO/デザイン) ‧技術試す遊び場(調査/検証/改善/業務/メタ認知) ‧発明(ブログ執筆/登壇ネタ/ツール開発)
ご清聴ありがとうございました& お付き合い頂きありがとうござ いました🥹 81
レビュー協⼒/参考⽂献 82 レビュー協⼒ ‧Kyo さん (とっ散らかっていたところをまとめて下さり圧倒的感謝!) 参考⽂献 ‧Zennを⽀える技術とサービス構成 ‧TSKaigi関連 ‧TypeScript
関数型スタイルでバックエンド開発のリアル ‧Step by Stepで学ぶ、ADT(代数的データ型)、モナドからEffect-TSまで゙ ‧複雑なビジネスルールに挑む:正確性と効率性を両⽴するfp-tsのチーム活⽤術 ‧Effectで作る堅牢でスケーラブルなAPIゲートウェイ ‧Deno Deploy で WebAuthn を使ったサイトを作ってみた ‧パスキーのすすめ
83