रियाक्ट सर्व्हर ॲक्शन व्हॅलिडेशनमध्ये प्राविण्य मिळवा. Zod, useFormState आणि useFormStatus वापरून फॉर्म प्रोसेसिंग, सुरक्षा सर्वोत्तम पद्धती आणि प्रगत तंत्रांचा सखोल अभ्यास.
रियाक्ट सर्व्हर ॲक्शन व्हॅलिडेशन: फॉर्म इनपुट प्रोसेसिंग आणि सुरक्षिततेसाठी एक सर्वसमावेशक मार्गदर्शक
Next.js सारख्या फ्रेमवर्कसह फुल-स्टॅक डेव्हलपमेंटमध्ये रियाक्ट सर्व्हर ॲक्शन्सच्या आगमनाने एक महत्त्वपूर्ण बदल झाला आहे. क्लायंट कंपोनेंट्सना थेट सर्व्हर-साइड फंक्शन्सना कॉल करण्याची परवानगी देऊन, आपण आता कमी बॉइलरप्लेटसह अधिक सुसंगत, कार्यक्षम आणि इंटरॅक्टिव्ह ॲप्लिकेशन्स तयार करू शकतो. तथापि, हे शक्तिशाली नवीन ॲबस्ट्रॅक्शन एक महत्त्वपूर्ण जबाबदारी समोर आणते: मजबूत इनपुट व्हॅलिडेशन आणि सुरक्षा.
जेव्हा क्लायंट आणि सर्व्हरमधील सीमा इतकी अखंड होते, तेव्हा वेब सुरक्षिततेच्या मूलभूत तत्त्वांकडे दुर्लक्ष करणे सोपे होते. वापरकर्त्याकडून येणारे कोणतेही इनपुट अविश्वसनीय असते आणि सर्व्हरवर त्याची कठोरपणे पडताळणी करणे आवश्यक आहे. हे मार्गदर्शक रियाक्ट सर्व्हर ॲक्शन्समध्ये फॉर्म इनपुट प्रोसेसिंग आणि व्हॅलिडेशनचे सर्वसमावेशक अन्वेषण प्रदान करते, ज्यात मूलभूत तत्त्वांपासून ते प्रगत, उत्पादन-तयार पॅटर्नपर्यंत सर्व काही समाविष्ट आहे जे आपले ॲप्लिकेशन वापरकर्ता-अनुकूल आणि सुरक्षित दोन्ही असल्याची खात्री करतात.
रियाक्ट सर्व्हर ॲक्शन्स नेमके काय आहेत?
व्हॅलिडेशनमध्ये जाण्यापूर्वी, सर्व्हर ॲक्शन्स काय आहेत याचा थोडक्यात आढावा घेऊया. थोडक्यात, हे असे फंक्शन्स आहेत जे आपण सर्व्हरवर परिभाषित करता परंतु क्लायंटवरून कार्यान्वित करू शकता. जेव्हा एखादा वापरकर्ता फॉर्म सबमिट करतो किंवा बटणावर क्लिक करतो, तेव्हा सर्व्हर ॲक्शनला थेट कॉल केला जाऊ शकतो, ज्यामुळे मॅन्युअली API एंडपॉइंट्स तयार करणे, `fetch` विनंत्या हाताळणे आणि लोडिंग/एरर स्टेट्स व्यवस्थापित करण्याची गरज नाहीशी होते.
ते HTML फॉर्म्स आणि वेब प्लॅटफॉर्मच्या `FormData` API च्या पायावर तयार केले आहेत, ज्यामुळे ते डीफॉल्टनुसार प्रगतीशीलपणे सुधारित होतात. याचा अर्थ असा की JavaScript लोड होण्यात अयशस्वी झाल्यासही आपले फॉर्म कार्य करतील, ज्यामुळे एक लवचिक वापरकर्ता अनुभव मिळतो.
एका साध्या सर्व्हर ॲक्शनचे उदाहरण:
// app/actions.js
'use server';
export async function createUser(formData) {
const name = formData.get('name');
const email = formData.get('email');
// ... logic to save user to the database
console.log('Creating user:', { name, email });
}
// app/page.js
import { createUser } from './actions';
export default function UserForm() {
return (
<form action={createUser}>
<input type="text" name="name" placeholder="Name" />
<input type="email" name="email" placeholder="Email" />
<button type="submit">Create User</button>
</form>
);
}
ही साधेपणा शक्तिशाली आहे, परंतु ती काय घडत आहे याची गुंतागुंत देखील लपवते. `createUser` फंक्शन केवळ सर्व्हरवर चालत आहे, तरीही ते क्लायंट कंपोनेंटमधून कॉल केले जात आहे. आपल्या सर्व्हर लॉजिकची ही थेट लाइनच आहे ज्यामुळे व्हॅलिडेशन केवळ एक वैशिष्ट्य नाही - ती एक आवश्यकता आहे.
व्हॅलिडेशनचे अढळ महत्त्व
सर्व्हर ॲक्शन्सच्या जगात, प्रत्येक फंक्शन तुमच्या सर्व्हरसाठी एक खुले गेट आहे. योग्य व्हॅलिडेशन त्या गेटवर रक्षकाचे काम करते. ते अविभाज्य का आहे ते येथे दिले आहे:
- डेटाची अखंडता: आपला डेटाबेस आणि ॲप्लिकेशनची स्थिती स्वच्छ, अंदाजित डेटावर अवलंबून असते. व्हॅलिडेशन हे सुनिश्चित करते की आपण चुकीच्या स्वरूपातील ईमेल पत्ते, नावांच्या जागी रिकाम्या स्ट्रिंग्ज, किंवा संख्यांसाठी असलेल्या फील्डमध्ये मजकूर साठवत नाही.
- सुधारित वापरकर्ता अनुभव (UX): वापरकर्ते चुका करतात. स्पष्ट, त्वरित आणि संदर्भ-विशिष्ट त्रुटी संदेश त्यांना त्यांचे इनपुट दुरुस्त करण्यासाठी मार्गदर्शन करतात, ज्यामुळे निराशा कमी होते आणि फॉर्म पूर्ण करण्याचे दर सुधारतात.
- लोहखनिज सुरक्षा: हा सर्वात महत्त्वाचा पैलू आहे. सर्व्हर-साइड व्हॅलिडेशनशिवाय, आपले ॲप्लिकेशन अनेक हल्ल्यांसाठी असुरक्षित आहे, यासह:
- SQL इंजेक्शन: एक दुर्भावनापूर्ण अभिनेता आपल्या डेटाबेसमध्ये फेरफार करण्यासाठी फॉर्म फील्डमध्ये SQL कमांड सबमिट करू शकतो.
- क्रॉस-साइट स्क्रिप्टिंग (XSS): आपण असंशोधित वापरकर्ता इनपुट साठवून रेंडर केल्यास, एक हल्लेखोर दुर्भावनापूर्ण स्क्रिप्ट्स इंजेक्ट करू शकतो जे इतर वापरकर्त्यांच्या ब्राउझरमध्ये कार्यान्वित होतात.
- डिनायल ऑफ सर्व्हिस (DoS): अनपेक्षितपणे मोठा किंवा संगणकीयदृष्ट्या महाग डेटा सबमिट केल्याने आपल्या सर्व्हर संसाधनांवर भार येऊ शकतो.
क्लायंट-साइड वि. सर्व्हर-साइड व्हॅलिडेशन: एक आवश्यक भागीदारी
हे समजणे महत्त्वाचे आहे की व्हॅलिडेशन दोन ठिकाणी व्हायला हवे:
- क्लायंट-साइड व्हॅलिडेशन: हे UX साठी आहे. हे नेटवर्क राऊंड-ट्रिपशिवाय त्वरित अभिप्राय प्रदान करते. आपण `required`, `minLength`, `pattern` सारख्या साध्या HTML5 विशेषता किंवा वापरकर्ता टाइप करत असताना स्वरूप तपासण्यासाठी JavaScript वापरू शकता. तथापि, JavaScript अक्षम करून किंवा डेव्हलपर टूल्स वापरून हे सहजपणे बायपास केले जाऊ शकते.
- सर्व्हर-साइड व्हॅलिडेशन: हे सुरक्षा आणि डेटा अखंडतेसाठी आहे. हे आपल्या ॲप्लिकेशनच्या सत्याचा अंतिम स्त्रोत आहे. क्लायंटवर काहीही झाले तरी, सर्व्हरला मिळालेल्या प्रत्येक गोष्टीची पुन्हा पडताळणी करणे आवश्यक आहे. सर्व्हर ॲक्शन्स हे लॉजिक लागू करण्यासाठी योग्य ठिकाण आहे.
मुख्य नियम: वापरकर्त्याच्या चांगल्या अनुभवासाठी क्लायंट-साइड व्हॅलिडेशन वापरा, परंतु नेहमी फक्त सर्व्हर-साइड व्हॅलिडेशनवर सुरक्षिततेसाठी विश्वास ठेवा.
सर्व्हर ॲक्शन्समध्ये व्हॅलिडेशनची अंमलबजावणी: साध्यापासून प्रगतपर्यंत
चला आपली व्हॅलिडेशन रणनीती तयार करूया, एका सोप्या दृष्टिकोनापासून सुरुवात करून आधुनिक साधनांचा वापर करून अधिक मजबूत, स्केलेबल सोल्यूशनकडे जाऊया.
दृष्टिकोन १: मॅन्युअल व्हॅलिडेशन आणि स्टेट परत करणे
व्हॅलिडेशन हाताळण्याचा सर्वात सोपा मार्ग म्हणजे तुमच्या सर्व्हर ॲक्शनमध्ये `if` स्टेटमेंट्स जोडणे आणि यश किंवा अपयश दर्शवणारे ऑब्जेक्ट परत करणे.
// app/actions.js
'use server';
import { redirect } from 'next/navigation';
export async function createInvoice(formData) {
const customerName = formData.get('customerName');
const amount = formData.get('amount');
if (!customerName || customerName.trim() === '') {
return { success: false, message: 'Customer name is required.' };
}
if (!amount || isNaN(Number(amount)) || Number(amount) <= 0) {
return { success: false, message: 'Please enter a valid amount greater than zero.' };
}
// ... logic to create the invoice in the database
console.log('Invoice created for', customerName, 'with amount', amount);
redirect('/dashboard/invoices');
}
हा दृष्टिकोन कार्य करतो, परंतु त्यात एक मोठी UX त्रुटी आहे: त्रुटी संदेश दर्शविण्यासाठी पूर्ण पृष्ठ रीलोड आवश्यक आहे. आम्ही फॉर्म पृष्ठावरच संदेश सहजपणे दर्शवू शकत नाही. इथेच रियाक्टचे सर्व्हर ॲक्शन्ससाठीचे हुक्स कामाला येतात.
दृष्टिकोन २: अखंड त्रुटी हाताळणीसाठी `useFormState` वापरणे
`useFormState` हुक विशेषतः याच उद्देशासाठी डिझाइन केले आहे. हे सर्व्हर ॲक्शनला अशी स्थिती परत करण्याची परवानगी देते जी पूर्ण नेव्हिगेशन इव्हेंटशिवाय UI अपडेट करण्यासाठी वापरली जाऊ शकते. हे सर्व्हर ॲक्शन्ससह आधुनिक फॉर्म हाताळणीचा आधारस्तंभ आहे.
चला आपला इनव्हॉइस तयार करण्याचा फॉर्म रिफॅक्टर करूया.
पायरी १: सर्व्हर ॲक्शन अपडेट करा
ॲक्शनला आता दोन युक्तिवाद स्वीकारण्याची आवश्यकता आहे: `prevState` आणि `formData`. त्याने एक नवीन स्टेट ऑब्जेक्ट परत केले पाहिजे जे `useFormState` कंपोनेंट अपडेट करण्यासाठी वापरेल.
// app/actions.js
'use server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
// Define the initial state shape
const initialState = {
message: null,
errors: {},
};
export async function createInvoice(prevState, formData) {
const customerName = formData.get('customerName');
const amount = formData.get('amount');
const status = formData.get('status');
const errors = {};
if (!customerName || customerName.trim().length < 2) {
errors.customerName = 'Customer name must be at least 2 characters.';
}
if (!amount || isNaN(Number(amount)) || Number(amount) <= 0) {
errors.amount = 'Please enter a valid amount.';
}
if (status !== 'pending' && status !== 'paid') {
errors.status = 'Please select a valid status.';
}
if (Object.keys(errors).length > 0) {
return {
message: 'Failed to create invoice. Please check the fields.',
errors,
};
}
try {
// ... logic to save to database
console.log('Invoice created successfully!');
} catch (e) {
return {
message: 'Database Error: Failed to create invoice.',
errors: {},
};
}
// Revalidate the cache for the invoices page and redirect
revalidatePath('/dashboard/invoices');
redirect('/dashboard/invoices');
}
पायरी २: `useFormState` सह फॉर्म कंपोनेंट अपडेट करा
आमच्या क्लायंट कंपोनेंटमध्ये, आम्ही फॉर्मची स्थिती व्यवस्थापित करण्यासाठी आणि त्रुटी प्रदर्शित करण्यासाठी हुक वापरू.
// app/ui/invoices/create-form.js
'use client';
import { useFormState } from 'react-dom';
import { createInvoice } from '@/app/actions';
const initialState = {
message: null,
errors: {},
};
export function CreateInvoiceForm() {
const [state, dispatch] = useFormState(createInvoice, initialState);
return (
<form action={dispatch}>
<div>
<label htmlFor="customerName">Customer Name</label>
<input id="customerName" name="customerName" type="text" />
{state.errors?.customerName &&
<p style={{ color: 'red' }}>{state.errors.customerName}</p>}
</div>
<div>
<label htmlFor="amount">Amount</label>
<input id="amount" name="amount" type="number" step="0.01" />
{state.errors?.amount &&
<p style={{ color: 'red' }}>{state.errors.amount}</p>}
</div>
{/* ... other fields ... */}
{state.message && <p style={{ color: 'red' }}>{state.message}</p>}
<button type="submit">Create Invoice</button>
</form>
);
}
आता, जेव्हा वापरकर्ता अवैध फॉर्म सबमिट करतो, तेव्हा सर्व्हर ॲक्शन चालते, त्रुटी ऑब्जेक्ट परत करते आणि `useFormState` हे `state` व्हेरिएबल अपडेट करते. कंपोनेंट पुन्हा रेंडर होतो, संबंधित फील्डच्या पुढे विशिष्ट त्रुटी संदेश प्रदर्शित करतो—हे सर्व पृष्ठ रीलोड न करता. हा एक मोठा UX सुधारणा आहे!
दृष्टिकोन ३: `useFormStatus` सह UX सुधारणे
सर्व्हर ॲक्शन चालू असताना काय होते? वापरकर्ता सबमिट बटण अनेक वेळा क्लिक करू शकतो. आम्ही `useFormStatus` हुक वापरून अभिप्राय देऊ शकतो, जे आम्हाला शेवटच्या फॉर्म सबमिशनच्या स्थितीबद्दल माहिती देते.
महत्त्वाचे: `useFormStatus` चा वापर `<form>` घटकाचा चाइल्ड असलेल्या कंपोनेंटमध्ये करणे आवश्यक आहे.
// app/ui/submit-button.js
'use client';
import { useFormStatus } from 'react-dom';
export function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" aria-disabled={pending} disabled={pending}>
{pending ? 'Creating...' : 'Create Invoice'}
</button>
);
}
// In your CreateInvoiceForm component:
import { SubmitButton } from './submit-button';
// ...
<form action={dispatch}>
{/* ... form fields ... */}
<SubmitButton />
</form>
या सोप्या जोडणीमुळे, सर्व्हर विनंतीवर प्रक्रिया करत असताना सबमिट बटण आता अक्षम केले जाईल आणि 'Creating...' दर्शवेल, ज्यामुळे डुप्लिकेट सबमिशन टाळता येईल आणि वापरकर्त्याला स्पष्ट अभिप्राय मिळेल.
दृष्टिकोन ४: Zod सह प्रोडक्शन-ग्रेड व्हॅलिडेशन
साध्या फॉर्मसाठी मॅन्युअल `if` तपासणी ठीक आहे, परंतु जटिल ॲप्लिकेशन्ससाठी ते शब्दबंबाळ, त्रुटी-प्रवण आणि देखरेखीसाठी कठीण बनतात. इथेच Zod, Yup, किंवा Valibot सारख्या स्कीमा व्हॅलिडेशन लायब्ररी चमकतात.
Zod ही TypeScript-प्रथम स्कीमा घोषणा आणि व्हॅलिडेशन लायब्ररी आहे. हे आपल्याला आपल्या डेटासाठी एकच स्कीमा परिभाषित करण्याची परवानगी देते जी सर्व्हर आणि क्लायंट दोन्हीवर वापरली जाऊ शकते, ज्यामुळे सुसंगतता आणि प्रकार सुरक्षितता सुनिश्चित होते.
पायरी १: Zod स्कीमा परिभाषित करा
चला आपल्या इनव्हॉइस फॉर्मसाठी एक स्कीमा परिभाषित करूया. हे वैध इनव्हॉइस काय आहे यासाठी सत्याचा एकमेव स्त्रोत बनते.
// app/lib/schemas.js
import { z } from 'zod';
export const InvoiceSchema = z.object({
id: z.string(), // We'll have this for updates, but not creation
customerId: z.string({ invalid_type_error: 'Please select a customer.' }),
amount: z.coerce
.number()
.gt(0, { message: 'Please enter an amount greater than $0.' }),
status: z.enum(['pending', 'paid'], {
invalid_type_error: 'Please select an invoice status.',
}),
date: z.string(),
});
export const CreateInvoice = InvoiceSchema.omit({ id: true, date: true });
पायरी २: तुमच्या सर्व्हर ॲक्शनमध्ये स्कीमा वापरा
आता, आपण आपल्या सर्व मॅन्युअल तपासण्या आमच्या Zod स्कीमाच्या एकाच कॉलने बदलू शकतो. Zod ची `safeParse` पद्धत एकतर प्रमाणित डेटा किंवा तपशीलवार त्रुटी ऑब्जेक्ट परत करेल.
// app/actions.js
'use server';
import { z } from 'zod';
import { CreateInvoice } from '@/app/lib/schemas';
export async function createInvoiceWithZod(prevState, formData) {
// 1. Validate form fields using Zod
const validatedFields = CreateInvoice.safeParse({
customerId: formData.get('customerId'),
amount: formData.get('amount'),
status: formData.get('status'),
});
// 2. If validation fails, return errors early.
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
message: 'Missing Fields. Failed to Create Invoice.',
};
}
// 3. Prepare data for insertion into the database
const { customerId, amount, status } = validatedFields.data;
const amountInCents = amount * 100;
const date = new Date().toISOString().split('T')[0];
// 4. Insert data into the database
try {
// await sql`...` your database query here
console.log('Successfully created invoice with validated data.');
} catch (error) {
return {
message: 'Database Error: Failed to Create Invoice.',
};
}
// 5. Revalidate and redirect
revalidatePath('/dashboard/invoices');
redirect('/dashboard/invoices');
}
हे किती स्वच्छ आहे ते लक्षात घ्या. व्हॅलिडेशन लॉजिक घोषणात्मक आहे आणि आमच्या स्कीमा फाइलमध्ये एकत्रित आहे. ॲक्शनची जबाबदारी आता व्हॅलिडेशन, डेटा प्रोसेसिंग आणि डेटाबेस इंटरॅक्शनचे आयोजन करणे आहे. Zod मधील `flatten().fieldErrors` पद्धत एक उत्तम प्रकारे संरचित ऑब्जेक्ट प्रदान करते जे फील्ड नावांना त्रुटी संदेशांच्या ॲरेमध्ये मॅप करते, जे आमच्या फॉर्म कंपोनेंटला नेमके हवे असते.
सर्व्हर ॲक्शन्ससाठी महत्त्वपूर्ण सुरक्षा सर्वोत्तम पद्धती
व्हॅलिडेशन लायब्ररी वापरणे हे एक मोठे पाऊल आहे, परंतु खऱ्या सुरक्षिततेसाठी बहुस्तरीय दृष्टिकोन आवश्यक आहे. प्रत्येक सर्व्हर ॲक्शन हा एक संभाव्य हल्ला वेक्टर आहे.
१. नेहमी दुर्भावनापूर्ण हेतू गृहीत धरा
वापरकर्त्याच्या इनपुटवर कधीही, कधीही विश्वास ठेवू नका. हा सुवर्ण नियम आहे. जरी तुमचा क्लायंट-साइड कोड परिपूर्ण डेटा पाठवत असला तरी, एक हल्लेखोर `curl` किंवा Postman सारख्या साधनांचा वापर करून थेट तुमच्या सर्व्हर ॲक्शन एंडपॉइंटला हस्तनिर्मित विनंती पाठवू शकतो. तुमचे सर्व्हर-साइड लॉजिक हे तुमचे एकमेव विश्वसनीय संरक्षण आहे.
- सर्वकाही प्रमाणित करा: केवळ स्वरूपाचेच नव्हे, तर व्यवसायिक तर्काचेही व्हॅलिडेशन करा. या वापरकर्त्याला *या* ग्राहकासाठी इनव्हॉइस तयार करण्याची परवानगी आहे का? रक्कम वाजवी मर्यादेत आहे का?
- आउटपुटसाठी सॅनिटाइज करा: रियाक्ट रेंडरिंग करताना XSS टाळण्यासाठी डेटा आपोआप एस्केप करत असले तरी, तुम्ही इतर संदर्भांमध्ये डेटा वापरत असाल (उदा. ईमेल तयार करणे, लॉगिंग करणे), तर त्या सिस्टीममध्ये स्क्रिप्ट इंजेक्शन टाळण्यासाठी तो सॅनिटाइज करण्याची काळजी घ्या.
२. प्रमाणीकरण आणि अधिकृतता अनिवार्य आहेत
प्रत्येक सर्व्हर ॲक्शन जी म्युटेशन (तयार करणे, अपडेट करणे, हटवणे) करते किंवा संरक्षित डेटा ॲक्सेस करते, तिने वापरकर्त्याची ओळख आणि परवानग्या सत्यापित केल्या पाहिजेत.
आपली ॲक्शन नेहमी सेशन तपासणीने सुरू करा:
// app/actions.js
'use server';
import { auth } from '@/auth'; // Assuming you use NextAuth.js or similar
import { sql } from '@vercel/postgres';
export async function deleteInvoice(id) {
const session = await auth();
if (!session?.user) {
// Or throw an error
return { message: 'Authentication required.' };
}
// Authorization check: Does this user have permission to delete?
// This could involve checking roles or ownership.
const userRole = session.user.role;
if (userRole !== 'admin') {
return { message: 'Unauthorized action.' };
}
try {
await sql`DELETE FROM invoices WHERE id = ${id}`;
revalidatePath('/dashboard/invoices');
return { message: 'Deleted Invoice.' };
} catch (error) {
return { message: 'Database Error: Failed to Delete Invoice.' };
}
}
३. CSRF (क्रॉस-साइट रिक्वेस्ट फोर्जरी) विरुद्ध संरक्षण
CSRF हल्ले लॉग-इन केलेल्या वापरकर्त्याला नकळतपणे आपल्या ॲप्लिकेशनला दुर्भावनापूर्ण विनंती सादर करण्यासाठी फसवतात. सुदैवाने, Next.js सारख्या फ्रेमवर्कमध्ये सर्व्हर ॲक्शन्ससाठी डबल-सबमिट कुकीज आणि ओरिजिन चेक्ससह विविध तंत्रांचा वापर करून अंगभूत CSRF संरक्षण आहे. जरी हे तुमच्यासाठी हाताळले जात असले तरी, याबद्दल जागरूक असणे आणि तुमची सेटअप चुकीच्या पद्धतीने कॉन्फिगर करून तुम्ही अनवधानाने असुरक्षितता निर्माण करत नाही याची खात्री करणे महत्त्वाचे आहे.
४. रेट लिमिटिंग लागू करा
एक दुर्भावनापूर्ण वापरकर्ता किंवा बॉट आपल्या फॉर्म सबमिशनला स्पॅम करू शकतो, लॉगिन ब्रूट-फोर्स करण्याचा प्रयत्न करू शकतो, आपले डेटाबेस कनेक्शन संपवू शकतो किंवा आपली सिस्टीम जंक डेटाने भरू शकतो. महत्त्वपूर्ण सर्व्हर ॲक्शन्सवर रेट लिमिटिंग लागू करणे आवश्यक आहे.
तुम्ही Upstash Rate Limiting सारख्या सेवा वापरू शकता किंवा Redis सारख्या की-व्हॅल्यू स्टोअरचा वापर करून स्वतःचे लॉजिक लागू करू शकता. की सामान्यतः वापरकर्त्याचा IP पत्ता किंवा वापरकर्ता आयडी असतो.
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
// Create a new ratelimiter, allowing 5 requests per 10 seconds
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(5, '10 s'),
});
export async function sensitiveAction(formData) {
const ip = headers().get('x-forwarded-for'); // Or get user ID from session
const { success } = await ratelimit.limit(ip);
if (!success) {
return { message: 'Too many requests. Please try again later.' };
}
// ... rest of the action logic
}
जागतिक आणि ॲक्सेसिबिलिटी विचार
जागतिक प्रेक्षकांसाठी तयार करताना केवळ तांत्रिक अंमलबजावणीच्या पलीकडे विचार करणे आवश्यक आहे.
त्रुटी संदेशांचे आंतरराष्ट्रीयकरण (i18n)
त्रुटी संदेश इंग्रजीमध्ये हार्डकोड करणे जागतिक ॲप्लिकेशनसाठी आदर्श नाही. एक चांगला दृष्टिकोन म्हणजे आपल्या सर्व्हर ॲक्शनला त्रुटी *कोड* किंवा *की* परत करणे.
// In the action
if (!validatedFields.success) {
// ...
return { errors: { customerId: ['error.customer.required'] } };
}
// In the client component, using a library like 'react-i18next'
import { useTranslation } from 'react-i18next';
function MyForm() {
const { t } = useTranslation();
const [state, dispatch] = useFormState(...);
// ...
{state.errors?.customerId &&
<p>{t(state.errors.customerId[0])}</p>}
}
हे तुमच्या व्हॅलिडेशन लॉजिकला तुमच्या प्रेझेंटेशनपासून वेगळे करते आणि तुमच्या फ्रंट-एंडला भाषांतरे सहजतेने हाताळण्यास अनुमती देते.
ॲक्सेसिबिलिटी (a11y)
त्रुटी प्रदर्शित करताना, त्या सहाय्यक तंत्रज्ञानाच्या वापरकर्त्यांसाठी प्रवेशयोग्य असल्याची खात्री करा. `aria-describedby` विशेषता वापरून त्रुटी संदेशांना त्यांच्या संबंधित फॉर्म इनपुटशी जोडा.
<div>
<label htmlFor="customerName">Customer Name</label>
<input
id="customerName"
name="customerName"
type="text"
aria-describedby="customer-error"
/>
<div id="customer-error" aria-live="polite" role="alert">
{state.errors?.customerName &&
state.errors.customerName.map((error) => (
<p key={error}>{error}</p>
))}
</div>
</div>
`aria-live="polite"` विशेषता हे सुनिश्चित करेल की स्क्रीन रीडर त्रुटी संदेश दिसल्यावर त्याची घोषणा करतील.
निष्कर्ष: जबाबदारीचे एक नवीन पर्व
रियाक्ट सर्व्हर ॲक्शन्स हे एक शक्तिशाली साधन आहे जे फुल-स्टॅक डेव्हलपमेंटला सुव्यवस्थित करते, सर्व्हर लॉजिकला UI च्या पूर्वीपेक्षा अधिक जवळ आणते. ही शक्ती, तथापि, एका शिस्तबद्ध आणि सुरक्षा-प्रथम मानसिकतेची मागणी करते.
`useFormState` आणि `useFormStatus` सारख्या हुक्सचा फायदा घेऊन, आपण उत्कृष्ट वापरकर्ता अनुभवासह प्रगतीशीलपणे सुधारित फॉर्म तयार करू शकतो. Zod सारख्या मजबूत स्कीमा व्हॅलिडेशन लायब्ररी एकत्रित करून, आपण स्वच्छ, देखरेख करण्यायोग्य आणि प्रकार-सुरक्षित व्हॅलिडेशन लॉजिक लिहू शकतो. आणि मूलभूत सुरक्षा तत्त्वांचे पालन करून - प्रमाणीकरण, अधिकृतता, रेट लिमिटिंग आणि नेहमी सर्व्हरवर व्हॅलिडेट करणे - आपण असे ॲप्लिकेशन्स तयार करू शकतो जे केवळ सुंदर आणि कार्यक्षमच नाहीत, तर लवचिक आणि सुरक्षित देखील आहेत.
प्रत्येक सर्व्हर ॲक्शनला एक सार्वजनिक API एंडपॉइंट म्हणून माना. त्याचे इनपुट प्रमाणित करा, त्याच्या परवानग्या तपासा आणि त्याच्या त्रुटी व्यवस्थित हाताळा. असे केल्याने, तुम्ही रियाक्ट डेव्हलपमेंटच्या या रोमांचक नवीन अध्यायाची पूर्ण क्षमता आत्मविश्वासाने वापरू शकता.