ã¡ãŒã«ã¢ãã¬ã¹ãåéããã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããéãããŒã¿å質ãç¶æãéä¿¡è ã®è©å€ãä¿è·ããããã«ãå ç¢ãªã¡ãŒã«æ€èšŒãå¿ èŠã§ããNode.js éçºè ã¯ãã¡ãŒã«æ€èšŒãµãŒãã¹ãã¢ããªã±ãŒã·ã§ã³ã«çµ±åããããã®åŒ·åãªããŒã«ãå©çšã§ããŸãããã®å æ¬çãªãã¥ãŒããªã¢ã«ã§ã¯ãåºæ¬çãªã»ããã¢ããããæ¬çªç°å¢å¯Ÿå¿ã®å®è£ ãŸã§ãNode.js ã§ã®ã¡ãŒã«æ€èšŒ API çµ±åã®å®è£ æ¹æ³ãé ã远ã£ãŠèª¬æããŸãã
ã¡ãŒã«æ€èšŒçµ±åã« Node.js ãéžã¶çç±
Node.js ã¯çŸä»£ç㪠Web ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®å¥œãŸããã©ã³ã¿ã€ã ãšãªã£ãŠããããã®éåææ§ã«ãããã¡ãŒã«æ€èšŒã®ãã㪠API çµ±åã«ç¹ã«é©ããŠããŸãããŠãŒã¶ãŒããã©ãŒã ãéããŠã¡ãŒã«ã¢ãã¬ã¹ãéä¿¡ããéããŠãŒã¶ãŒäœéšãé ãããªãé«éã§ãã³ããããã³ã°ãªæ€èšŒãå¿ èŠã§ããNode.js ã¯è€æ°ã®åæ API ãªã¯ãšã¹ããå¹ççã«åŠçããããšã«åªããŠããããªã¢ã«ã¿ã€ã ã®åäžã¡ãŒã«æ€èšŒãšãããåŠçã·ããªãªã®äž¡æ¹ã«çæ³çã§ãã
npm ãšã³ã·ã¹ãã ã¯ãAPI çµ±åãç°¡çŽ åããåªãã HTTP ã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªãæäŸããŠããŸããçµã¿èŸŒã¿ã® fetch APIãaxiosãnode-fetch ã®ãããã奜ãå Žåã§ããNode.js ã§ã¡ãŒã«ããªããŒã¿ãŒãå®è£ ããã«ã¯æå°éã®ãã€ã©ãŒãã¬ãŒãã³ãŒãã§æžã¿ãã«ã¹ã¿ãã€ãºã®ããã®æå€§éã®æè»æ§ãæäŸããŸãã
Node.js ãããžã§ã¯ãã®ã»ããã¢ãã
ã¡ãŒã«æ€èšŒã®å®è£ ã«å ¥ãåã«ãéçºç°å¢ãé©åã«èšå®ãããŠããããšã確èªããŠãã ããããã€ãã£ãã® fetch API ãæŽ»çšããã«ã¯ Node.js ããŒãžã§ã³ 18 以éãå¿ èŠã§ããã以åã®ããŒãžã§ã³ã§ã¯ node-fetch ãããªãã£ã«ãšããŠäœ¿çšã§ããŸãã
äŸåé¢ä¿ã®ã€ã³ã¹ããŒã«
æ°ãããããžã§ã¯ããã£ã¬ã¯ããªãäœæããnpm ã§åæåããŸããpackage.json ã«ã¯ HTTP ãªã¯ãšã¹ããšç°å¢å€æ°ç®¡çã«å¿ èŠãªäŸåé¢ä¿ãå«ããå¿ èŠããããŸããdotenv ããã±ãŒãžã¯ããœãŒã¹ã³ãŒãã«æ©å¯æ å ±ãããŒãã³ãŒãã£ã³ã°ããã®ã§ã¯ãªããç°å¢ãã¡ã€ã«ããèªã¿èŸŒãããšã§ API èªèšŒæ å ±ãå®å šã«ä¿ã€ã®ã«åœ¹ç«ã¡ãŸãã
// package.json
{
"name": "email-verification-demo",
"version": "1.0.0",
"type": "module",
"dependencies": {
"dotenv": "^16.3.1"
}
}
ç°å¢å€æ°ã®èšå®
BillionVerify API ããŒãç°å¢ãã¡ã€ã«ã«ä¿åããŸããAPI ããŒãããŒãžã§ã³ç®¡çã«ã³ãããããªãã§ãã ããã.env ãã¡ã€ã«ã¯èªèšŒæ å ±ãã³ãŒãããŒã¹ããåé¢ãããã¹ãŠã®ã¡ãŒã«æ€èšŒãµãŒãã¹ãæšå¥šããã»ãã¥ãªãã£ã®ãã¹ããã©ã¯ãã£ã¹ã«åŸããŸãã
# .env BILLIONVERIFY_API_KEY=your_api_key_here
åäžã¡ãŒã«æ€èšŒã®å®è£
ããããã¡ãŒã«æ€èšŒçµ±åã®åºç€ã¯ãåã ã®ã¡ãŒã«ã¢ãã¬ã¹ãæ€èšŒããæ©èœã§ãããã®æ©èœã¯ããŠãŒã¶ãŒç»é²ããåãåãããã©ãŒã ã®éä¿¡ãããã³å³åº§ã®ãã£ãŒãããã¯ãå¿ èŠãªããããã·ããªãªã§ã®ãªã¢ã«ã¿ã€ã æ€èšŒãå®çŸããŸãã
æåã® API åŒã³åºããè¡ã
BillionVerify ã¡ãŒã«æ€èšŒ API ã¯ããªã¯ãšã¹ãããã£ã«ã¡ãŒã«ã¢ãã¬ã¹ãå«ã POST ãªã¯ãšã¹ããåãä»ããŸããã¬ã¹ãã³ã¹ã«ã¯ãæå¹æ§ã¹ããŒã¿ã¹ãé ä¿¡å¯èœæ§è©äŸ¡ãäœ¿ãæšãŠã¡ãŒã«ã圹å²ããŒã¹ã¢ãã¬ã¹ããã£ãããªãŒã«ãã¡ã€ã³ã®è©³çްãªãã§ãã¯ãªã©ãå æ¬çãªæ€èšŒçµæãå«ãŸããŸãã
// verify-email.js
import 'dotenv/config';
const API_BASE_URL = 'https://api.billionverify.com/v1';
const API_KEY = process.env.BILLIONVERIFY_API_KEY;
async function verifyEmail(email) {
const response = await fetch(`${API_BASE_URL}/verify`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
if (!response.ok) {
throw new Error(`Verification failed: ${response.status}`);
}
return response.json();
}
// Usage example
const result = await verifyEmail('user@example.com');
console.log(result);
ã¬ã¹ãã³ã¹ãã£ãŒã«ããçè§£ãã
æ€èšŒã¬ã¹ãã³ã¹ã¯ãåã¡ãŒã«ã¢ãã¬ã¹ã«é¢ããå®çšçãªæ å ±ãæäŸããŸãããããã®ã¬ã¹ãã³ã¹ãã£ãŒã«ããçè§£ããããšã§ãã¡ãŒã«ã¢ãã¬ã¹ãã·ã¹ãã ã«åãå ¥ãããã©ããã«ã€ããŠæ å ±ã«åºã¥ããæ±ºå®ãäžãããšãã§ããŸãã
| ãã£ãŒã«ã | 説æ | ãŠãŒã¹ã±ãŒã¹ |
|---|---|---|
| is_valid | ç·åçãªæå¹æ§è©äŸ¡ | æ¿èª/æåŠã®äž»èŠãªæ±ºå® |
| is_deliverable | ã¡ãŒã«ãåä¿¡ã§ãã | ã¡ãŒã«ãã£ã³ããŒã³ã®é©æ Œæ§ |
| is_disposable | äžæçãªã¡ãŒã«ãµãŒãã¹ | äžæ£é²æ¢ |
| is_role_based | æ±çšã¢ãã¬ã¹ (info@ãsupport@) | B2B ã¿ãŒã²ãã£ã³ã° |
| is_catch_all | ãã¡ã€ã³ããã¹ãŠã®ã¢ãã¬ã¹ãåãå ¥ãã | ãªã¹ã¯è©äŸ¡ |
| risk_score | 0-100 ã®ãªã¹ã¯è©äŸ¡ | ãã现ããªãã£ã«ã¿ãªã³ã° |
åå©çšå¯èœãªã¡ãŒã«ããªããŒã¿ãŒã¯ã©ã¹ã®æ§ç¯
æ¬çªã¢ããªã±ãŒã·ã§ã³ã¯ãã¡ãŒã«æ€èšŒããžãã¯ãåå©çšå¯èœãªã¯ã©ã¹ã«ã«ãã»ã«åããããšã§æ©æµãåããŸãããã®ã¢ãããŒãã¯ãäžè²«ãããšã©ãŒåŠçãèªåãªãã©ã€ãããã³ã¢ããªã±ãŒã·ã§ã³ã®æ®ãã®éšåãå©çšããããã®ã¯ãªãŒã³ãªã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããŸãã
ã¯ã©ã¹ã¢ãŒããã¯ãã£
EmailValidator ã¯ã©ã¹ã¯ HTTP ã®è©³çŽ°ãæœè±¡åããäžè¬çãªæ€èšŒã·ããªãªã®ããã®ã¡ãœãããæäŸããŸããAPI èªèšŒããªã¯ãšã¹ãã®ãã©ãŒããããã¬ã¹ãã³ã¹ã®è§£æãåŠçããã¢ããªã±ãŒã·ã§ã³ã³ãŒãã API ã®ã¡ã«ãã¯ã¹ã§ã¯ãªãããžãã¹ããžãã¯ã«éäžã§ããããã«ããŸãã
// EmailValidator.js
import 'dotenv/config';
class EmailValidator {
constructor(apiKey = process.env.BILLIONVERIFY_API_KEY) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.billionverify.com/v1';
this.maxRetries = 3;
this.retryDelay = 1000;
}
async verify(email) {
let lastError;
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
try {
const response = await fetch(`${this.baseUrl}/verify`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
if (response.status === 429) {
// Rate limited - wait and retry
await this.sleep(this.retryDelay * attempt);
continue;
}
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
} catch (error) {
lastError = error;
if (attempt < this.maxRetries) {
await this.sleep(this.retryDelay * attempt);
}
}
}
throw lastError;
}
async isValid(email) {
const result = await this.verify(email);
return result.is_valid && result.is_deliverable;
}
async isHighRisk(email) {
const result = await this.verify(email);
return result.risk_score > 70 || result.is_disposable;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
export default EmailValidator;
èªåãªãã©ã€ããžãã¯
ãã®ã¯ã©ã¹ã¯ã倱æãããªã¯ãšã¹ãã«å¯ŸããŠææ°ããã¯ãªããå®è£ ããŠãããããã¯æ¬çªç°å¢ã®ä¿¡é Œæ§ã«ãšã£ãŠäžå¯æ¬ ã§ããã¡ãŒã«æ€èšŒãµãŒãã¹ãã¬ãŒãå¶éãšã©ãŒãè¿ããäžæçãªåé¡ãçµéšããå Žåãã¯ã©ã¹ã¯è©Šè¡ééãå¢ãããªããèªåçã«ãªãã©ã€ããŸãã
Express.js ã¢ããªã±ãŒã·ã§ã³ãšã®çµ±å
ã»ãšãã©ã® Node.js Web ã¢ããªã±ãŒã·ã§ã³ã¯ Express.js ãŸãã¯é¡äŒŒã®ãã¬ãŒã ã¯ãŒã¯ã䜿çšããŸããã¡ãŒã«æ€èšŒã Express ã«ãŒãã«çµ±åããããšã§ããã©ãŒã éä¿¡æã®ãªã¢ã«ã¿ã€ã æ€èšŒãå¯èœã«ãªããŸãããŠãŒã¶ãŒã¯ç¡å¹ãªã¡ãŒã«ã¢ãã¬ã¹ã«ã€ããŠå³åº§ã«ãã£ãŒãããã¯ãåãåããã¡ãŒã«ãªã¹ãã®å質ãä¿è·ããªããç»é²äœéšãåäžãããŸãã
æ€èšŒããã«ãŠã§ã¢ã®äœæ
ã«ãŒããã³ãã©ãŒã«å°éããåã«ã¡ãŒã«ã¢ãã¬ã¹ãæ€èšŒããããã«ãŠã§ã¢é¢æ°ãäœæããŸãããã®ã¢ãããŒãã¯ãæ€èšŒããžãã¯ãããžãã¹ããžãã¯ããåé¢ããã³ãŒããããä¿å®ãããããã¹ãããããããŸãã
// server.js
import express from 'express';
import EmailValidator from './EmailValidator.js';
const app = express();
const validator = new EmailValidator();
app.use(express.json());
// Middleware for email verification
const verifyEmailMiddleware = async (req, res, next) => {
const { email } = req.body;
if (!email) {
return res.status(400).json({ error: 'Email is required' });
}
try {
const result = await validator.verify(email);
if (!result.is_valid) {
return res.status(400).json({
error: 'Invalid email address',
details: result
});
}
if (result.is_disposable) {
return res.status(400).json({
error: 'Disposable email addresses are not allowed'
});
}
// Attach verification result for downstream use
req.emailVerification = result;
next();
} catch (error) {
console.error('Email verification failed:', error);
// Allow request to proceed but flag as unverified
req.emailVerification = { verified: false, error: error.message };
next();
}
};
// Registration endpoint with email verification
app.post('/api/register', verifyEmailMiddleware, async (req, res) => {
const { email, name, password } = req.body;
// Email is already verified by middleware
// Proceed with registration logic
res.json({
success: true,
message: 'Registration successful',
emailVerification: req.emailVerification
});
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
æ€èšŒçµæã®åŠç
ããã«ãŠã§ã¢ã¢ãããŒãã¯ãã¡ãŒã«æ€èšŒãã©ã®çšåºŠå³å¯ã«å®æœãããã«ã€ããŠæè»æ§ãæäŸããŸããäžéšã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã¹ãŠã®æªæ€èšŒã¡ãŒã«ãæåŠããããšãéžæããå ŽåããããŸãããä»ã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãæåã¬ãã¥ãŒçšã®èŠåãã©ã°ä»ãã§åãå ¥ããå ŽåããããŸãããªã¯ãšã¹ããªããžã§ã¯ãã«æ·»ä»ãããã¡ãŒã«ç¢ºèªçµæã«ãããäžæµã®ãã³ãã©ãŒããã现ããªæ±ºå®ãäžãããšãã§ããŸãã
ãªã¹ãã¯ãªãŒãã³ã°ã®ããã®ãããã¡ãŒã«æ€èšŒ
ãªã¢ã«ã¿ã€ã æ€èšŒã¯åã ã®ã¢ãã¬ã¹ãåŠçããŸãããå€ãã®ã¢ããªã±ãŒã·ã§ã³ã¯å€§èŠæš¡ãªã¡ãŒã«ãªã¹ããæ€èšŒããå¿ èŠããããŸããããŒã±ãã£ã³ã°ããŒã ã¯å®æçã«è³Œèªè ãªã¹ããã¯ãªãŒãã³ã°ããCRM ã·ã¹ãã ã¯å®æçã«ä¿åãããé£çµ¡å ãæ€èšŒããŸãããããæ€èšŒãšã³ããã€ã³ãã¯è€æ°ã®ã¡ãŒã«ãå¹ççã«åŠçããAPI åŒã³åºããåæžããŠã¹ã«ãŒããããåäžãããŸãã
ããããžã§ãã®éä¿¡
ãããæäœã¯åäžæ€èšŒãšã¯ç°ãªãåŠçãå¿ èŠã§ãããžã§ãã®éä¿¡ãã¹ããŒã¿ã¹ã®ããŒãªã³ã°ãçµæã®ååŸãå¥ã ã®æäœãšããŠç®¡çããå¿ èŠããããŸãããã®éåæãã¿ãŒã³ã«ãããã¡ãŒã«æ€èšŒãµãŒãã¹ã¯ã¿ã€ã ã¢ãŠãããããšãªãå€§èŠæš¡ãªãªã¹ããåŠçã§ããŸãã
// batch-verify.js
import EmailValidator from './EmailValidator.js';
class BatchEmailValidator extends EmailValidator {
async submitBatch(emails) {
const response = await fetch(`${this.baseUrl}/verify/batch`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ emails })
});
if (!response.ok) {
throw new Error(`Batch submission failed: ${response.status}`);
}
return response.json();
}
async getBatchStatus(jobId) {
const response = await fetch(`${this.baseUrl}/verify/batch/${jobId}`, {
headers: {
'Authorization': `Bearer ${this.apiKey}`
}
});
if (!response.ok) {
throw new Error(`Status check failed: ${response.status}`);
}
return response.json();
}
async verifyBatch(emails, options = {}) {
const {
pollInterval = 5000,
maxWaitTime = 300000,
onProgress = () => {}
} = options;
// Submit the batch job
const { job_id } = await this.submitBatch(emails);
const startTime = Date.now();
// Poll for completion
while (Date.now() - startTime < maxWaitTime) {
const status = await this.getBatchStatus(job_id);
onProgress({
processed: status.processed,
total: status.total,
percentage: Math.round((status.processed / status.total) * 100)
});
if (status.status === 'completed') {
return status.results;
}
if (status.status === 'failed') {
throw new Error(`Batch job failed: ${status.error}`);
}
await this.sleep(pollInterval);
}
throw new Error('Batch verification timed out');
}
}
// Usage example
const batchValidator = new BatchEmailValidator();
const emails = [
'user1@example.com',
'user2@company.org',
'invalid@fake.domain',
// ... more emails
];
const results = await batchValidator.verifyBatch(emails, {
onProgress: (progress) => {
console.log(`Progress: ${progress.percentage}%`);
}
});
// Process results
const validEmails = results.filter(r => r.is_valid);
const invalidEmails = results.filter(r => !r.is_valid);
console.log(`Valid: ${validEmails.length}, Invalid: ${invalidEmails.length}`);
çµæã®ããŒãªã³ã°
ãããæ€èšŒã®å®è£ ã«ã¯é²æã³ãŒã«ããã¯ãå«ãŸããŠãããã¢ããªã±ãŒã·ã§ã³ããŠãŒã¶ãŒã«æ€èšŒã®é²æã衚瀺ããããç£èŠã®ããã«ãã°ã«èšé²ãããã§ããŸããããã¯ãå®äºã«æ°åãããå¯èœæ§ã®ããæ°åã®ã¡ãŒã«ã¢ãã¬ã¹ãå«ããªã¹ããåŠçããå Žåã«ç¹ã«æçšã§ãã
ãšã©ãŒåŠçãšèé害æ§
æ¬çªç°å¢ã®ã¡ãŒã«æ€èšŒçµ±åã¯ããšã©ãŒãé©åã«åŠçããå¿ èŠããããŸãããããã¯ãŒã¯ã®åé¡ãAPI ã¬ãŒãå¶éããµãŒãã¹ã®å©çšäžå¯ã¯åæ£ã·ã¹ãã ã§ã¯é¿ããããŸãããé©åãªãšã©ãŒåŠçãå®è£ ããããšã§ãæ€èšŒãµãŒãã¹ãåé¡ãçµéšããŠããã¢ããªã±ãŒã·ã§ã³ãæ©èœãç¶æã§ããããã«ããŸãã
ã«ã¹ã¿ã ãšã©ãŒã¯ã©ã¹
ç°ãªããšã©ãŒã¿ã€ããåºå¥ããå æ¬çãªãšã©ãŒåŠçæŠç¥ãäœæããŸããã¬ãŒãå¶éã®ãããªäžæçãªãšã©ãŒã¯å詊è¡ãè¡ã䟡å€ããããŸãããç¡å¹ãª API ããŒã®ãããªæ°žç¶çãªãšã©ãŒã¯å³åº§ã®æ³šæãšã¢ã©ãŒããå¿ èŠã§ãã
// errors.js
class EmailVerificationError extends Error {
constructor(message, code, retryable = false) {
super(message);
this.name = 'EmailVerificationError';
this.code = code;
this.retryable = retryable;
}
}
class RateLimitError extends EmailVerificationError {
constructor(retryAfter) {
super('Rate limit exceeded', 'RATE_LIMITED', true);
this.retryAfter = retryAfter;
}
}
class AuthenticationError extends EmailVerificationError {
constructor() {
super('Invalid API key', 'AUTH_FAILED', false);
}
}
// Enhanced validator with error handling
class RobustEmailValidator extends EmailValidator {
async verify(email) {
try {
const response = await fetch(`${this.baseUrl}/verify`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
if (response.status === 401) {
throw new AuthenticationError();
}
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
throw new RateLimitError(parseInt(retryAfter));
}
if (response.status >= 500) {
throw new EmailVerificationError(
'Service temporarily unavailable',
'SERVICE_ERROR',
true
);
}
if (!response.ok) {
const error = await response.json();
throw new EmailVerificationError(
error.message || 'Verification failed',
'API_ERROR',
false
);
}
return response.json();
} catch (error) {
if (error instanceof EmailVerificationError) {
throw error;
}
// Network or parsing error
throw new EmailVerificationError(
error.message,
'NETWORK_ERROR',
true
);
}
}
}
export { EmailVerificationError, RateLimitError, AuthenticationError, RobustEmailValidator };
ã°ã¬ãŒã¹ãã«ãã°ã©ããŒã·ã§ã³ã®å®è£
ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã¯ãç°ãªããšã©ãŒã¿ã€ããé©åã«åŠçãããŠãŒã¶ãŒã«æå³ã®ãããã£ãŒãããã¯ãæäŸããéçšããŒã ã«é©åãªã¢ã©ãŒããããªã¬ãŒã§ããŸãã
ããã©ãŒãã³ã¹åäžã®ããã®ãã£ãã·ã¥å®è£
ã¡ãŒã«æ€èšŒ API åŒã³åºãã«ã¯ãééçããã³ã¬ã€ãã³ã·ãŒã®äž¡é¢ã§ã³ã¹ããããããŸãããã£ãã·ã¥ã¬ã€ã€ãŒãå®è£ ããããšã§ãåãã¡ãŒã«ã¢ãã¬ã¹ã®åé·ãªæ€èšŒãåæžããªãããã¬ã¹ãã³ã¹æéãæ¹åããŸããé©åã«èšèšããããã£ãã·ã¥ã¯ãã¡ãŒã«æå¹æ§ã®åçãªæ§è³ªãå°éããªãããæå³ã®ããããã©ãŒãã³ã¹äžã®å©ç¹ãæäŸããŸãã
ã€ã³ã¡ã¢ãªãã£ãã·ã¥æŠç¥
ãŠãŒã¹ã±ãŒã¹ã«åºã¥ããŠé©åãªãã£ãã·ã¥æéãéžæããŠãã ãããã¡ãŒã«ã®æå¹æ§ã¯å€åããå¯èœæ§ããããŸããã¡ãŒã«ããã¯ã¹ãåé€ããããã¡ã€ã³ãæéåãã«ãªãããã£ãããªãŒã«èšå®ã倿ŽãããŸããã»ãšãã©ã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ã24 æéã®ãã£ãã·ã¥æéãããã©ãŒãã³ã¹ãšç²ŸåºŠã®ãã©ã³ã¹ãåããŸãã
// cached-validator.js
class CachedEmailValidator extends EmailValidator {
constructor(apiKey, cacheOptions = {}) {
super(apiKey);
this.cache = new Map();
this.cacheTTL = cacheOptions.ttl || 24 * 60 * 60 * 1000; // 24 hours
this.maxCacheSize = cacheOptions.maxSize || 10000;
}
getCacheKey(email) {
return email.toLowerCase().trim();
}
getCached(email) {
const key = this.getCacheKey(email);
const cached = this.cache.get(key);
if (!cached) return null;
if (Date.now() > cached.expiresAt) {
this.cache.delete(key);
return null;
}
return cached.result;
}
setCache(email, result) {
// Implement LRU eviction if cache is full
if (this.cache.size >= this.maxCacheSize) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}
const key = this.getCacheKey(email);
this.cache.set(key, {
result,
expiresAt: Date.now() + this.cacheTTL
});
}
async verify(email) {
// Check cache first
const cached = this.getCached(email);
if (cached) {
return { ...cached, fromCache: true };
}
// Perform verification
const result = await super.verify(email);
// Cache successful results
if (result && !result.error) {
this.setCache(email, result);
}
return { ...result, fromCache: false };
}
clearCache() {
this.cache.clear();
}
getCacheStats() {
return {
size: this.cache.size,
maxSize: this.maxCacheSize
};
}
}
export default CachedEmailValidator;
ãã£ãã·ã¥ã®ç¡å¹å
倧éãåŠçããæ¬çªã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã¡ã¢ãªå ãã£ãã·ã¥ã®ä»£ããã« Redis ãŸã㯠Memcached ã®äœ¿çšãæ€èšããŠãã ããããããã®å€éšãã£ãã·ã¥ã¹ãã¢ã¯ãã¢ããªã±ãŒã·ã§ã³ã®åèµ·ååŸãæ°žç¶åãããã¯ã©ã¹ã¿ãŒåããããããã€ã¡ã³ãã§è€æ°ã®ã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹éã§å ±æã§ããŸãã
ã¡ãŒã«æ€èšŒçµ±åã®ãã¹ã
å æ¬çãªãã¹ãã«ãããã¡ãŒã«æ€èšŒçµ±åããã¹ãŠã®ã·ããªãªã§æ£ããæ©èœããããšãä¿èšŒãããŸããåäœãã¹ãã¯åã ã®ã³ã³ããŒãã³ããæ€èšŒããçµ±åãã¹ãã¯é©å㪠API éä¿¡ã確èªããŸããåäœãã¹ãäžã¯ HTTP ã¬ã€ã€ãŒãã¢ãã¯ããŠãå®éã® API åŒã³åºããé¿ããŸãã
ã¢ãã¯ã䜿çšããåäœãã¹ã
// validator.test.js
import { jest } from '@jest/globals';
import EmailValidator from './EmailValidator.js';
describe('EmailValidator', () => {
let validator;
beforeEach(() => {
validator = new EmailValidator('test-api-key');
global.fetch = jest.fn();
});
test('returns valid result for valid email', async () => {
fetch.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({
is_valid: true,
is_deliverable: true,
is_disposable: false,
risk_score: 10
})
});
const result = await validator.verify('valid@example.com');
expect(result.is_valid).toBe(true);
expect(result.is_deliverable).toBe(true);
});
test('handles rate limiting with retry', async () => {
fetch
.mockResolvedValueOnce({ ok: false, status: 429 })
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ is_valid: true })
});
const result = await validator.verify('test@example.com');
expect(fetch).toHaveBeenCalledTimes(2);
expect(result.is_valid).toBe(true);
});
test('throws after max retries exceeded', async () => {
fetch.mockResolvedValue({ ok: false, status: 500 });
await expect(validator.verify('test@example.com'))
.rejects.toThrow('API error: 500');
});
});
ãšããžã±ãŒã¹ã®ãã¹ã
ãããã¯ãŒã¯é害ãäžæ£ãªåœ¢åŒã®ã¬ã¹ãã³ã¹ãç°åžžãªã¡ãŒã«åœ¢åŒãªã©ã®ãšããžã±ãŒã¹ã®ãã¹ããå«ããŠãã ãããã¡ãŒã«ãã§ãã«ãŒã¯ãã¢ããªã±ãŒã·ã§ã³ãã¯ã©ãã·ã¥ãããããšãªãããã¹ãŠã®ã·ããªãªãé©åã«åŠçããå¿ èŠããããŸãã
ã¢ãã¿ãªã³ã°ãšãã®ã³ã°ã®ãã¹ããã©ã¯ãã£ã¹
æ¬çªç°å¢ã®ã¡ãŒã«æ€èšŒçµ±åã«ã¯ãããã©ãŒãã³ã¹ã®è¿œè·¡ãåé¡ã®ç¹å®ãã³ã¹ãã®æé©åã®ããã®ç£èŠãå¿ èŠã§ããæ€èšŒçµæãã¬ã¹ãã³ã¹æéããšã©ãŒçããã£ããã£ããæ§é åããããã®ã³ã°ãå®è£ ããŸãã
æ§é åãã®ã³ã°
// monitored-validator.js
class MonitoredEmailValidator extends EmailValidator {
constructor(apiKey, logger = console) {
super(apiKey);
this.logger = logger;
this.metrics = {
totalRequests: 0,
successfulVerifications: 0,
failedVerifications: 0,
cacheHits: 0,
totalLatency: 0
};
}
async verify(email) {
const startTime = Date.now();
this.metrics.totalRequests++;
try {
const result = await super.verify(email);
const latency = Date.now() - startTime;
this.metrics.successfulVerifications++;
this.metrics.totalLatency += latency;
this.logger.info({
event: 'email_verification',
email: this.maskEmail(email),
is_valid: result.is_valid,
latency_ms: latency
});
return result;
} catch (error) {
this.metrics.failedVerifications++;
this.logger.error({
event: 'email_verification_error',
email: this.maskEmail(email),
error: error.message,
latency_ms: Date.now() - startTime
});
throw error;
}
}
maskEmail(email) {
const [local, domain] = email.split('@');
const maskedLocal = local.charAt(0) + '***' + local.slice(-1);
return `${maskedLocal}@${domain}`;
}
getMetrics() {
return {
...this.metrics,
averageLatency: this.metrics.totalRequests > 0
? Math.round(this.metrics.totalLatency / this.metrics.totalRequests)
: 0,
successRate: this.metrics.totalRequests > 0
? (this.metrics.successfulVerifications / this.metrics.totalRequests * 100).toFixed(2)
: 0
};
}
}
export default MonitoredEmailValidator;
ã¡ããªã¯ã¹ã®è¿œè·¡
ãšã©ãŒçã®äžæããAPI ã®åé¡ãäžæ£äœ¿çšã®è©Šã¿ã瀺ãå¯èœæ§ã®ããç°åžžãªãã¿ãŒã³ã«å¯ŸããŠã¢ã©ãŒããèšå®ããŸããç£èŠããã·ã¥ããŒãã¯ãæ€èšŒãã¿ãŒã³ãçè§£ããæéã®çµéãšãšãã«å®è£ ãæé©åããã®ã«åœ¹ç«ã¡ãŸãã
ã»ãã¥ãªãã£ã«é¢ããèæ ®äºé
ã¡ãŒã«æ€èšŒçµ±åã¯æœåšçã«æ©å¯ããŒã¿ãåŠçãããããæ éãªã»ãã¥ãªãã£æ€èšãå¿ èŠã§ããAPI ããŒãä¿è·ããå ¥åãæ€èšŒããäžæ£äœ¿çšãé²ãããã«ç¬èªã®ãšã³ããã€ã³ãã«ã¬ãŒãå¶éãå®è£ ããŸãã
API èªèšŒæ å ±ã®ä¿è·
BillionVerify API ããŒãã¯ã©ã€ã¢ã³ãåŽã®ã³ãŒãã«å ¬éããªãã§ãã ããããã¹ãŠã®æ€èšŒãªã¯ãšã¹ãã¯ãAPI èªèšŒæ å ±ãå®å šã«ä¿æããããã¯ãšã³ããµãŒããŒãçµç±ããå¿ èŠããããŸããããã«ãããæªæã®ããã¢ã¯ã¿ãŒãèªåã®ç®çã®ããã« API ã¯ã©ãŒã¿ã䜿çšããããšãé²ããŸãã
å ¥åæ€èšŒãšã¬ãŒãå¶é
æ€èšŒ API ã«ã¡ãŒã«ãéä¿¡ããåã«ãå ¥åæ€èšŒãå®è£ ããŸããèªåã®åŽã§ã®åºæ¬çãªåœ¢åŒæ€èšŒã«ãããäžèŠãª API åŒã³åºããåæžããæããã«ç¡å¹ãªå ¥åã«å¯ŸããŠããè¿ éãªãã£ãŒãããã¯ãæäŸããŸãã
// secure-validator.js
class SecureEmailValidator extends EmailValidator {
constructor(apiKey, options = {}) {
super(apiKey);
this.rateLimiter = new Map();
this.maxRequestsPerMinute = options.maxRequestsPerMinute || 100;
}
validateEmailFormat(email) {
if (!email || typeof email !== 'string') {
throw new Error('Email must be a non-empty string');
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
throw new Error('Invalid email format');
}
if (email.length > 254) {
throw new Error('Email exceeds maximum length');
}
return email.toLowerCase().trim();
}
checkRateLimit(clientId) {
const now = Date.now();
const windowStart = now - 60000;
if (!this.rateLimiter.has(clientId)) {
this.rateLimiter.set(clientId, []);
}
const requests = this.rateLimiter.get(clientId);
const recentRequests = requests.filter(time => time > windowStart);
if (recentRequests.length >= this.maxRequestsPerMinute) {
throw new Error('Rate limit exceeded. Please try again later.');
}
recentRequests.push(now);
this.rateLimiter.set(clientId, recentRequests);
}
async verify(email, clientId = 'default') {
this.checkRateLimit(clientId);
const sanitizedEmail = this.validateEmailFormat(email);
return super.verify(sanitizedEmail);
}
}
export default SecureEmailValidator;
ãŸãšã
Node.js ã¢ããªã±ãŒã·ã§ã³ã§ã¡ãŒã«æ€èšŒãå®è£ ããããšã¯ãé«å質ãªã¡ãŒã«ãªã¹ããç¶æãéä¿¡è ã®è©å€ãä¿è·ããããã®åºç€ãæäŸããŸãããã®ãã¥ãŒããªã¢ã«ã§åãäžããæè¡ïŒåºæ¬ç㪠API çµ±åããããã£ãã·ã³ã°ããšã©ãŒåŠçãç£èŠãå«ãæ¬çªç°å¢å¯Ÿå¿ãã¿ãŒã³ãŸã§ïŒã¯ãä»»æã® Node.js ã¢ããªã±ãŒã·ã§ã³ã«å ç¢ãªã¡ãŒã«ããªããŒã·ã§ã³ãçµã¿èŸŒãããã®è£ åãæäŸããŸãã
BillionVerify ã®ã¡ãŒã«æ€èšŒ API 㯠Node.js ãšã·ãŒã ã¬ã¹ã«çµ±åããããªã¢ã«ã¿ã€ã ã®åäžã¡ãŒã«æ€èšŒãšãããåŠçæ©èœãæäŸããŸããã¬ã¹ãã³ã¹ããŒã¿ã«ãããåçŽãªæå¹/ç¡å¹ã®å€å®ãããæŽç·Žããããªã¹ã¯ããŒã¹ã®ãã£ã«ã¿ãªã³ã°ãŸã§ãã¡ãŒã«åãå ¥ãã«é¢ãããã现ããªæææ±ºå®ãå¯èœã«ãªããŸãã
åºæ¬çãªå®è£ ããå§ã㊠API ãã¿ãŒã³ãçè§£ããã¢ããªã±ãŒã·ã§ã³ã®èŠä»¶ãé²åããã«ã€ããŠãåŸã ã«ãã£ãã·ã³ã°ãç£èŠããšã©ãŒåŠçã远å ããŠãã ãããããã§ç€ºãããã¡ãŒã«ãã§ãã«ãŒãã¿ãŒã³ã¯ãã¹ã¿ãŒãã¢ããã® MVP ããæ°çŸäžã®æ€èšŒãåŠçãããšã³ã¿ãŒãã©ã€ãºã°ã¬ãŒãã®ã¢ããªã±ãŒã·ã§ã³ãŸã§ã¹ã±ãŒã«ããŸãã
ãŠãŒã¶ãŒç»é²ã·ã¹ãã ãæ§ç¯ããå Žåã§ããããŒã±ãã£ã³ã°ãªã¹ããã¯ãªãŒãã³ã°ããå Žåã§ãããåãåãããã©ãŒã ã®éä¿¡ãæ€èšŒããå Žåã§ããé©åãªã¡ãŒã«æ€èšŒã¯ã¡ãŒã«é ä¿¡å¯èœæ§ãä¿è·ããã¡ãã»ãŒãžãå®éã®åä¿¡è ã«å±ãããšãä¿èšŒããŸããBillionVerify ã¢ã«ãŠã³ãã«ãµã€ã³ã¢ããããŠã仿¥ãã Node.js ã¢ããªã±ãŒã·ã§ã³ã«ã¡ãŒã«æ€èšŒãçµ±åããç¬¬äžæ©ãèžã¿åºããŸãããã