أدلة التكامل
أدلة خطوة بخطوة لدمج Qawaid في مشروعك الحالي.
.NET / ASP.NET Core
Node.js / Express
Python / Django
React / Next.js
.NET / ASP.NET Core
Prerequisites
Install the Qawaid SDK via NuGet
Add the Qawaid SDK package to your project.
dotnet add package Qawaid.Sdk
# For gRPC support (optional):
dotnet add package Qawaid.Sdk.GrpcConfigure Dependency Injection
Register the Qawaid client in your Program.cs or Startup.cs.
// Program.cs
using Qawaid.Sdk;
var builder = WebApplication.CreateBuilder(args);
// Add Qawaid client with configuration
builder.Services.AddQawaid(options =>
{
options.BaseUrl = "https://api.qawaid.ai";
options.ApiKey = builder.Configuration["Qawaid:ApiKey"];
options.TenantId = builder.Configuration["Qawaid:TenantId"];
options.EnableRetry = true;
options.MaxRetryAttempts = 3;
});
var app = builder.Build();Inject and Use the Client
Inject the IQawaidClient into your controllers or services.
using Qawaid.Sdk;
public class LoanController : ControllerBase
{
private readonly IQawaidClient _qawaid;
public LoanController(IQawaidClient qawaid)
{
_qawaid = qawaid;
}
[HttpPost("apply")]
public async Task<IActionResult> ApplyForLoan(LoanApplication model)
{
var result = await _qawaid.Validation.ValidateAsync(
"loan-application",
new
{
applicant = new { age = model.Age, income = model.Income },
loan = new { amount = model.Amount, term = model.Term }
});
if (!result.IsValid)
{
return BadRequest(new
{
errors = result.Failures.Select(f => new
{
field = f.FieldPath,
message = f.Message,
code = f.ErrorCode
})
});
}
// Process the valid loan application...
return Ok(new { status = "approved" });
}
}Add Configuration to appsettings.json
Store your API credentials securely in configuration.
{
"Qawaid": {
"ApiKey": "qw_live_your_api_key_here",
"TenantId": "your-tenant-id"
}
}Node.js / Express
Prerequisites
Install Dependencies
No SDK needed -- Qawaid uses a simple fetch-based approach.
# No additional packages required -- uses built-in fetch (Node 18+)
# For older Node.js versions:
npm install node-fetchCreate a Qawaid Client Helper
Create a reusable client module for making API calls.
// lib/qawaid.js
const QAWAID_BASE_URL = process.env.QAWAID_BASE_URL || "https://api.qawaid.ai";
const QAWAID_API_KEY = process.env.QAWAID_API_KEY;
const QAWAID_TENANT_ID = process.env.QAWAID_TENANT_ID;
class QawaidClient {
constructor(baseUrl, apiKey, tenantId) {
this.baseUrl = baseUrl;
this.headers = {
"X-Api-Key": apiKey,
"X-Tenant-Id": tenantId,
"Content-Type": "application/json",
};
}
async validate(context, payload) {
const res = await fetch(`${this.baseUrl}/api/v1/validation/validate`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ context, payload }),
});
if (!res.ok) throw new Error(`Qawaid error: ${res.status}`);
return res.json();
}
async validateBatch(context, items) {
const res = await fetch(`${this.baseUrl}/api/v1/validation/validate-batch`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ context, items }),
});
if (!res.ok) throw new Error(`Qawaid error: ${res.status}`);
return res.json();
}
async getRules(page = 1, pageSize = 20) {
const res = await fetch(
`${this.baseUrl}/api/v1/rules?page=${page}&pageSize=${pageSize}`,
{ headers: this.headers }
);
if (!res.ok) throw new Error(`Qawaid error: ${res.status}`);
return res.json();
}
}
module.exports = new QawaidClient(
QAWAID_BASE_URL,
QAWAID_API_KEY,
QAWAID_TENANT_ID
);Create Express Validation Middleware
Add a reusable middleware that validates request bodies against Qawaid rules.
// middleware/qawaidValidation.js
const qawaid = require("../lib/qawaid");
function validateWith(context) {
return async (req, res, next) => {
try {
const result = await qawaid.validate(context, req.body);
if (!result.isValid) {
return res.status(422).json({
message: "Validation failed",
errors: result.failures.map((f) => ({
field: f.fieldPath,
message: f.message,
code: f.errorCode,
})),
});
}
// Attach result to request for downstream use
req.validationResult = result;
next();
} catch (err) {
console.error("Qawaid validation error:", err);
next(err);
}
};
}
module.exports = { validateWith };Use the Middleware in Your Routes
Apply the validation middleware to your Express routes.
// routes/loans.js
const express = require("express");
const router = express.Router();
const { validateWith } = require("../middleware/qawaidValidation");
router.post("/apply", validateWith("loan-application"), async (req, res) => {
// If we reach here, validation passed
const application = req.body;
// Process the valid loan application...
res.json({
status: "approved",
rulesEvaluated: req.validationResult.totalRulesEvaluated,
});
});
module.exports = router;Python / Django
Prerequisites
Install the requests library
If not already installed, add the requests HTTP library.
pip install requestsCreate a QawaidClient Class
Build a reusable client for your Django project.
# qawaid/client.py
import requests
from django.conf import settings
class QawaidClient:
def __init__(self):
self.base_url = getattr(settings, "QAWAID_BASE_URL", "https://api.qawaid.ai")
self.headers = {
"X-Api-Key": settings.QAWAID_API_KEY,
"X-Tenant-Id": settings.QAWAID_TENANT_ID,
"Content-Type": "application/json",
}
def validate(self, context: str, payload: dict) -> dict:
"""Validate a payload against all published rules in the given context."""
response = requests.post(
f"{self.base_url}/api/v1/validation/validate",
headers=self.headers,
json={"context": context, "payload": payload},
timeout=10,
)
response.raise_for_status()
return response.json()
def validate_batch(self, context: str, items: list[dict]) -> dict:
"""Validate multiple payloads in a single request."""
response = requests.post(
f"{self.base_url}/api/v1/validation/validate-batch",
headers=self.headers,
json={"context": context, "items": items},
timeout=30,
)
response.raise_for_status()
return response.json()
def get_rules(self, page: int = 1, page_size: int = 20) -> dict:
"""List all rules with pagination."""
response = requests.get(
f"{self.base_url}/api/v1/rules",
headers=self.headers,
params={"page": page, "pageSize": page_size},
timeout=10,
)
response.raise_for_status()
return response.json()
# Singleton instance
qawaid = QawaidClient()Create Django Middleware
Add middleware that validates incoming POST/PUT requests automatically.
# qawaid/middleware.py
import json
import logging
from django.http import JsonResponse
from .client import qawaid
logger = logging.getLogger(__name__)
# Map URL patterns to Qawaid contexts
VALIDATION_ROUTES = {
"/api/loans/apply/": "loan-application",
"/api/orders/create/": "order-validation",
"/api/customers/register/": "kyc-check",
}
class QawaidValidationMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.method in ("POST", "PUT") and request.path in VALIDATION_ROUTES:
context = VALIDATION_ROUTES[request.path]
try:
body = json.loads(request.body)
result = qawaid.validate(context, body)
if not result["isValid"]:
return JsonResponse(
{
"message": "Validation failed",
"errors": [
{
"field": f["fieldPath"],
"message": f["message"],
"code": f["errorCode"],
}
for f in result["failures"]
],
},
status=422,
)
# Store result on request for views to use
request.qawaid_result = result
except Exception as e:
logger.error(f"Qawaid validation error: {e}")
# Fail open -- allow request through on error
pass
return self.get_response(request)Configure Django Settings
Add Qawaid settings and enable the middleware.
# settings.py
# Qawaid configuration
QAWAID_BASE_URL = "https://api.qawaid.ai"
QAWAID_API_KEY = env("QAWAID_API_KEY") # Use django-environ or os.environ
QAWAID_TENANT_ID = env("QAWAID_TENANT_ID")
# Add middleware (place after AuthenticationMiddleware)
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"qawaid.middleware.QawaidValidationMiddleware", # <-- Add here
"django.contrib.messages.middleware.MessageMiddleware",
]React / Next.js
Prerequisites
Create an API Route Proxy
Keep your API key server-side by creating a Next.js route handler.
// app/api/validate/route.ts
import { NextRequest, NextResponse } from "next/server";
const QAWAID_BASE_URL = process.env.QAWAID_BASE_URL!;
const QAWAID_API_KEY = process.env.QAWAID_API_KEY!;
const QAWAID_TENANT_ID = process.env.QAWAID_TENANT_ID!;
export async function POST(request: NextRequest) {
const body = await request.json();
const response = await fetch(
`${QAWAID_BASE_URL}/api/v1/validation/validate`,
{
method: "POST",
headers: {
"X-Api-Key": QAWAID_API_KEY,
"X-Tenant-Id": QAWAID_TENANT_ID,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const data = await response.json();
return NextResponse.json(data, { status: response.status });
}Create a Client-Side Validation Hook
Build a reusable React hook for form validation.
// hooks/useQawaidValidation.ts
"use client";
import { useState, useCallback } from "react";
interface ValidationFailure {
ruleCode: string;
ruleName: string;
severity: string;
message: string;
errorCode: string;
fieldPath: string;
}
interface ValidationResult {
isValid: boolean;
totalRulesEvaluated: number;
failures: ValidationFailure[];
executionTimeMs: number;
}
export function useQawaidValidation() {
const [isValidating, setIsValidating] = useState(false);
const [result, setResult] = useState<ValidationResult | null>(null);
const [error, setError] = useState<string | null>(null);
const validate = useCallback(
async (context: string, payload: Record<string, unknown>) => {
setIsValidating(true);
setError(null);
setResult(null);
try {
const res = await fetch("/api/validate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ context, payload }),
});
const data: ValidationResult = await res.json();
setResult(data);
return data;
} catch (err) {
const message = err instanceof Error ? err.message : "Validation failed";
setError(message);
return null;
} finally {
setIsValidating(false);
}
},
[]
);
const getFieldError = useCallback(
(fieldPath: string): string | undefined => {
return result?.failures.find((f) => f.fieldPath === fieldPath)?.message;
},
[result]
);
return { validate, isValidating, result, error, getFieldError };
}Build a Validated Form Component
Use the hook in a real form with field-level error display.
// components/LoanApplicationForm.tsx
"use client";
import { useState } from "react";
import { useQawaidValidation } from "@/hooks/useQawaidValidation";
export function LoanApplicationForm() {
const { validate, isValidating, result, getFieldError } =
useQawaidValidation();
const [form, setForm] = useState({
age: "",
income: "",
loanAmount: "",
loanTerm: "30",
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const validationResult = await validate("loan-application", {
applicant: {
age: Number(form.age),
income: Number(form.income),
},
loan: {
amount: Number(form.loanAmount),
term: Number(form.loanTerm),
},
});
if (validationResult?.isValid) {
// Submit the form to your backend
console.log("Form is valid, submitting...");
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4 max-w-md">
<div>
<label className="block text-sm font-medium mb-1">Age</label>
<input
type="number"
value={form.age}
onChange={(e) => setForm({ ...form, age: e.target.value })}
className="w-full border rounded-lg px-3 py-2"
/>
{getFieldError("applicant.age") && (
<p className="text-sm text-red-500 mt-1">
{getFieldError("applicant.age")}
</p>
)}
</div>
<div>
<label className="block text-sm font-medium mb-1">Annual Income</label>
<input
type="number"
value={form.income}
onChange={(e) => setForm({ ...form, income: e.target.value })}
className="w-full border rounded-lg px-3 py-2"
/>
{getFieldError("applicant.income") && (
<p className="text-sm text-red-500 mt-1">
{getFieldError("applicant.income")}
</p>
)}
</div>
<div>
<label className="block text-sm font-medium mb-1">Loan Amount</label>
<input
type="number"
value={form.loanAmount}
onChange={(e) => setForm({ ...form, loanAmount: e.target.value })}
className="w-full border rounded-lg px-3 py-2"
/>
{getFieldError("loan.amount") && (
<p className="text-sm text-red-500 mt-1">
{getFieldError("loan.amount")}
</p>
)}
</div>
<button
type="submit"
disabled={isValidating}
className="w-full bg-primary text-white rounded-lg px-4 py-2 font-medium disabled:opacity-50"
>
{isValidating ? "Validating..." : "Apply for Loan"}
</button>
{result && !result.isValid && (
<div className="p-3 bg-red-50 dark:bg-red-950/20 border border-red-200 dark:border-red-800 rounded-lg">
<p className="text-sm font-medium text-red-800 dark:text-red-300">
{result.failures.length} validation error(s) found
</p>
</div>
)}
{result?.isValid && (
<div className="p-3 bg-green-50 dark:bg-green-950/20 border border-green-200 dark:border-green-800 rounded-lg">
<p className="text-sm font-medium text-green-800 dark:text-green-300">
All {result.totalRulesEvaluated} rules passed
</p>
</div>
)}
</form>
);
}Add Environment Variables
Configure your .env.local with the required environment variables.
# .env.local
QAWAID_BASE_URL=https://api.qawaid.ai
QAWAID_API_KEY=qw_live_your_api_key_here
QAWAID_TENANT_ID=your-tenant-idبحاجة لمساعدة أخرى؟
Qawaid يعمل مع أي لغة تدعم HTTP. تحقق من مرجع API للتفاصيل الكاملة.