Leveraging FastAPI for Building Secure and High-Performance Banking APIs
Explore the importance of FastAPI for developing banking APIs and how it can empower financial institutions to deliver efficient and secure services to their customers.
Join the DZone community and get the full member experience.
Join For FreeIn today's fast-paced digital world, the banking industry relies heavily on robust and secure APIs to deliver seamless services to customers. FastAPI, a modern web framework for building APIs with Python, has gained significant popularity due to its exceptional performance, scalability, and ease of development. In this blog post, we will explore the importance of FastAPI for developing banking APIs and how it can empower financial institutions to deliver efficient and secure services to their customers also discuss the implementation of automated test cases using the BDD framework.
- Unmatched Performance: FastAPI is built on top of Starlette, a high-performance asynchronous framework. It leverages Python's asynchronous capabilities to handle multiple requests concurrently, resulting in blazing-fast response times. For banking APIs that require quick response times, FastAPI ensures that transactions, queries, and account information can be retrieved swiftly, providing customers with an excellent user experience.
- Type Safety and Documentation: FastAPI's strong typing system, powered by Pydantic, allows developers to define clear data models and request/response schemas. This type of safety ensures that the data passed to and from the API is accurate and consistent. Additionally, FastAPI generates interactive and automatically documented APIs based on the defined models, making it easier for developers and other stakeholders to understand and consume the API.
- Security and Authentication: Banking APIs handle sensitive customer data, and security is of utmost importance. FastAPI provides built-in security features such as OAuth2 authentication, token validation, and request validation, enabling developers to implement robust security measures to protect customer information. Furthermore, FastAPI seamlessly integrates with other security frameworks and tools, allowing the implementation of various authentication and authorization mechanisms, including two-factor authentication and encryption, to meet the stringent security requirements of the banking industry.
- Scalability and Extensibility: FastAPI's asynchronous architecture enables horizontal scaling, allowing banking APIs to handle a large volume of concurrent requests. Financial institutions can easily scale their API infrastructure based on user demand without sacrificing performance. Additionally, FastAPI's modular design and compatibility with other Python libraries provide developers with the flexibility to extend functionality by integrating with existing banking systems, databases, or third-party services.
- Automated Testing and Debugging: FastAPI encourages and facilitates automated testing with tools like
pytest
andpytest-bdd
. These testing frameworks enable developers to write comprehensive tests, ensuring the correctness and stability of the API. FastAPI's integration with the Swagger UI and ReDoc documentation tools further simplifies testing and debugging by providing an interactive interface to explore and validate API endpoints.
Here's an example of a parameterized FastAPI code that creates a banking REST API to connect to a SQL Server database, extract account summary and user details, and return the JSON response. The parameter values are passed using a separate configuration file. Let's go step by step.
First, create a configuration file named config.ini
with the following content:
[SQLServer]
server = your_server_name
database = your_database_name
username = your_username
password = your_password
driver = {ODBC Driver 17 for SQL Server}
Next, install the required dependencies by running pip install fastapi pydantic pyodbc python-dotenv
.
from fastapi import FastAPI
from pydantic import BaseModel
import pyodbc
from dotenv import load_dotenv
import os
# Load configuration from the .env file
load_dotenv(".env")
# Define the FastAPI app
app = FastAPI()
# Read configuration from the environment variables or use default values
server = os.getenv("SERVER", "your_server_name")
database = os.getenv("DATABASE", "your_database_name")
username = os.getenv("USERNAME", "your_username")
password = os.getenv("PASSWORD", "your_password")
driver = os.getenv("DRIVER", "{ODBC Driver 17 for SQL Server}")
# Establish a database connection
conn = pyodbc.connect(f"DRIVER={driver};SERVER={server};DATABASE={database};UID={username};PWD={password}")
# Account model
class AccountSummary(BaseModel):
account_number: str
balance: float
# User model
class User(BaseModel):
user_id: int
name: str
email: str
# Route to retrieve account summary
@app.get("/account/{account_number}")
def get_account_summary(account_number: str):
cursor = conn.cursor()
# Execute the SQL query
cursor.execute(f"SELECT account_number, balance FROM accounts WHERE account_number = '{account_number}'")
# Fetch the result
row = cursor.fetchone()
# Check if the account exists
if row is None:
return {"error": "Account not found"}
# Create an instance of the AccountSummary model
account_summary = AccountSummary(account_number=row.account_number, balance=row.balance)
return account_summary
# Route to retrieve user details
@app.get("/user/{user_id}")
def get_user(user_id: int):
cursor = conn.cursor()
# Execute the SQL query
cursor.execute(f"SELECT user_id, name, email FROM users WHERE user_id = {user_id}")
# Fetch the result
row = cursor.fetchone()
# Check if the user exists
if row is None:
return {"error": "User not found"}
# Create an instance of the User model
user = User(user_id=row.user_id, name=row.name, email=row.email)
return user
# Run the FastAPI app
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Explanation
- Import the necessary dependencies:
FastAPI
,BaseModel
frompydantic
,pyodbc
,load_dotenv
fromdotenv
, andos
. - Load the configuration from the
config.ini
file usingload_dotenv(".env")
. - Create an instance of the
FastAPI
class. - Read the configuration values from the environment variables or use default values specified in the code. The
os.getenv()
function. - Establish a database connection using the configuration values obtained from the environment variables or default values.
- Define the
AccountSummary
model usingBaseModel
to represent the account summary withaccount_number
andbalance
attributes. - Define the
User
model usingBaseModel
to represent user details withuser_id
,name
, andemail
attributes. - Create a route
/account/{account_number}
using the@app.get
decorator to handle GET requests and retrieve the account summary for a given account number. - Inside the route function
get_account_summary
, establish a database cursor to execute SQL queries. - Execute the SQL query to retrieve the account summary for the provided account number.
- Fetch the first row of the result using
cursor.fetchone()
. - Check if the account exists by verifying if the fetched row is
None
. If it is, return an error message indicating that the account was not found. - If the account exists, create an instance of the
AccountSummary
model with the fetchedaccount_number
andbalance
. - Return the account summary as JSON.
- Create a route
/user/{user_id}
using the@app.get
decorator to handle GET requests and retrieve the user details for a given user ID. - Inside the route function
get_user
, establish a database cursor to execute SQL queries. - Execute the SQL query to retrieve the user details for the provided user ID.
- Fetch the first row of the result using
cursor.fetchone()
. - Check if the user exists by verifying if the fetched row is
None
. If it is, return an error message indicating that the user was not found. - If the user exists, create an instance of the
User
model with the fetcheduser_id
,name
, andemail
. - Return the user details as JSON.
- Finally, run the FastAPI app using
uvicorn
server.
Make sure to install the required dependencies by running pip install fastapi pydantic pyodbc python-dotenv
before running the code. Additionally, create the config.ini
file with the correct values for the SQL Server connection. You can customize the configuration values by modifying the config.ini
file or setting environment variables with the same names.
Automated Behavior-Driven Development (BDD) Test Cases
To create automated Behavior-Driven Development (BDD) test cases for the banking API, you can use a testing framework like pytest
along with libraries such as requests
and pytest-bdd
. Here's an example of how you can structure and write BDD test cases for the API:
- Install the required dependencies by running
pip install pytest requests pytest-bdd
. - Create a new directory for your test suite and navigate to it.
- Create a new file called
test_banking_api.feature
and add the following content:
Feature: Banking API
Scenario: Retrieve account summary
Given the API is running
When I send a GET request to "/account/123456789"
Then the response status code should be 200
And the response should contain the account summary
Scenario: Retrieve user details
Given the API is running
When I send a GET request to "/user/1"
Then the response status code should be 200
And the response should contain the user details
- Create another file called
test_banking_api.py
and add the following content:
import requests
import pytest
from pytest_bdd import given, when, then, parsers
@pytest.fixture
def base_url():
return "http://localhost:8000"
@given("the API is running")
def api_running(base_url):
response = requests.get(f"{base_url}/docs")
assert response.status_code == 200
@when(parsers.parse('I send a GET request to "{endpoint}"'))
def send_get_request(base_url, endpoint):
global response
response = requests.get(f"{base_url}{endpoint}")
@then("the response status code should be 200")
def verify_status_code():
assert response.status_code == 200
@then("the response should contain the account summary")
def verify_account_summary():
json_response = response.json()
assert "account_number" in json_response
assert "balance" in json_response
@then("the response should contain the user details")
def verify_user_details():
json_response = response.json()
assert "user_id" in json_response
assert "name" in json_response
assert "email" in json_response
- Open a terminal, navigate to the test suite directory, and run
pytest
to execute the tests.
The above code sets up the BDD test cases using pytest-bdd
. It defines steps using decorators (@given
, @when
, @then
) that correspond to the Gherkin syntax in the test_banking_api.feature
file. The steps make use of the requests
library to send HTTP requests to the API and validate the responses.
Make sure the API is running at http://localhost:8000
or update the base_url
fixture in the test file with the appropriate URL.
You can further extend the BDD test cases by adding more scenarios or steps as per your requirements.
Conclusion
FastAPI has emerged as a powerful framework for developing high-performance and secure banking APIs. Its efficient request handling, strong typing, automatic documentation generation, and security features make it an ideal choice for financial institutions aiming to deliver reliable, scalable, and fast banking services. By leveraging FastAPI, banks can build robust APIs that facilitate seamless integration with mobile applications, web portals, and other digital channels, ultimately enhancing customer experience and driving innovation in the banking industry
Opinions expressed by DZone contributors are their own.
Comments