Astro、Upstash、GitHub を使用して、無料のオープンソース LinkTree の代替を構築する
この投稿では、itsmy.fyi (LinkTree に代わるオープンソース) が Upstash、Astro、GitHuband Edgio を使用してどのように構築されるかについて説明します。 Upstash は、すべてのユーザーの (CRUD) データの管理に役立ち、CRUD 操作に対して GitHub API と比較して大幅なレート制限を提供し、きめ細かいレート制限を実装しました。

使用するもの
- Astro (フロントエンドおよびバックエンド)
- Upstash (レート制限と CRUD オペレーション)
- GitHub の問題と Webhook (ユーザー プロファイルを管理するためのパブリック CMS)
- Tailwind CSS (スタイリング)
- Edgio (展開)
必要なもの
- GitHub アカウント
- データベースを作成するための Upstash アカウント
Upstash Redis のセットアップ
Upstash アカウントを作成してログインしたら、[Redis] タブに移動してデータベースを作成します。


データベースを作成したら、[詳細] タブに移動します。 Connect your database が見つかるまで下にスクロールします。 セクション。コンテンツをコピーし、安全な場所に保存します。

また、REST API セクションが見つかるまで下にスクロールし、.env ボタンを選択します。コンテンツをコピーし、安全な場所に保存します。

プロジェクトのセットアップ
セットアップするには、アプリ リポジトリのクローンを作成し、このチュートリアルに従ってそこに含まれるすべての内容を学習します。プロジェクトをフォークするには、次のコマンドを実行します。
git clone https://github.com/rishi-raj-jain/itsmy.fyi
cd itsmy.fyi
yarn install リポジトリのクローンを作成したら、.env ファイルを作成します。上記のセクションで保存したアイテムを追加します。
次のようになります:
.env# Obtained from your GitHub repo
GITHUB_API_TOKEN="to_create_and_update_github_comments"
GITHUB_WEBHOOK_SECRET="if_you_are_matching_github_webhooks_sha256"
# Obtained from the steps as above
UPSTASH_DB="your_upstash_redis_from_above"
UPSTASH_REDIS_REST_URL="your_upstash_redis_rest__url_from_above"
UPSTASH_REDIS_REST_TOKEN="your_upstash_redis_rest__token_from_above" これらの手順を完了すると、次のコマンドを使用してローカル環境を起動できるようになります。
yarn run edgio:dev リポジトリの構造
これはプロジェクトのメイン フォルダー構造です。 CRUD 操作、レート制限、およびそれらが参照されるファイルについては、この投稿でさらに説明するファイルを赤で囲みました。

高レベルのデータ フロー
これは、データがどのように流れるかを示す概要図です。
- ユーザーが itsmy.fyi/me/slug にアクセスし、このページへの応答がキャッシュされていない (または再検証中である) 場合、getUserInfo 関数が呼び出され、Upstash DB からユーザーの json が取得されます
- ユーザーが GitHub Issue を作成、更新、または削除すると、GitHub はエンドポイントに POST する Webhook をトリガーします。そのエンドポイントでは、最初に Upstash レート制限を使用して、要求された変更を行うことができるかどうかを評価し、次に Upstash を使用してユーザー json が作成、更新、または削除されます。

Upstash Redis を介したユーザー プロファイルの CRUD 操作
このセクションでは、ユーザー プロファイルのデータの取得、更新、削除がどのように行われるかについて詳しく説明します。私たちは常に Upstash を使用しています (ioredis 経由) ) データを取得して表示します。
CRUD オペレーションのために GitHub から Upstash に移行したのはなぜですか?
データ管理のソースとして GitHub を使用し始めましたが、データ フォームから Github Issues、GitHub Webhook、リポジトリ内の CRUD ユーザー JSON まで、GitHub REST API の制限は次のとおりです:1,000 requests per hour per repository プラットフォームの意図された使用法を制限し、むしろ後退させているように見えました。
Upstash は、最初は無料プランで毎日 10,000 個のコマンドを提供し、その後、使用量が拡大するにつれて非常に最小限の料金を提供してくれたので、はるかに優れていました。この種のアプローチにより、ほぼ無料に近いコストでより多くのユーザーを獲得でき、データベースのスケーリングや管理コストを気にせずに反復処理を高速化することができました。
getUserInfo:ユーザー プロファイル関数の取得
getUserInfo 関数はioredisのhgetを使用します slug をキーとして使用し、一意の slug で識別される、関連するユーザー プロフィール ページの Upstash への API リクエストを作成します。 そのユーザー プロファイルが存在しない (またはエラーがある) 場合、関数は { code: 0 } を持つオブジェクトを返すように設定されます。 これにより、ユーザーは Astro の動的ルートで自動的に 404 にリダイレクトされます。
// File: lib/Upstash/users/get.js
// Read User Profile Code
import redis from "../setup";
export async function getUserInfo(slug) {
try {
const userData = await redis.hget("profiles", slug);
const parsedData = JSON.parse(userData);
if (parsedData.slug === slug) {
return { ...parsedData, code: 1 };
}
return {
code: 0,
error: `slug doesn't match for the user.`,
};
} catch (e) {
const error = e.message || e.toString();
console.log(error);
return {
code: 0,
error,
};
}
} 同様に、残りの CRUD 操作は次のとおりです。
import redis from "../setup";
// File: @/lib/Upstash/users/delete.js
// Delete User Profile Code
export async function deleteUserInfo(slug) {
try {
await redis.hdel("profiles", slug);
return { code: 1 };
} catch (e) {
console.log(e.message || e.toString());
return {
code: 0,
};
}
}
// File: @/lib/Upstash/users/post.js
// Create/Update User Profile Code
export async function postUserInfo(data) {
try {
await redis.hset("profiles", data.slug, JSON.stringify(data));
return { code: 1 };
} catch (e) {
const error = e.message || e.toString();
console.log(error);
return {
code: 0,
error,
};
}
} レート制限
Edgio を使用してサーバーレス環境にレート制限を実装するには、Upstash Redis データベース クライアントと @upstash/ratelimit というレート リミッター ライブラリを使用します。 .
// Reference Function to ratelimiting
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import { getENV } from "@/lib/env";
const url = getENV("UPSTASH_REDIS_REST_URL");
const token = getENV("UPSTASH_REDIS_REST_TOKEN");
export const ratelimit = (number, time) => {
if (url && token) {
return new Ratelimit({
redis: new Redis({
url,
token,
}),
limiter: Ratelimit.fixedWindow(number, time),
});
}
return;
}; レート制限を使用すると、次のことを達成できました。
A.サービスを利用しましょう - 完全に無料かつ無制限
レート制限を使用することで、プロファイル作成 API を公開することができます。これにより、GUI を介したプロファイルのセットアップの容易さなど、システムの利点を紹介することができました。文字通り、誰でも Web サイト (itsmy.fyi) 自体を介して 1 週間に 3 つのプロファイルを作成でき、プロファイルの編集や無制限のプロファイルの作成などの機能に無制限にアクセスするには、ユーザーは GitHub のプロファイル作成方法に切り替える必要があります。1 週間に 3 つのプロファイルのレート制限を強制することができます。 IP アドレスをキーとして使用します。
// Rate limit 3 profiles in a week via the web for a user
const ratelimitUser = ratelimit(3, 7 * 24 * 60 * 60 + " s");
if (rateLimiter) {
// Look at the x-0-client-ip set by Edgio in serverless
const result = await rateLimiter.limit("x-0-client-ip");
limit = result.limit;
remaining = result.remaining;
if (!result.success) {
// Return a message
}
} B.ユーザーによる編集回数に対するきめ細かなモデレーションを実装します
また、レート制限により、GitHub ユーザー名に基づいてユーザーが 1 分間に行う編集の数を調整できます。現時点では、1 分間に最大 3 件の変更を加えることが許可されています。これにより、目に見えないスパムを減らすことができます。
@/pages/github/hook/issue.jsconst rateLimiter = ratelimit(3, "60 s");
if (rateLimiter) {
const result = await rateLimiter.limit(context.sender.login);
limit = result.limit;
remaining = result.remaining;
if (!result.success) {
return {
headers: {
"X-RateLimit-Limit": limit,
"X-RateLimit-Remaining": remaining,
},
body: JSON.stringify({
message:
"Too many updates in 1 minute. Please try again in a few minutes.",
}),
};
}
} すべてのユーザー プロファイルのエッジで stale-while-revalidate を実装する
次のコードは、Stale While Revalidate の概念を使用してキャッシュ ヒット率を向上させる方法を説明しています。コード内 (routes.js 内) )、router.match 関数は、すべてのユーザー プロファイル (/me/ で始まるもの) と一致するために使用されます。 )。キャッシュ メソッド内では、ブラウザーでのページのキャッシュを防止し、常に最新のコンテンツを高速にユーザーに提供するためにエッジ キャッシュのみを有効にします。エッジ オプションは maxAgeSeconds: 1 に設定されています。 データが 1 秒間だけキャッシュされるようにします。staleWhileRevalidateSeconds オプションは、キャッシュが更新されている間にキャッシュから直接データを提供できるように、年に設定されます。
// User path(s)
router.match("/me/:path", ({ cache, removeUpstreamResponseHeader }) => {
// Remove the cache-control header from Astro's standalone server
removeUpstreamResponseHeader("cache-control");
// Disable in browser caching, and use Edgio's edge to use SWR
cache({
edge: {
maxAgeSeconds: 1,
staleWhileRevalidateSeconds: 60 * 60 * 24 * 365,
},
browser: false,
});
}); Stale While Revalidate を使用すると、サーバーの負荷が軽減され、ユーザーへの応答が速くなり、アプリのパフォーマンスが向上します。
動的ユーザー プロファイルをその場で作成する
Astro を使用すると、動的ルートを非常に簡単に設定できます。アプリには src/pages/me/[slug].astro があります。 、 /me/ で始まるページをマップします。 例には /me/rishi-raj-jain が含まれます と /me/some-other-user .
ユーザー プロファイルの取得
slug を使用して、現在のユーザーのデータを取得します。 Astro パラメータからクエリ パラメータを抽出し、getUserInfo 関数 (前述のとおり) を呼び出して、関連するすべてのユーザー データを取得します。見つからない場合、またはエラーが発生した場合は、訪問者を 404 にリダイレクトします。
import { getUserInfo } from "@/lib/Upstash/users";
// Extract slug query
const { slug } = Astro.params;
// Get data from Upstash using the getUserInfo function
const {
name: userName,
image: userImage,
links = [],
socials = [],
about = "",
og = {},
background = {},
code = 1,
} = await getUserInfo(userSlug);
// In case the code: 0 is recevied, redirect to a 404
if (code === 0) {
return Astro.redirect("/404");
} CLI からデプロイ
以下を使用して、アプリの実稼働ビルドを実行し、ローカルでテストできます。
yarn run edgio:build && yarn run edgio:production 導入にはEdgioのアカウントが必要です。ここから無料でサインアップしてください。アカウントを取得したら、プロジェクトのルート フォルダーで次のコマンドを実行して、Edgio にデプロイできます。
yarn run edgio:deploy これで展開は完了です。はい、それだけです。
結論
結論として、このプロジェクトは、きめ細かなレート制限の実装、サーバーレスでの CRUD データ操作、GitHub の問題を CMS として使用すること、そしてニーズに合わせて拡張するサービス (つまり Upstash) を使用して MVP を出荷するというより適切な決定を下すことにおいて貴重な経験を提供しました。
-
Envflow の構築:Laravel および Upstash Redis と環境変数を安全に共有する
私は最近、Nuno Maduro のプロジェクト Pyre にインスピレーションを受けています。これは、必要な人に短期間の秘密メッセージを送信できる Web アプリです。これらのメッセージは保存時に暗号化されており、あなたまたは復号化リンクを共有した人だけがメッセージを読むことができます。 私は Upstash Redis で同様のものを構築したかったので、環境変数の共有というニッチな分野を選択しました。きっと、ある時点でチームメイトと秘密を共有する必要があり、それを安全に行うことができるシステムを構築する方法を疑問に思ったことがあると思います。 Envflow を紹介します。これは私が構
-
Redis PUNSUBSCRIBE – redis pub/subの複数のパターンから退会する方法
このチュートリアルでは、redis-cliを使用してredisメッセージブローカーシステムの複数のパターンからサブスクライブを解除する方法について学習します。 PUNSUBSCRIBEコマンド PUNSUBSCRIBEコマンドは、redisメッセージブローカーシステムで指定された1つ以上のパターンからクライアントのサブスクライブを解除するために使用されます。パターンが指定されていない場合、クライアントはすべてのサブスクライブされたパターンからサブスクライブ解除されます。サブスクライブされていないパターンごとにメッセージを返します。 redis PUNSUBSCRIBEコマンドの構文は次の