العودة إلى التوثيق
أدلة التكامل

أدلة التكامل

أدلة خطوة بخطوة لدمج Qawaid في مشروعك الحالي.

C#

.NET / ASP.NET Core

Prerequisites

.NET 8.0 SDK or later
An existing ASP.NET Core web application
A Qawaid account with an API key
1

Install the Qawaid SDK via NuGet

Add the Qawaid SDK package to your project.

bash
dotnet add package Qawaid.Sdk
# For gRPC support (optional):
dotnet add package Qawaid.Sdk.Grpc
2

Configure Dependency Injection

Register the Qawaid client in your Program.cs or Startup.cs.

csharp
// 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();
3

Inject and Use the Client

Inject the IQawaidClient into your controllers or services.

csharp
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" });
    }
}
4

Add Configuration to appsettings.json

Store your API credentials securely in configuration.

json
{
  "Qawaid": {
    "ApiKey": "qw_live_your_api_key_here",
    "TenantId": "your-tenant-id"
  }
}
JS

Node.js / Express

Prerequisites

Node.js 18+ with npm or yarn
An existing Express application
A Qawaid account with an API key
1

Install Dependencies

No SDK needed -- Qawaid uses a simple fetch-based approach.

bash
# No additional packages required -- uses built-in fetch (Node 18+)
# For older Node.js versions:
npm install node-fetch
2

Create a Qawaid Client Helper

Create a reusable client module for making API calls.

javascript
// 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
);
3

Create Express Validation Middleware

Add a reusable middleware that validates request bodies against Qawaid rules.

javascript
// 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 };
4

Use the Middleware in Your Routes

Apply the validation middleware to your Express routes.

javascript
// 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;
PY

Python / Django

Prerequisites

Python 3.10+
An existing Django project
A Qawaid account with an API key
requests library installed
1

Install the requests library

If not already installed, add the requests HTTP library.

bash
pip install requests
2

Create a QawaidClient Class

Build a reusable client for your Django project.

python
# 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()
3

Create Django Middleware

Add middleware that validates incoming POST/PUT requests automatically.

python
# 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)
4

Configure Django Settings

Add Qawaid settings and enable the middleware.

python
# 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",
]
TSX

React / Next.js

Prerequisites

Next.js 14+ with App Router
React 18+
A Qawaid account with an API key
1

Create an API Route Proxy

Keep your API key server-side by creating a Next.js route handler.

typescript
// 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 });
}
2

Create a Client-Side Validation Hook

Build a reusable React hook for form validation.

typescript
// 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 };
}
3

Build a Validated Form Component

Use the hook in a real form with field-level error display.

typescript
// 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>
  );
}
4

Add Environment Variables

Configure your .env.local with the required environment variables.

bash
# .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 للتفاصيل الكاملة.

Qawaid — Business Rules Engine for Regulated Industries