Ontwerp een Geavanceerde Data Validatie en Normalisatie voor API Integraties met Externe Diensten
description
Met deze prompt kan de gebruiker een robuuste strategie ontwikkelen voor het valideren en normaliseren van data binnen API-integraties met externe diensten. Dit vermindert fouten, verhoogt de betrouwbaarheid van data-uitwisseling en zorgt voor consistentie in systemen. De gebruiker krijgt concrete voorbeelden en best practices, wat de kwaliteit van de integratie verbetert en problemen voorkomt die anders moeilijk te traceren zijn.
prompt
Help me een geavanceerde data validatie- en normalisatiestrategie te ontwerpen voor mijn API-integratie met externe diensten zoals Stripe, SendGrid of Twilio. Beschrijf mijn huidige data-invoer en verwerking: <beschrijf je huidige data-invoer en verwerking>. ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Zeker! Hier is een uitgebreide strategie voor geavanceerde data validatie en normalisatie voor jouw API-integratie met Stripe, SendGrid en Twilio, passend bij jouw React frontend en Node.js backend.
**1. Data-invoer en verwerking overzicht**
- **Frontend**: Verzamelt klantgegevens (naam, e-mail, telefoonnummer, adres) en bestellinginformatie.
- **Backend**: Verwerkt deze gegevens, valideert ze, normaliseert en stuurt ze naar externe diensten zoals Stripe (betalingen), Twilio (sms), SendGrid (emails).
---
**2. Validatie- en normalisatiestrategie**
### A. Validatieprincipes
- **Client-side**: Basis validatie (vereiste velden, eenvoudige format checks) om gebruikerservaring te verbeteren.
- **Server-side**: Strenge validatie om datakwaliteit te garanderen vóór verwerking.
### B. Validatieregels
| Gegevenstype | Validatieregels | Voorbeeld in code |
|--------------|------------------|-------------------|
| E-mail | Correcte e-mailstructuur, niet leeg, geen spamwoorden | `validator.isEmail(email)` |
| Telefoonnummer | Numeriek, juiste lengte, internationaal formaat | `libphonenumber-js` of regex |
| Naam | Niet leeg, geen speciale tekens | regex `/^[a-zA-Z\s'-]+$/` |
| Adres | Niet leeg, juiste structuur (straat, nummer, postcode, stad) | regex of address parsing librarie |
| Betalingsgegevens | Validatie via Stripe API (bv. token) | Stripe client library |
### C. Voorbeeld validatiecode (Node.js)
```js
const validator = require('validator');
function validateCustomerData(data) {
const errors = [];
if (!data.name || !validator.matches(data.name, /^[a-zA-Z\s'-]+$/)) {
errors.push('Ongeldige naam.');
}
if (!validator.isEmail(data.email || '')) {
errors.push('Ongeldig e-mailadres.');
}
if (!data.phone || !validator.isMobilePhone(data.phone, 'NL')) {
errors.push('Ongeldig telefoonnummer.');
}
if (!data.address || !data.address.street || !data.address.postcode || !data.address.city) {
errors.push('Adresgegevens incompleet.');
}
return errors;
}
```
---
### D. Normalisatie en formattering
| Gegevenstype | Normalisatiestappen | Voorbeeld |
|--------------|---------------------|------------|
| E-mail | Convert naar lowercase, trim whitespace | `email = email.trim().toLowerCase()` |
| Telefoon | Remove spaties, standaard formaat | `phone = phone.replace(/\s+/g, '')` |
| Naam | Capitalize eerste letters | `name = name.trim().replace(/\b\w/g, c => c.toUpperCase())` |
| Adres | Standardiseer straatnaam, postcode | gebruik adresconversie libraries of API's |
### E. Voorbeeld normalisatiecode
```js
function normalizeCustomerData(data) {
return {
name: data.name.trim().replace(/\b\w/g, c => c.toUpperCase()),
email: data.email.trim().toLowerCase(),
phone: data.phone.replace(/\s+/g, ''),
address: {
street: data.address.street.trim(),
postcode: data.address.postcode.toUpperCase(),
city: data.address.city.trim()
}
};
}
```
---
### F. Integratie met externe diensten
- **Stripe**: Valideer betalingsgegevens vóór het aanmaken van betalingen; gebruik Stripe’s client- en server-side libraries voor tokenization en validatie.
- **Twilio**: Normaliseer telefoonnummer en gebruik Twilio’s API om te verifiëren of het nummer inderdaad actief is.
- **SendGrid**: Validate e-mailadressen, voorkom spam en misbruik.
---
**3. Extra aanbevelingen**
- **Gebruik JSON-schema validatie** (bijv. `ajv`) voor gestructureerde validatie.
- **Gebruik externe adres-validatiediensten** zoals Google Maps API of PostNL API.
- **Log en monitor invalid data** voor verdere verbetering.
- **Gebruik try-catch blokken en foutafhandeling** om aangepaste foutmeldingen terug te sturen.
---
**Kort samengevat:**
- Voer basisvalidatie op frontend uit, maar controleer alles op backend.
- Valideer en normaliseer data vóór verzending naar externe diensten.
- Gebruik geschikte libraries en API’s voor adres- en telefoonnummervalidatie.
- Zorg dat alle data uniform is (lowercase, uppercase, format) voor maximale compatibiliteit.
---
Als je hulp nodig hebt met specifieke codevoorbeelden of verdere details, laat het gerust weten!
provider: deepseek
model: deepseek-chat
Zeker, hier is een uitgebreide strategie voor geavanceerde data validatie en normalisatie voor jouw API-integraties:
## 1. Gelaagde Validatie-Architectuur
### Frontend Validatie (React)
```jsx
// hooks/useValidation.js
import { useState, useEffect } from 'react';
export const useValidation = (initialValue, rules) => {
const [value, setValue] = useState(initialValue);
const [errors, setErrors] = useState([]);
useEffect(() => {
const validationErrors = [];
rules.forEach(rule => {
const error = rule(value);
if (error) validationErrors.push(error);
});
setErrors(validationErrors);
}, [value, rules]);
return [value, setValue, errors, errors.length === 0];
};
// validators/customerValidators.js
export const customerValidators = {
email: (value) => {
if (!value) return 'E-mail is verplicht';
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) return 'Ongeldig e-mailadres';
return null;
},
phone: (value) => {
if (!value) return null; // Optioneel veld
const cleaned = value.replace(/[^\d+]/g, '');
if (cleaned.length < 10) return 'Telefoonnummer te kort';
if (!/^[\d+][\d\s-()]+$/.test(value)) return 'Ongeldig telefoonnummer';
return null;
},
name: (value) => {
if (!value) return 'Naam is verplicht';
if (value.length < 2) return 'Naam moet minimaal 2 karakters bevatten';
if (!/^[a-zA-Z\s\-']+$/.test(value)) return 'Naam bevat ongeldige karakters';
return null;
}
};
```
### Backend Validatie (Node.js)
```javascript
// middleware/validationMiddleware.js
const Joi = require('joi');
const customerSchema = Joi.object({
email: Joi.string().email().required(),
phone: Joi.string().pattern(/^[\d+][\d\s-()]{9,}$/).optional(),
firstName: Joi.string().min(2).max(50).pattern(/^[a-zA-Z\s\-']+$/).required(),
lastName: Joi.string().min(2).max(50).pattern(/^[a-zA-Z\s\-']+$/).required(),
address: Joi.object({
street: Joi.string().required(),
city: Joi.string().required(),
postalCode: Joi.string().pattern(/^[1-9][0-9]{3}[\s]?[A-Za-z]{2}$/).required(),
country: Joi.string().valid('NL', 'BE').required()
}).required()
});
const orderSchema = Joi.object({
items: Joi.array().items(
Joi.object({
productId: Joi.string().required(),
quantity: Joi.number().integer().min(1).max(100).required(),
price: Joi.number().precision(2).positive().required()
})
).min(1).required(),
currency: Joi.string().valid('EUR', 'USD').default('EUR'),
totalAmount: Joi.number().precision(2).positive().required()
});
exports.validateCustomer = (req, res, next) => {
const { error, value } = customerSchema.validate(req.body, {
abortEarly: false,
stripUnknown: true
});
if (error) {
return res.status(400).json({
error: 'Validatiefout',
details: error.details.map(detail => ({
field: detail.path.join('.'),
message: detail.message
}))
});
}
req.validatedData = value;
next();
};
```
## 2. Data Normalisatie Service
```javascript
// services/normalizationService.js
class NormalizationService {
static normalizePhone(phone) {
if (!phone) return null;
// Verwijder alle niet-numerieke karakters behalve +
let normalized = phone.replace(/[^\d+]/g, '');
// Voor Nederlandse nummers: +31 toevoegen indien nodig
if (normalized.startsWith('06')) {
normalized = '+31' + normalized.substring(1);
} else if (normalized.startsWith('0') && !normalized.startsWith('+')) {
normalized = '+31' + normalized.substring(1);
}
return normalized;
}
static normalizeEmail(email) {
if (!email) return null;
return email.toLowerCase().trim();
}
static normalizePostalCode(postalCode) {
if (!postalCode) return null;
// Verwijder spaties en zet om naar hoofdletters
let normalized = postalCode.replace(/\s/g, '').toUpperCase();
// Zorg voor consistent formaat: 1234AB
if (normalized.length === 6) {
normalized = normalized.substring(0, 4) + ' ' + normalized.substring(4);
}
return normalized;
}
static normalizeName(name) {
if (!name) return null;
// Kapitaliseer eerste letters van elke woord
return name
.toLowerCase()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
.trim();
}
static normalizeCustomerData(customerData) {
return {
...customerData,
email: this.normalizeEmail(customerData.email),
phone: this.normalizePhone(customerData.phone),
firstName: this.normalizeName(customerData.firstName),
lastName: this.normalizeName(customerData.lastName),
address: customerData.address ? {
...customerData.address,
postalCode: this.normalizePostalCode(customerData.address.postalCode),
city: this.normalizeName(customerData.address.city)
} : null
};
}
}
```
## 3. Stripe-specifieke Validatie
```javascript
// services/stripeValidationService.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
class StripeValidationService {
static async validatePaymentMethod(paymentMethodId, amount, currency = 'eur') {
try {
// Valideer payment method
const paymentMethod = await stripe.paymentMethods.retrieve(paymentMethodId);
if (!paymentMethod) {
throw new Error('Ongeldige betaalmethode');
}
// Valideer bedrag
if (amount <= 0) {
throw new Error('Bedrag moet groter zijn dan 0');
}
// Valideer valuta
const validCurrencies = ['eur', 'usd'];
if (!validCurrencies.includes(currency.toLowerCase())) {
throw new Error(`Ongeldige valuta: ${currency}`);
}
return {
isValid: true,
paymentMethod,
normalizedAmount: Math.round(amount * 100), // Convert to cents
normalizedCurrency: currency.toLowerCase()
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
static async createValidatedPaymentIntent(customerData, orderData) {
const validationResult = await this.validatePaymentMethod(
orderData.paymentMethodId,
orderData.totalAmount,
orderData.currency
);
if (!validationResult.isValid) {
throw new Error(`Betaling validatie mislukt: ${validationResult.error}`);
}
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: validationResult.normalizedAmount,
currency: validationResult.normalizedCurrency,
payment_method: orderData.paymentMethodId,
confirmation_method: 'manual',
confirm: false,
customer: customerData.stripeCustomerId,
metadata: {
order_id: orderData.orderId,
customer_email: customerData.email
}
});
return paymentIntent;
} catch (error) {
throw new Error(`Stripe betaling mislukt: ${error.message}`);
}
}
}
```
## 4. Twilio-specifieke Validatie
```javascript
// services/twilioValidationService.js
const twilio = require('twilio');
class TwilioValidationService {
static validatePhoneNumber(phoneNumber) {
const normalizedPhone = NormalizationService.normalizePhone(phoneNumber);
// Eenvoudige validatie voor Twilio
if (!normalizedPhone) {
return { isValid: false, error: 'Telefoonnummer is vereist' };
}
// Valideer E.164 formaat
const e164Regex = /^\+[1-9]\d{1,14}$/;
if (!e164Regex.test(normalizedPhone)) {
return { isValid: false, error: 'Telefoonnummer moet in E.164 formaat zijn' };
}
return {
isValid: true,
normalizedPhone,
countryCode: normalizedPhone.substring(1, 3)
};
}
static validateSMSText(text) {
if (!text || text.trim().length === 0) {
return { isValid: false, error: 'SMS tekst mag niet leeg zijn' };
}
if (text.length > 1600) {
return { isValid: false, error: 'SMS tekst mag maximaal 1600 karakters bevatten' };
}
return {
isValid: true,
normalizedText: text.trim(),
segmentCount: Math.ceil(text.length / 160)
};
}
}
```
## 5. Geïntegreerde Verwerkingspijplijn
```javascript
// controllers/orderController.js
const processOrder = async (req, res) => {
try {
// Stap 1: Basis validatie
const { error, value: rawData } = orderSchema.validate(req.body, {
abortEarly: false,
stripUnknown: true
});
if (error) {
return res.status(400).json({
error: 'Order validatie mislukt',
details: error.details
});
}
// Stap 2: Data normalisatie
const normalizedData = NormalizationService.normalizeCustomerData(rawData);
// Stap 3: Stripe validatie
const stripeValidation = await StripeValidationService.validatePaymentMethod(
normalizedData.paymentMethodId,
normalizedData.totalAmount,
normalizedData.currency
);
if (!stripeValidation.isValid) {
return res.status(400).json({
error: 'Betaling validatie mislukt',
details: stripeValidation.error
});
}
// Stap 4: Twilio validatie (indien van toepassing)
if (normalizedData.phone) {
const twilioValidation = TwilioValidationService.validatePhoneNumber(normalizedData.phone);
if (!twilioValidation.isValid) {
// Log de waarschuwing maar blokkeer niet de bestelling
console.warn(`Twilio validatie waarschuwing: ${twilioValidation.error}`);
}
}
// Stap 5: Verwerking
const paymentIntent = await StripeValidationService.createValidatedPaymentIntent(
normalizedData,
stripeValidation
);
// Stap 6: Response
res.json({
success: true,
orderId: generateOrderId(),
paymentIntentId: paymentIntent.id,
clientSecret: paymentIntent.client_secret,
normalizedData: normalizedData
});
} catch (error) {
console.error('Order verwerking mislukt:', error);
res.status(500).json({
error: 'Interne serverfout',
message: error.message
});
}
};
```
## 6. Monitoring en Logging
```javascript
// middleware/loggingMiddleware.js
const { createLogger, format, transports } = require('winston');
const validationLogger = createLogger({
level: 'info',
format: format.combine(
format.timestamp(),
format.json()
),
transports: [
new transports.File({ filename: 'logs/validation-errors.log' }),
new transports.File({ filename: 'logs/normalization-changes.log' })
]
});
exports.logValidation = (data, context) => {
validationLogger.info('Data validatie', {
timestamp: new Date().toISOString(),
context,
originalData: data.original,
normalizedData: data.normalized,
changes: data.changes
});
};
```
## Belangrijkste Voordelen van deze Strategie:
1. **Defensief Programmeren**: Elke laag heeft zijn eigen validatie
2. **Consistente Data**: Normalisatie zorgt voor uniforme gegevens
3. **Uitbreidbaar**: Eenvoudig nieuwe validators toe te voegen
4. **Foutpreventie**: Vangt problemen vroeg in het proces af
5. **Betere UX**: Duidelijke foutmeldingen voor gebruikers
Deze strategie minimaliseert fouten en zorgt voor consistente, betrouwbare dataverwerking in jouw platform.