GitHunt
NI

NishanthMuruganantham/dynamic-formula-execution-api

A FastAPI-based API for evaluating dynamic mathematical expressions on datasets. It is developed for a coding Challenge conducted by 'doselect', a collaborative and technology independent hiring tool for companies, for Cognida.ai

Dynamic Formula Execution API ๐Ÿš€

Overview ๐Ÿ“

The Dynamic Formula Execution API is a Python-based API that interprets and executes complex mathematical formulas on structured datasets. It supports formula chaining, validation, and real-time calculation of values across various data types, such as numbers, strings, booleans, dates, and currencies. The solution ensures efficient performance with sub-second response times, making it suitable for large datasets and complex workflows.

This API was developed as part of a coding challenge to demonstrate key skills in Python and API development.

Why FastAPI? ๐ŸŽ๏ธ

FastAPI was selected for the following reasons:

  • โšก Performance: FastAPI is one of the fastest Python web frameworks, built on top of ASGI and supports async programming, which helps to efficiently handle I/O-bound operations.
  • ๐Ÿ’ผ Ease of Use: FastAPI has automatic request validation, serialization, and generation of OpenAPI documentation, which helps to reduce boilerplate code and improve development speed.

Requirements ๐Ÿ“ฆ

  • Python 3.8+ ๐Ÿ
  • Pydantic: For data validation. ๐Ÿ› ๏ธ
  • FastAPI: For building the API. ๐Ÿšง
  • Uvicorn: For serving the application. ๐ŸŒ
  • re: For regex operations in currency/percentage parsing. ๐Ÿ’ฒ

Project Structure ๐Ÿ—‚๏ธ

.
โ”œโ”€โ”€ src
โ”‚   โ”œโ”€โ”€ app.py              # ๐Ÿ’ป it houses the core FastAPI app
โ”‚   โ”œโ”€โ”€ logic.py            # ๐Ÿงฌ it houses all the logic associated with the API which involves Formula validation, execution, etc.,
โ”‚   โ”œโ”€โ”€ models.py           # ๐Ÿ“Š Contains the pydantic models needed such as Data, Formula, Inputs, and ResultBody models
โ”‚   โ””โ”€โ”€ routes.py           # ๐Ÿ”— Contains the route function for the given endpoint /api/execute-formula
โ”œโ”€โ”€ tests
โ”‚   โ””โ”€โ”€ ErrorTests.py       # โŒ Pytests for validating Exception cases
โ”‚   โ””โ”€โ”€ SuccessTests.py     # โœ… Pytests for validating expected success scenarios
โ”œโ”€โ”€ .gitignore              # ๐Ÿ™ˆ specifies files and directories Git should ignore
โ”œโ”€โ”€ main.py                 # ๐Ÿš€ runs the FastAPI app with live reloading using Uvicorn server 
โ””โ”€โ”€ pyproject.toml          # ๐Ÿงฉ Project metadata and configuration settings
โ”œโ”€โ”€ README.md               # ๐Ÿ“„ This file
โ”œโ”€โ”€ requirements.txt        # ๐Ÿ“œ Dependencies for the project
โ”œโ”€โ”€ vercel.json             # โœˆ๏ธ Contains the vercel deployment configuration

Setup Instructions ๐Ÿ› ๏ธ

Prerequisites

Before setting up the project, ensure that the following dependencies are installed:

  • Python 3.8+
  • FastAPI
  • Pydantic
  • pytest (for running tests)

Installation

  1. Clone the Repository:

    git clone https://github.com/NishanthMuruganantham/dynamic-formula-execution-api.git
    cd dynamic-formula-execution-api
  2. Create a Virtual Environment:

    python3 -m venv venv
    source venv/bin/activate  # For Windows: venv\Scripts\activate
  3. Install Dependencies:

    Use pip to install the required dependencies from requirements.txt:

    pip install -r requirements.txt
  4. Run Tests:

    Execute the unit tests to ensure everything is set up correctly:

    pytest
  5. Run the Server:

    Running the server locally:

    python main.py

API Endpoints ๐ŸŒ

The API exposes endpoints to execute formulas dynamically using FastAPI. The main endpoint accepts the dataset and the list of formulas to be executed.

Endpoint: /api/execute-formula

  • Method: POST
  • Description: Executes the provided formulas on the given data and returns the results.

Usage ๐Ÿ“ˆ

To use the API, you can run the FastAPI server locally:

python main.py

This will start the API, and you can use tools like Postman or cURL to send requests to the /execute-formulas endpoint.

Example - 1 | Simple Addition

Request Payload:

{
    "data": [
        {
            "id": 1,
            "fieldA": 10
        },
        {
            "id": 2,
            "fieldA": 20
        }
    ],
    "formulas": [
        {
            "outputVar": "result",
            "expression": "fieldA + 10",
            "inputs": [
                {
                    "varName": "fieldA",
                    "varType": "number"
                }
            ]
        }
    ]
}

Response:

{
    "results": {
        "result": [
            20,
            30
        ]
    },
    "message": "The formulas were executed successfully.",
    "status": "success"
}

Example - 2 | Formula Chaining

Request Payload:

{
    "data": [
        {
            "id": 1,
            "fieldA": 10,
            "fieldB": 2
        },
        {
            "id": 2,
            "fieldA": 20,
            "fieldB": 3
        }
    ],
    "formulas": [
        {
            "outputVar": "sumResult",
            "expression": "fieldA + fieldB",
            "inputs": [
                {
                    "varName": "fieldA",
                    "varType": "number"
                },
                {
                    "varName": "fieldB",
                    "varType": "number"
                }
            ]
        },
        {
            "outputVar": "finalResult",
            "expression": "sumResult * 2 + fieldA",
            "inputs": [
                {
                    "varName": "sumResult",
                    "varType": "number"
                },
                {
                    "varName": "fieldA",
                    "varType": "number"
                }
            ]
        }
    ]
}

Response Example:

{
    "results": {
        "sumResult": [
            12,
            23
        ],
        "finalResult": [
            34,
            66
        ]
    },
    "message": "The formulas were executed successfully.",
    "status": "success"
}

Example - 3 | Sales Revenue

Request Payload:

{
    "data": [
        {
            "id": 1,
            "product": "Laptop",
            "unitPrice": "1000 USD",
            "quantity": 5,
            "discount": "10%"
        },
        {
            "id": 2,
            "product": "Smartphone",
            "unitPrice": "500 USD",
            "quantity": 10,
            "discount": "5%"
        },
        {
            "id": 3,
            "product": "Tablet",
            "unitPrice": "300 USD",
            "quantity": 15,
            "discount": "0%"
        }
    ],
    "formulas": [
        {
            "outputVar": "revenue",
            "expression": "((unitPrice * quantity) - (unitPrice * quantity * (discount / 100)))",
            "inputs": [
                {
                    "varName": "unitPrice",
                    "varType": "currency"
                },
                {
                    "varName": "quantity",
                    "varType": "number"
                },
                {
                    "varName": "discount",
                    "varType": "percentage"
                }
            ]
        }
    ]
}

Response Example:

{
    "results": {
        "revenue": [
            4500,
            4750,
            4500
        ]
    },
    "message": "The formulas were executed successfully.",
    "status": "success"
}

Public Deployment ๐ŸŒŽ

The Dynamic Formula Execution API has been publicly deployed and can be accessed via Vercel.

Live API URL: https://dynamic-formula-execution-api.vercel.app

This live deployment allows users to directly interact with the API for formula execution. Access it from Postman to perform POST calls.

Features ๐ŸŒŸ

  • Dynamic Expression Evaluation: Supports dynamic evaluation of mathematical expressions based on input variables.
  • Formula Chaining: Formulas can depend on the output of other formulas, allowing for complex workflows.
  • Topological Sorting: Ensures that formulas are executed in the correct order based on their dependencies.
  • Error Handling: Provides robust error handling for invalid expressions and missing input variables.
  • Extensible Framework: Easily extendable to support additional data types or more complex formula logic.

Key Components ๐Ÿ”‘

FormulaExecutor Class

The FormulaExecutor class is responsible for processing a list of formulas on the dataset. It first sorts the formulas based on their dependencies using topological sorting and then evaluates each formula dynamically.

Key Methods:

  • perform_formula_execution: Executes all formulas in the correct order and returns the results.
  • _perform_topogical_sort_for_formulas: Sorts formulas based on dependencies.
  • _execute_formula_for_given_data: Safely evaluates a single formula on a given dataset.

Models ๐Ÿ“‹

  • Data: Represents the dataset structure.
  • Formula: Defines each formula's expression and input-output variables.
  • Inputs: Represents input variables for formulas.
  • ResultBody: Holds the results of formula executions.
  1. ๐Ÿ Hackathon Link - https://hackathon-app.doselect.com/1464/problem/1poryb
  2. ๐Ÿ’ป Vercel Hosted API domain - https://dynamic-formula-execution-api.vercel.app
  3. ๐Ÿ“œ Swagger UI - An interactive documentation interface provided by FastAPI - https://dynamic-formula-execution-api.vercel.app/docs
  4. ReDoc - Another option for API documentation, offering a different interface. - https://dynamic-formula-execution-api.vercel.app/redoc