Open3
Hono 参考資料
![masterak](https://res.cloudinary.com/zenn/image/fetch/s--Otiqjr1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/49698f6451.jpeg)
参考資料
- Remix+Hono+JWTで簡単な認証を実装する
- OAuthの仕組みを説明してHonoで実装してみる(OAuth解説)
- JSON Web Token(JWT)の紹介
- [Deno] FreshでHonoのRPCモードを使う 🍋+🔥
- [Deno] Fresh入門ハンズオン ~ プロジェクト作成からデプロイまで
- How to Setup Auth with Fresh ログイン機能について
- Hono Error handling in Validator
- Cloudflare Workers x HonoでJWT認証を設定する
- HonoのmiddlewareでAPI-KEYを使った認証を行う
- Hono 環境変数を使う Bindungsa
- JWT Auth Middlewareの作り方
- なんとなく CORS がわかる...はもう終わりにする。
- JWT認証の流れを理解する
- Forms FreshでPOST, GETフォームの扱い方
- Query D1 from Hono
- CloudFlare D1 + Prisma
- D1 Getting started
- Hono + Prisma + Cloudflare D1でさくっとAPIを作ってみる
- Build Applications at the Edge with Prisma ORM & Cloudflare D1 (Preview)
- Prisma queries
- キャッシュ周り
- 動的コンテンツをエッジにキャッシュする。
![masterak](https://res.cloudinary.com/zenn/image/fetch/s--Otiqjr1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/49698f6451.jpeg)
import { Handlers } from "$fresh/server.ts";
import { setCookie } from "std/http/cookie.ts";
export const handler: Handlers = {
async POST(req) {
const url = new URL(req.url);
const form = await req.formData();
if (form.get("username") === "deno" && form.get("password") === "land") {
const headers = new Headers();
setCookie(headers, {
name: "auth",
value: "bar", // this should be a unique value for each session
maxAge: 120,
sameSite: "Lax", // this is important to prevent CSRF attacks
domain: url.hostname,
path: "/",
secure: true,
});
headers.set("location", "/");
return new Response(null, {
status: 303, // "See Other"
headers,
});
} else {
return new Response(null, {
status: 403,
});
}
},
};
このコードは、HTTP レスポンスを作成し、ユーザーにリダイレクトする際にクッキーを設定する例です。以下に各部分の詳細な説明をします。
Headers
オブジェクトの作成
1. const headers = new Headers();
- 空の
Headers
オブジェクトを作成します。これに対して後で HTTP ヘッダーを追加します。 - Headers オブジェクトは、HTTP リクエストやレスポンスに関連するヘッダーを操作するためのインターフェイスです。
2. クッキーの設定
setCookie(headers, {
name: "auth",
value: "bar", // this should be a unique value for each session
maxAge: 120,
sameSite: "Lax", // this is important to prevent CSRF attacks
domain: url.hostname,
path: "/",
secure: true,
});
-
setCookie
関数を使って、クッキーを設定します。クッキーの詳細は以下の通りです:-
name: "auth"
: クッキーの名前は "auth" です。 -
value: "bar"
: クッキーの値は "bar" です(セッションごとに一意であるべき)。 -
maxAge: 120
: クッキーの有効期間は 120 秒です。 -
sameSite: "Lax"
: クッキーは SameSite 属性を "Lax" に設定しています。これにより、CSRF 攻撃を防ぎます。 -
domain: url.hostname
: クッキーのドメインをurl.hostname
に設定します。 -
path: "/"
: クッキーのパスをルートに設定します。 -
secure: true
: クッキーは HTTPS 接続でのみ送信されます。
-
3. リダイレクトヘッダーの設定
headers.set("location", "/");
-
location
ヘッダーを "/" に設定します。これにより、クライアントはルートパスにリダイレクトされます。 - リダイレクト先を変更する場合はここを編集します。
4. HTTP レスポンスの作成と返却
return new Response(null, {
status: 303, // "See Other"
headers,
});
-
Response
オブジェクトを作成します。ボディはnull
です。 - HTTP ステータスコードは
303
("See Other") に設定されます。これは、クライアントに他の URI を取得するよう指示するリダイレクトコードです。 - 先ほど設定した
headers
をレスポンスに追加します。
全体の流れ
- 新しいヘッダーオブジェクトを作成します。
- クッキーを設定し、その設定をヘッダーに追加します。
-
location
ヘッダーを設定し、リダイレクト先を指定します。 - HTTP レスポンスを作成し、ステータスコード 303 でリダイレクトを指示し、設定したヘッダーを含めてレスポンスを返します。
このコードは、ユーザーが特定の URL にアクセスしたときに、クッキーを設定してから別のページにリダイレクトするシナリオを実現するためのものです。クッキーの設定には、セキュリティとセッション管理のための重要な属性が含まれています。
pretyJsonについて
Pretty JSON middleware enables "JSON pretty print" for JSON response body. Adding ?pretty to url query param, the JSON strings are prettified.
つまりPretty JSON Middleware
を使用すると、URLのクエリパラメータに ?pretty
を追加することで、JSONレスポンスを整形された(見やすい)形式で返すことができます。
通常、APIからのJSONレスポンスはデータ転送の効率を上げるために、空白や改行を省略したコンパクトな形式で送信されます。Pretty JSON Middleware
を使うと、デバッグや開発時にそのJSONレスポンスを整形して見やすくすることができます。
具体例
通常のJSONレスポンス
{"name":"John","age":30,"city":"New York"}
?pretty
を使用した場合の整形されたJSONレスポンス
{
"name": "John",
"age": 30,
"city": "New York"
}
使用方法
URLに ?pretty
を追加するだけです。
整形されたJSONレスポンスを取得するリクエスト
curl http://localhost:8787/api/posts?pretty
![masterak](https://res.cloudinary.com/zenn/image/fetch/s--Otiqjr1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/49698f6451.jpeg)
HonoでZennのRSSデータを取得して、パース。ほとんどAIが書いてくれた。
そのままだと多分使えないので、事前にキャッシュしておく方法を考える。
今回の教訓は、正規表現の使い方が未だによくわからないマンだけどやっぱり便利ということを再認識した。
import { Hono } from 'hono'
const app = new Hono();
app.get('/', async (c) => {
const res = await fetch('https://zenn.dev/catnose99/feed');
const rss = await res.text();
try {
const json = await parseRSStoJson(rss);
return c.json(json);
} catch (e) {
console.log(e)
return c.text("Not Found");
};
})
export default app;
type RSSItem = {
title: string;
link: string;
pubDate: string;
}
async function parseRSStoJson(text:string): Promise<RSSItem[]> {
const items:RSSItem[] = [];
// <items>の検索・正規表現
const itemsRegex = /<item>([\s\S]*?)<\/item>/g;
let match;
while((match = itemsRegex.exec(text)) !== null) {
const itemContent = match[1];
const titleMatch = itemContent.match(/<title>([\s\S]*?)<\/title>/);
const linkMatch = itemContent.match(/<link>([\s\S]*?)<\/link>/);
const pubDateMatch = itemContent.match(/<pubDate>([\s\S]*?)<\/pubDate>/);
// CDATAセクションを削除
let title = titleMatch ? titleMatch[1].trim() : '';
title = title.replace(/<!\[CDATA\[(.*?)\]\]>/, '$1');
// Date型に変換
let pubDate = pubDateMatch ? pubDateMatch[1].trim() : '';
const date = new Date(pubDate);
pubDate = `${date.getFullYear()}/${(date.getMonth() + 1).toString().padStart(2, '0')}/${date.getDate().toString().padStart(2, '0')}`;
items.push({
title,
link: linkMatch ? linkMatch[1].trim() : '',
pubDate,
});
}
return items;
};