SvelteKit, Svelte के लिए आगामी पूर्ण-स्टैक एप्लिकेशन फ्रेमवर्क है, UI फ्रेमवर्क जो आपके ऐप को छोटे, तेज जावास्क्रिप्ट का उत्पादन करने के लिए संकलन समय पर बनाता है। जबकि SvelteKit आपको एंडपॉइंट का उपयोग करके सर्वर-साइड लॉजिक लिखने की अनुमति देता है, यह आप पर निर्भर है कि आप अपने एप्लिकेशन के डेटा को कैसे बनाए रखना चाहते हैं।
इस पोस्ट में, मैं दिखाऊंगा कि SvelteKit एप्लिकेशन में Redis का उपयोग करके डेटा को कैसे स्टोर किया जाए। मूवी डेटाबेस (TMDB) API के डेटा का उपयोग करके, हम मूवी API प्रतिक्रियाओं को कैश करने और एक यादृच्छिक मूवी प्रदर्शित करने के लिए Redis का उपयोग करेंगे।
डेमो के साथ पालन करने के लिए आपको या तो रेडिस कनेक्शन स्ट्रिंग की आवश्यकता होगी या रेडिस को स्थानीय रूप से चलाने की आवश्यकता होगी। यदि आपके पास पहले से कोई Redis उदाहरण नहीं है, तो मैं Upstash की अनुशंसा करता हूं। SvelteKit की तरह, यह सर्वर रहित अनुप्रयोगों के लिए अनुकूलित है और यदि आप बहुत अधिक अनुरोध नहीं कर रहे हैं तो यह मुफ़्त है (लिखने के समय कैप 10k/दिन है)। चाहे आपको अपना रेडिस इंस्टेंस कहीं भी मिले, आपको यह सुनिश्चित करना चाहिए कि यह विलंबता को कम करने के लिए आपके एप्लिकेशन को तैनात किए जाने के करीब स्थित है।
आवश्यकताएँ
- SvelteKit की बुनियादी जानकारी (उदाहरण के लिए पेज बनाम एंडपॉइंट, लोड हो रहा है, किसी दिए गए पेज के लिए क्वेरी और पैरामीटर्स प्राप्त करना)
- यदि आप डेमो चलाना या परिनियोजित करना चाहते हैं तो एक TMDB API कुंजी और Redis उदाहरण (उदा. Upstash पर)
स्टार्टर ओवरव्यू
स्टार्टर रेपो क्लोन करें। main
शाखा का अंतिम परिणाम है, इसलिए initial
. चेकआउट करें इस पोस्ट के साथ पालन करने के लिए शाखा। यदि आप अपने परिवर्तनों को आगे बढ़ाना चाहते हैं, तो पहले रेपो को फोर्क करें।
git clone https://github.com/geoffrich/movie-search-redis.git
cd movie-search-redis
git checkout initial
यह एक छोटा SvelteKit एप्लिकेशन है जो TMDB API का उपयोग करके फिल्मों की खोज करने और उनके विवरण देखने की अनुमति देता है। यह एपीआई प्रतिक्रियाओं के साथ बातचीत को आसान बनाने के लिए टाइपस्क्रिप्ट का उपयोग करता है, लेकिन यह Redis या SvelteKit का उपयोग करने की आवश्यकता नहीं है। निम्नलिखित मार्ग पहले से मौजूद हैं (src/routes
में फाइलों के अनुरूप ):
/
मुख पृष्ठ प्रस्तुत करता है/search
खोज परिणामों की एक सूची प्रस्तुत करता है। यहquery
takes लेता है औरpage
क्वेरी पैराम्स के रूप में, उदा।?query=star wars&page=3
"स्टार वार्स" के परिणामों का तीसरा पृष्ठ दिखाता है/search.json
एक सर्वर एंडपॉइंट है जो TMDB API से पूछताछ करता है और परिणामों की सूची देता है। यह वही क्वेरी पैरामीटर लेता है जैसे/search
/movie/[id]
दी गई आईडी वाली मूवी के लिए विवरण प्रस्तुत करता है, उदा./movie/11
/movie/[id].json
एक सर्वर एंडपॉइंट है जो TMDB API से मूवी विवरण देता है। चूंकि TMDB प्रतिक्रिया पृष्ठ पर हमारे द्वारा उपयोग किए जाने से अधिक डेटा लौटाती है, इसलिए हम डेटा के सबसेट को वापस करने के लिए प्रतिक्रिया को अनुकूलित करते हैं।
आप Netlify पर चल रहे डेमो को देख सकते हैं।
ध्यान दें कि TMDB API कॉल केवल सर्वर एंडपॉइंट में होती है। ऐसा इसलिए है कि हमारी एपीआई कुंजी क्लाइंट के सामने नहीं आती है।
डेमो को स्थानीय रूप से चलाने के लिए, एक .env
बनाएं प्रोजेक्ट की जड़ में फ़ाइल करें और अपनी TMDB API कुंजी और Redis कनेक्शन स्ट्रिंग (नीचे नमूना) जोड़ें। फिर npm install
run चलाएं निर्भरता स्थापित करने और चलाने के लिए npm run dev
ऐप चलाने के लिए।
TMDB_API_KEY=KEY_GOES_HERE
REDIS_CONNECTION=CONNECTION_GOES_HERE
रनटाइम पर, हम process.env['TMDB_API_KEY']
का उपयोग करके इन मानों तक पहुंच सकते हैं या process.env['REDIS_CONNECTION']
. मान .env
. से पढ़े जाते हैं hooks.ts
. में dotenv का उपयोग कर फ़ाइल ।
Redis में API प्रतिक्रिया को कैश करना
एक सुधार जो हम मौजूदा परियोजना में कर सकते हैं, वह है रेडिस में एक व्यक्तिगत फिल्म के लिए एपीआई प्रतिक्रिया को कैश करना। वर्तमान में, ऐप हर बार मूवी पेज लोड होने पर टीएमडीबी एपीआई से अनुरोध करता है। जब हम पहली बार अनुरोध करते हैं, तो हम एपीआई प्रतिक्रिया को रेडिस में संग्रहीत कर सकते हैं ताकि हमें टीएमडीबी से डेटा का अनुरोध करने की आवश्यकता न हो।
जबकि TMDB API तेज़ है और इसे कैश करने की आवश्यकता नहीं है, यह API के लिए एक उपयोगी तकनीक हो सकती है जो प्रतिक्रिया देने में कुछ समय लेती है या जिसकी अनुरोध सीमाएँ होती हैं। अगर एपीआई को नीचे जाना है तो यह लचीलापन का एक स्तर भी प्रदान करता है।
हमने पहले ही ioredis को एक निर्भरता के रूप में जोड़ा है। यह नोड के लिए एक रेडिस क्लाइंट है जो हमारे रेडिस डेटाबेस के साथ इंटरैक्ट करने में हमारी मदद करेगा।
फ़ाइल बनाएँ src/lib/redis.ts
. यह फ़ाइल रेडिस क्लाइंट को इनिशियलाइज़ करती है और इसे अन्य कार्यों द्वारा उपयोग के लिए निर्यात करती है। इसमें चाबियां प्राप्त करने के लिए कुछ सहायक कार्य भी शामिल हैं। फ़ाइल में नीचे दिया गया कोड जोड़ें।
import Redis from "ioredis";
const connectionString = process.env["REDIS_CONNECTION"];
export const MOVIE_IDS_KEY = "movie_ids";
/** Return the key used to store movie details for a given ID in Redis */
export function getMovieKey(id): string {
return `movie:${id}`;
}
export default connectionString ? new Redis(connectionString) : new Redis();
ध्यान दें कि यह कार्यान्वयन प्रति सर्वर रहित उदाहरण के लिए एक एकल रेडिस क्लाइंट बनाता है। एक अन्य विकल्प प्रति अनुरोध एक रेडिस कनेक्शन बनाना और बंद करना है। अपस्टैश में एक आरईएसटी एपीआई भी है जिसके लिए आपको रेडिस कनेक्शन शुरू करने की आवश्यकता नहीं है। सबसे अच्छा विकल्प आपके ऐप की विलंबता और मेमोरी आवश्यकताओं पर निर्भर करता है।
/src/routes/movie/[id].json.ts
पर जाएं फ़ाइल। Redis क्लाइंट आयात करें और getMovieKey
redis.ts
. से कार्य करता है ।
import redis, { getMovieKey } from "$lib/redis";
getMovieDetailsFromApi
. पर एक नज़र डालें समारोह। यह मूवी विवरण और क्रेडिट प्राप्त करने और उन्हें वापस करने के लिए TMDB API को कॉल करता है। डेटा वापस करने से पहले, हम इसे अपने रेडिस कैश में स्टोर करना चाहते हैं ताकि अगली बार हम एपीआई को कॉल करने के बजाय कैश्ड संस्करण को पुनः प्राप्त कर सकें। एक नया cacheMovieResponse
जोड़ें Redis में डेटा को कैश करने के लिए फ़ाइल में कार्य करता है।
async function cacheMovieResponse(id: number, movie, credits) {
try {
const cache: MovieDetails = {
movie,
credits,
};
// store movie response for 24 hours
await redis.set(getMovieKey(id), JSON.stringify(cache), "EX", 24 * 60 * 60);
} catch (e) {
console.log("Unable to cache", id, e);
}
}
प्रत्येक मूवी आईडी को एक अलग कुंजी के तहत संग्रहीत किया जाएगा। उदाहरण के लिए, अगर हम आईडी 11 के साथ मूवी के बारे में जानकारी प्राप्त कर रहे थे, तो कुंजी movie:11
होगी। . redis.set
के अंतिम दो तर्क कहते हैं कि हमें केवल 24 घंटे (86400 सेकंड) के लिए डेटा कैश करना चाहिए। हमें डेटा को हमेशा के लिए कैश नहीं करना चाहिए—यह उपयोग की शर्तों का उल्लंघन करता है, और डेटा अंततः पुराना हो जाएगा।
ध्यान दें कि कैश में स्टोर करने से पहले आपको JS ऑब्जेक्ट को स्ट्रिंग करना होगा। हम अपने समापन बिंदु को अधिक लचीला बनाने के लिए इस ऑपरेशन के दौरान फेंके गए किसी भी अपवाद को भी पकड़ते हैं। यदि हम डेटा को कैश नहीं कर सकते हैं, तो हमें अभी भी एक अप्रबंधित अपवाद को फेंकने के बजाय API से डेटा वापस करना चाहिए।
अब हम नए cacheMovieResponse
. का उपयोग कर सकते हैं getMovieDetailsFromApi
. के अंदर कार्य करें एपीआई प्रतिक्रिया को कैशे में स्टोर करने के लिए।
async function getMovieDetailsFromApi(id: number) {
const [movieResponse, creditsResponse] = await Promise.all([
getMovieDetails(id),
getCredits(id),
]);
if (movieResponse.ok) {
const movie = await movieResponse.json();
const credits = await creditsResponse.json();
// add this line
await cacheMovieResponse(id, movie, credits);
return {
movie,
credits,
};
}
return {
status: movieResponse.status,
};
}
अब हमने कैश में डेटा संग्रहीत कर लिया है, लेकिन हमें अभी भी कैश्ड डेटा को पुनः प्राप्त करने की आवश्यकता है। चलिए कैश से मूवी विवरण पढ़ने के लिए एक फ़ंक्शन जोड़ते हैं।
async function getMovieDetailsFromCache(
id: number
): Promise<MovieDetails | Record<string, never>> {
try {
const cached: string = await redis.get(getMovieKey(id));
if (cached) {
const parsed: MovieDetails = JSON.parse(cached);
console.log(`Found ${id} in cache`);
return parsed;
}
} catch (e) {
console.log("Unable to retrieve from cache", id, e);
}
return {};
}
चूंकि डेटा को एक स्ट्रिंग के रूप में संग्रहीत किया गया था, इसलिए हमें इसे प्रयोग करने योग्य बनाने के लिए इसे किसी ऑब्जेक्ट में पार्स करना होगा। पिछले फ़ंक्शन के समान, हम किसी भी अपवाद को लॉग करते हैं, लेकिन उन्हें कैशिंग फ़ंक्शन से बचने की अनुमति नहीं देते हैं। हम हमेशा एपीआई से डेटा पुनर्प्राप्त करने के लिए वापस आ सकते हैं।
अंत में, हम अपने कैशिंग फ़ंक्शन को मुख्य अनुरोध हैंडलर में कॉल कर सकते हैं। यदि हमें कैश में डेटा मिलता है, तो हम इसे तुरंत वापस कर देते हैं; अन्यथा, हम पहले की तरह एपीआई से पढ़ते हैं।
export const get: RequestHandler = async function ({ params }) {
const { id: rawId } = params;
// validate and sanitize the input
const id = parseInt(rawId);
if (isNaN(id)) {
return {
status: 400
};
}
// add these lines
const { movie, credits } = await getMovieDetailsFromCache(id);
if (movie && credits) {
return {
body: adaptResponse(movie, credits)
};
}
// fallback to the API
const result = await getMovieDetailsFromApi(id);
आप डेमो रेपो में इस समापन बिंदु के लिए अंतिम कोड देख सकते हैं।
इन परिवर्तनों के साथ, मूवी के पृष्ठ पर नेविगेट करने का प्रयास करें। जब आप पेज को रीफ्रेश करते हैं, तो आपको कंसोल लॉग में "फाउंड आईडी इन कैशे" दिखाई देना चाहिए, जो दर्शाता है कि हमने उस मूवी को कैशे से सफलतापूर्वक संग्रहीत और पुनर्प्राप्त किया है।
एक यादृच्छिक मूवी पुनर्प्राप्त करना
रेडिस केवल एपीआई प्रतिक्रियाओं को कैशिंग करने से ज्यादा कुछ नहीं कर सकता है। आइए देखें कि हम एक ऐसा मार्ग कैसे बना सकते हैं जो उपयोगकर्ता को एक यादृच्छिक फिल्म पर पुनर्निर्देशित करेगा।
यह 1 और 300000 के बीच एक यादृच्छिक संख्या चुनने और मूवी आईडी के रूप में उपयोग करने जितना आसान नहीं है। उस श्रेणी की प्रत्येक संख्या मूवी के अनुरूप नहीं होगी—उदाहरण के लिए, 1 या 1000 की आईडी वाली कोई फिल्म नहीं है। अधिकतम संभव आईडी क्या है, इसका ट्रैक रखना भी मुश्किल होगा, क्योंकि यह हमेशा बदलता रहेगा। नई फिल्में जोड़ी जाती हैं। इसके बजाय, हम दो चरणों वाली प्रक्रिया का उपयोग करके यादृच्छिक फिल्मों का चयन करेंगे:
- जब कोई खोज क्वेरी की जाती है, तो लौटाई गई सभी आईडी को एक रेडिस सेट में रखें।
- जब
/movie/random
मार्ग का अनुरोध किया जाता है, उस सेट के एक यादृच्छिक सदस्य को पुनः प्राप्त करें और संबंधित मूवी विवरण पृष्ठ पर रीडायरेक्ट करें।
लौटाई गई संभावित यादृच्छिक फिल्में छोटी शुरू होंगी, लेकिन जैसे-जैसे अधिक खोजें की जाएंगी, वे बड़ी होती जाएंगी।
रैंडम सेट को पॉप्युलेट करने के लिए, /src/routes/search.json.ts
को अपडेट करें निम्नलिखित के लिए।
import type { RequestHandler } from "@sveltejs/kit";
import type { SearchResponse } from "$lib/types/tmdb";
import redis, { MOVIE_IDS_KEY } from "$lib/redis";
const VOTE_THRESHOLD = 20;
export const get: RequestHandler = async function ({ query }) {
const searchQuery = query.get("query");
const page = query.get("page") ?? 1;
const response = await fetch(
`https://api.themoviedb.org/3/search/movie?api_key=${process.env["TMDB_API_KEY"]}&page=${page}&include_adult=false&query=${searchQuery}`
);
const parsed: SearchResponse = await response.json();
// add these lines
const filteredMovies = parsed.results.filter(
(movie) => movie.vote_count >= VOTE_THRESHOLD
);
if (filteredMovies.length > 0) {
try {
await redis.sadd(MOVIE_IDS_KEY, ...filteredMovies.map((r) => r.id));
} catch (e) {
console.log(e);
}
}
return {
body: parsed,
};
};
ध्यान दें कि हम हर को नहीं जोड़ रहे हैं फिल्म की सेट पर वापसी मैंने उन फिल्मों को फ़िल्टर करना चुना जिनमें अधिक वोट नहीं हैं, क्योंकि उन फिल्मों की उपयोगकर्ताओं द्वारा जांच किए जाने की संभावना कम होती है। आप VOTE_THRESHOLD
को एडजस्ट कर सकते हैं आपकी पसंद के अनुसार।
इस बदलाव के साथ, मूवी की खोज मूवी आईडी के सेट को पॉप्युलेट करना शुरू कर देगी। सेट में कुछ आईडी जोड़ने के लिए कुछ खोजें करें। उदाहरण के लिए:
- स्टार वार्स
- शेर राजा
- स्पाइडर मैन
कुछ खोज करने के बाद, आपके पास रेडिस में संग्रहीत यादृच्छिक आईडी का एक सेट होना चाहिए। आइए /movie/random
. के लिए मार्ग बनाएं समापन बिंदु और पृष्ठ।
src/routes/movie/random.json.ts
import type { RequestHandler } from "@sveltejs/kit";
import redis, { MOVIE_IDS_KEY } from "$lib/redis";
export const get: RequestHandler = async function () {
const randomId = await redis.srandmember(MOVIE_IDS_KEY);
return {
body: randomId,
};
};
यह सर्वर एंडपॉइंट मूवी आईडी सेट से रैंडम आईडी चुनने के लिए SRANDMEMBER का उपयोग करता है।
src/routes/movie/random.svelte
<script context="module" lang="ts">
import type { Load } from "@sveltejs/kit";
export const load: Load = async function ({ fetch }) {
const result = await fetch(`/movie/random.json`);
if (result.ok) {
const id = await result.json();
return {
redirect: `/movie/${id}`,
status: 303,
};
}
return {
status: result.status,
error: new Error("Could not retrieve random id"),
};
};
</script>
संबंधित Svelte पृष्ठ को केवल लोड फ़ंक्शन की आवश्यकता होती है क्योंकि यह किसी UI को प्रस्तुत नहीं करता है। यह सर्वर एंडपॉइंट को कॉल करता है जिसे हमने अभी जोड़ा है और संबंधित मूवी पेज पर रीडायरेक्ट करता है।
यही सब है इसके लिए! अब, https://localhost:3000/movie/random पर नेविगेट करें। आपके द्वारा की गई पिछली खोजों से आपको स्वचालित रूप से एक यादृच्छिक फिल्म पर पुनर्निर्देशित किया जाना चाहिए। इस मार्ग तक पहुंच को आसान बनाने के लिए, आप इसे /src/routes/__layout.svelte
में नेविगेशन में जोड़ सकते हैं
<header>
<nav>
<a href="/">Search</a>
<a href="/movie/random">Random</a>
</nav>
</header>
आप इसे लाइव डेमो में काम करते हुए देख सकते हैं।
रैपिंग अप
Redis का उपयोग करने के और भी कई तरीके हैं, लेकिन मुझे आशा है कि इस पोस्ट ने आपको SvelteKit ऐप में Redis को एकीकृत करने की मूल बातें अच्छी तरह समझ दी हैं। आप GitHub पर अंतिम कोड और Netlify पर लाइव डेमो देख सकते हैं।
कोई भी प्रश्न है? ट्विटर पर पहुंचें। आप मेरे ब्लॉग पर Svelte के बारे में मेरा अन्य लेखन भी पा सकते हैं।