# API Wrapper Service Overview ## Purpose This service is a Flask-based API wrapper for CreditFair partner and checkout APIs. It exposes configured HTTP endpoints, authenticates incoming requests, loads endpoint-specific schemas from S3, validates payloads, executes configured business rules and helper functions, persists data to MySQL, and returns schema-defined responses. The codebase is intentionally schema-driven. Most endpoint behavior is not hard-coded in Flask route functions. Instead, Python provides a reusable execution engine, while route definitions, authentication rules, validation schemas, response formats, rule blocks, function blocks, and persistence instructions are loaded from JSON files stored in S3. ## High-Level Runtime Flow 1. `app.py` creates the Flask app and registers dynamic routes through `Routes().main(app, app_name)`. 2. `routes.py` loads route configuration from the S3 path `api_wrapper/api/routes.json`. 3. Each configured route is mapped to the same dynamic handler. 4. A request enters `APIWrapper.main()` in `main.py`. 5. `authentication.py` validates the request domain, route auth requirements, Basic/JWT credentials, and optional IP whitelisting. 6. `main.py` selects the correct endpoint schema from S3. Merchant-level schema is preferred over category-level schema when available. 7. `schema_validation.py` validates the request body against the JSON schema defined for the endpoint. 8. `dry_run_function.py`, `helper_functions.py`, `operations.py`, and `rules_aggregator.py` execute configured pre-processing functions and business rules. 9. `data_persistence.py` executes configured persistence operations against MySQL. 10. `response/response_generation.py` resolves and returns the configured response body and HTTP status code. ## Entry Points ### `app.py` Initializes the Flask application, sets a generated `SECRET_KEY`, registers dynamic routes, applies response headers, and runs the app when started directly. The currently enabled app groups are: - `test1` - `mconnect` These names are used by `routes.py` to filter route definitions from the S3 route schema. ### `gunicorn.sh` Production/container startup script. It runs: ```bash gunicorn --workers 5 --worker-class gevent --timeout 120 --bind 0.0.0.0:5000 app:app ``` ### `Dockerfile` Builds a Python 3.10 slim image, installs system dependencies including PHP and `wkhtmltopdf`, installs Python requirements, copies the service, and starts it through `gunicorn.sh`. ## Configuration Runtime configuration is loaded from environment variables through `config.py` and direct `os.getenv()` calls. Important configuration areas: - Flask host and port: `HOST`, `PORT` - AWS/S3: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION_NAME`, `AWS_BUCKET` - MySQL: `MYSQL_HOST`, `MYSQL_DB`, `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_PORT` - CloudWatch logging: `CLOUDWATCH_ACCESS_KEY`, `CLOUDWATCH_SECRET_KEY` - External APIs: Karza, Pirimid, checkout/backend endpoints - Business constants: supported document types, document formats, electricity provider mappings The local `.env` file is not documented here because it can contain secrets. ## Dynamic Routing `routes.py` reads `api_wrapper/api/routes.json` from S3 using `SchemaLoad.read_schema()`. For each enabled app name, it extracts endpoint definitions and registers Flask routes dynamically. Each route uses the same generated handler, which delegates all request processing to `APIWrapper(request).main()`. Route definitions are expected to include at least: - endpoint path - HTTP method - authentication settings - optional IP whitelist flag Because routes are S3-backed, adding or changing an endpoint usually requires updating the route schema, not adding a new Flask function. ## Authentication `authentication.py` controls request authentication. The authentication schema is loaded from: ```text api_wrapper/authentication/authentication_schema.json ``` Authentication flow: 1. Determine the host from the `Host` header. 2. Verify that the host exists in the authentication schema. 3. Load route configuration to check whether the endpoint requires auth. 4. Support Basic authentication backed by database-stored credentials. 5. Support JWT authentication using schema-defined token headers, decode keys, algorithms, and verification queries. 6. Optionally validate request IP against merchant/domain whitelist configuration. 7. Store request, merchant, and token context in Flask `g` through `helper_functions.set_data()`. For unauthenticated admin-style requests, the service still prepares request context and returns domain, endpoint, method, and source metadata. ## Schema Selection `main.py` selects endpoint behavior schema from S3 after authentication. Schema path selection: - Admin requests use: ```text api_wrapper/{source}/{domain}/category/default/default.json ``` - Merchant-level schema candidate: ```text api_wrapper/merchant/{merchant_id}/{domain}/{merchant_name}.json ``` - Category-level schema candidate: ```text api_wrapper/category/{category_id}/{domain}/{category_name}.json ``` Merchant-level schema is selected first when it exists. If it does not exist, the service falls back to category-level schema. The selected schema controls validation, functions, rules, persistence, and response generation for the request. ## Request Processing Pipeline `APIWrapper.main()` is the orchestration layer. The main pipeline is: 1. Log request payload. 2. Authenticate request. 3. Build selected S3 schema path. 4. Load selected schema body. 5. Create a response controller for the current endpoint and method. 6. Execute `functions.init` from the schema. 7. Validate request body with JSON Schema. 8. Execute request rules. 9. Execute remaining configured functions. 10. Execute persistence operations. 11. Generate response for the final `cf_code`. The service uses internal `cf_code` values such as `CF200`, `CF300`, and `CF500` to choose the correct response block from the endpoint schema. ## Validation `schema_validation.py` validates the request body against the endpoint schema: ```text paths.{endpoint}.{method}.requestBody.content ``` It uses the `jsonschema` package. Validation errors can return schema-defined messages and return codes. The selected error response is stored in Flask `g` for response generation. ## Rules And Functions Rules and functions are schema-defined execution blocks. ### Rules `rules_aggregator.py` reads: ```text paths.{endpoint}.{method}.requestBody.rules.data ``` It evaluates nested conditions using `helper_functions.condition_check()`. When a matching branch contains an operation, it delegates execution to `Operations.perform_operation()`. Supported condition styles include: - `equals` - `notEquals` - `isNotNull` - `greaterThan` - `lesserThan` - `in` ### Functions `dry_run_function.py` reads: ```text paths.{endpoint}.{method}.functions ``` The `init` function block runs before validation. Other function blocks run after rules pass. Function execution supports nested conditions and operation blocks. ## Operation Engine `operations.py` is the generic operation executor used by rules, functions, response actions, and persistence helpers. Supported operation types include: - `returnResponse` - `setData` - `returnData` - `mapData` - `length` - `concat` - `query` - `s3Upload` - `calculate` - `conversion` - `apiCall` - `iterate` - `date_calc` - `generateToken` Most operation values are resolved through `KeyResolver`, so schema values can refer to request fields, environment variables, stored state, auth headers, token payloads, or component/static functions. ## Key Resolution And Request State `key_resolver.py` resolves dynamic values used in schemas. Supported key sources: - `$request.*`: incoming request body or query params - `$env.*`: environment variables - `$auth.*`: request headers - `$token.*`: decoded JWT payload - `$stateKey` style references: data stored in Flask `g` - `request_id`: generated UUID - `datetime.CUR_TIMESTAMP`: current timestamp string - `function->arg1,arg2`: component/static function execution `helper_functions.py` stores and retrieves request-scoped state through Flask `g`. ## Persistence And Database Access Database access is MySQL-based. Key files: - `db/database.py`: singleton-style MySQL connection pool and context manager - `db/query.py`: query builder and execution helper - `db/database_operations.py`: executes schema-defined DB operations - `db/direct_query.py`: shared raw SQL snippets - `data_persistence.py`: runs endpoint persistence blocks from schema Persistence configuration is read from: ```text paths.{endpoint}.{method}.persistence ``` The persistence layer supports insert, update, select, and raw SQL operations depending on the operation dictionary. Inserted auto IDs can be stored in request state for later operations or response generation. ## Response Generation `response/response_generation.py` reads response configuration from: ```text paths.{endpoint}.{method}.responses.{cf_code} ``` It resolves response values using `KeyResolver` and `Components`, stores the final response in Flask `g`, executes optional response actions, and returns: ```python (content, status_code) ``` Response content and status codes are schema-controlled. ## External Integrations ### S3 `utilities/schema_loader.py` reads route, auth, and endpoint schemas from S3. It also uploads base64-decoded content to S3 for schema-defined upload operations. ### Karza `integrations/karza.py` integrates with Karza electricity bill verification. It can: - call the Karza electricity API - save validation responses in MySQL - generate a PDF validation report using Jinja2 and `pdfkit` - upload the generated report to S3 - insert the generated report into `consumer_application_files` `static_functions.py` also contains Karza-related helper logic for Aadhaar masking and electricity validation orchestration. ### Pirimid `static_functions.py` includes `uploadPirimidDocument()`, which uploads password-protected PDF bank documents to Pirimid and records the tracking response in MySQL. ### PHP Encryption Helpers `encrypt_decrypt.py` shells out to PHP scripts in `static/php/` for AES-128-CBC encryption and decryption: - `static/php/enc.php` - `static/php/dec.php` These helpers are exposed through schema functions/components as `encrypt` and `decrypt`. ## Logging `logger_module/package_logger.py` prints logs locally and sends them to AWS CloudWatch through a custom logging handler. Current logger defaults: - log group: `/aws/api_wrapper` - log stream: `mconnect` ## Important Files | File | Responsibility | | --- | --- | | `app.py` | Flask app creation, dynamic route registration, CORS-like headers | | `routes.py` | Loads S3 route schema and registers endpoints | | `main.py` | Main request orchestration pipeline | | `authentication.py` | Host, route, Basic/JWT, merchant, and IP whitelist authentication | | `schema_validation.py` | JSON Schema request validation | | `rules_aggregator.py` | Schema-driven conditional business rule execution | | `dry_run_function.py` | Schema-driven pre/post function execution | | `operations.py` | Generic operation execution engine | | `key_resolver.py` | Resolves `$request`, `$env`, `$auth`, `$token`, state, and component references | | `components.py` | Executes built-in and static component functions | | `static_functions.py` | Business helper functions used by schemas | | `data_persistence.py` | Executes schema-defined persistence blocks | | `db/database.py` | MySQL connection pool | | `db/query.py` | Query builder and query executor | | `db/database_operations.py` | Converts operation dictionaries into database calls | | `utilities/schema_loader.py` | S3 schema read/check/upload helpers | | `response/response_generation.py` | Builds schema-defined API responses | | `integrations/karza.py` | Karza electricity verification and report generation | | `encrypt_decrypt.py` | Python wrapper around PHP encrypt/decrypt scripts | | `config.py` | Environment-backed config and constants | | `Dockerfile` | Container build definition | | `gunicorn.sh` | Production startup command | ## Schema Dependency This repository alone does not contain the full API contract. The behavior of each endpoint depends heavily on S3 JSON schemas: - `api_wrapper/api/routes.json` - `api_wrapper/authentication/authentication_schema.json` - merchant-level endpoint schemas - category-level endpoint schemas - admin endpoint schemas To fully document this service, these S3 schemas should be documented alongside the Python execution engine. ## Operational Notes - The service expects AWS, MySQL, Karza, Pirimid, CloudWatch, and PHP runtime dependencies to be configured correctly. - Request-specific state is stored in Flask `g`, so values are scoped to the current request. - Route behavior can change without Python code changes when S3 schemas are updated. - Adding a new endpoint generally means updating S3 route/auth/schema files and only adding Python code when a new operation or static function is needed. - Some operations call external APIs or execute raw SQL, so schema changes should be reviewed with the same care as code changes.