Application Programming Interface
An Application Programming Interface (API) is a foundational element in
modern software development, acting as a crucial intermediary that enables
different software applications to communicate and share data with each
other. This will explore the core concepts of APIs, their necessity in
overcoming architectural limitations, and their versatile applications,
including in the field of machine learning.
1. What is an API?
At its core, an API is a set of rules and definitions that allows one software
application to interact with another. Think of it as a contract of service
between two applications, defining the kinds of requests that can be made,
how to make them, the data formats that should be used, and the
conventions to follow. This allows developers to access and use the
functionality of other applications without needing to understand their
internal workings.
APIs operate on a request-response cycle. A client application sends a
request to the API of a server, and after processing the request, the server
returns a response.[5]
2. The Need for APIs: Moving Beyond Monolithic Architecture
To understand the importance of APIs, it's essential to first grasp the concept
of monolithic architecture and its inherent challenges.
Monolithic Architecture: This is a traditional model for software
development where an entire application is built as a single, unified
unit. All the different components of the application, such as the user
interface (frontend) and the business logic (backend), are tightly
interwoven and interdependent.[6][7]
Problems with Monolithic Architecture:
o Frontend and Backend Tightly Coupled: A primary drawback
of the monolithic approach is the tight coupling between the
frontend and the backend.[6][8] Any change in one part of
the system, no matter how small, can have a significant
and often unpredictable impact on other parts.
o Reduced Agility: This tight coupling slows down development
cycles. A small change requires the entire application to be re-
tested and redeployed, making it difficult to implement updates
quickly.
o Scalability Challenges: Scaling a monolithic application can be
inefficient. Even if only one feature is experiencing high
traffic, the entire application must be scaled, leading to
wasted resources.
o Technology Stack Rigidity: In a monolithic architecture, the
entire application is typically built with a single
technology stack. This makes it challenging to adopt new
technologies or languages for different parts of the application.
o High Impact of Failures: If one component of the
application fails, it can bring down the entire system.
APIs provide a solution to these problems by enabling a decoupled, more
modular approach to software development.
3. APIs as Special Functions on the Internet
You can think of APIs as a collection of special, remotely accessible functions.
Just as a function in a programming language takes inputs, performs an
operation, and returns an output, an API endpoint can be called over the
internet with specific parameters to trigger an action or retrieve
data. This abstraction allows developers to leverage powerful functionalities
from other services without having to build them from the ground up.
4. JSON: The Lingua Franca of APIs
For applications to communicate effectively via APIs, they need a common
data format. This is where JSON (JavaScript Object Notation) comes in.
What is JSON? JSON is a lightweight, human-readable data
interchange format that is easy for machines to parse and
generate. It represents data in key-value pairs, similar to a
dictionary or a hash map in many programming languages.
The Role of JSON in APIs: JSON is the most common format for
sending and receiving data in modern web APIs.[3][5] Its simplicity,
readability, and the fact that it is language-independent make it an
ideal choice for structuring the information exchanged between
different applications.[1]
5. One API, Multiple Frontends
One of the most significant advantages of using APIs is the ability to have
a single backend that serves multiple different frontend
applications. A single, well-designed API can provide data and functionality
to a website, an Android app, and an iOS app simultaneously.[10][11]
This approach offers several benefits:
Code Reusability: The core business logic is centralized in the
backend and exposed through the API. This eliminates the need to
duplicate code across different platforms.
Faster Development: Frontend teams can work independently on
their respective platforms, as long as they adhere to the API's contract.
Consistent User Experience: Since all frontends are interacting with
the same underlying data and logic, it's easier to maintain a consistent
user experience across different devices.
Easier Maintenance: Updates to the business logic only need to be
made in one place – the backend. These changes are then
automatically available to all connected frontends.
6. APIs from a Machine Learning Perspective
APIs play a pivotal role in the world of machine learning, making complex AI
models accessible and usable.[4]
Access to Pre-trained Models: Many large tech companies provide
powerful, pre-trained machine learning models through APIs. This
allows developers to integrate sophisticated capabilities like image
recognition, natural language processing, and sentiment analysis into
their applications without needing to build and train these models
themselves.
Model Deployment: Once a custom machine learning model is
trained, it can be deployed as an API. This makes the model's
predictions available to other applications and services. For example, a
recommendation engine model could be exposed via an API that a
website can call to get product recommendations for a user.
Data Integration: Machine learning models require large amounts of
data for training. APIs can be used to gather and integrate data from
various sources.
Scalability: APIs enable machine learning models to be scaled
independently, allowing them to handle a large volume of prediction
requests efficiently.[12]
In conclusion, APIs are the invisible backbone of the modern, interconnected
digital world. They break down the rigid silos of monolithic architecture,
fostering a more flexible, scalable, and efficient approach to software
development. From powering our daily mobile apps to making the power of
machine learning accessible to all, APIs are a fundamental
FastAPI is a modern, fast (high-performance) web framework for building
APIs with Python 3.8+ based on standard Python type hints. It's designed
for quick development, robust production-ready applications, and aims to
provide excellent developer experience.
1. How Starlette is Used in FastAPI
FastAPI is built on top of Starlette, an ASGI (Asynchronous Server Gateway
Interface) toolkit. This means FastAPI inherits Starlette's core functionalities,
making it a powerful and efficient framework for asynchronous programming.
Starlette's Role:
Core Web Functionalities: Starlette manages how your API
receives requests and sends back responses.[5] It provides the
fundamental web components like routing, middleware, and
WebSocket support.
ASGI Compliance: As an ASGI toolkit, Starlette enables FastAPI to
handle asynchronous operations efficiently.[3][8][9]
Minimalistic and Flexible: Starlette is known for being small, fast,
and flexible, and FastAPI leverages these characteristics internally.[3]
Essentially, Starlette provides the underlying asynchronous web capabilities,
and FastAPI builds on this foundation by adding convenient features like
automatic data validation, serialization, and interactive API documentation.
[10][11]
2. How Pydantic is Used in FastAPI
Pydantic is a data validation and settings management library that integrates
seamlessly with FastAPI. It uses Python type hints to define data models,
ensuring data integrity and providing automatic validation.[10][12][13][14]
Pydantic's Role:
Data Modeling and Validation: Pydantic models allow you to
define clear, predictable data structures with built-in type-
checking and validation.[10][12][13][14] This ensures that incoming
request data adheres to the expected format and types.[14]
Automatic Documentation: FastAPI leverages Pydantic models for
automatic generation of interactive API documentation
(Swagger UI and ReDoc).[5][10][12]
Serialization: Pydantic handles the parsing and conversion of data
(e.g., JSON) into Python objects, and vice-versa, based on the defined
models.[14]
Error Handling: If data validation fails, FastAPI automatically returns
detailed and informative error messages based on the Pydantic
models.[10]
Request and Response Models: You use Pydantic models to
declare the expected structure of request bodies, query
parameters, and the shape of the responses your API sends
back to clients.[13]
In essence, Pydantic acts as the backbone for structured data handling
within FastAPI applications, simplifying data validation, serialization, and
documentation.[12][13]
3. Philosophy of FastAPI
FastAPI's philosophy centers around several key principles aimed at
optimizing both developer experience and application performance:[1][5][15]
Speed (Fast to Run and Fast to Code):
o Fast to Run: Achieves very high performance, comparable to
NodeJS and Go, thanks to its foundation on Starlette and
Pydantic, and its ASGI nature.[1]
o Fast to Code: Aims to significantly increase the speed of feature
development (by 200% to 300%) by providing an intuitive API,
excellent editor support with completion everywhere, and
minimizing code duplication.[1]
Robustness and Fewer Bugs: By leveraging standard Python type
hints and Pydantic for data validation, FastAPI helps reduce human
(developer) induced errors by about 40%.[1]
Intuitive and Easy to Use/Learn: Designed to be straightforward to
use and learn, leading to less time spent debugging and reading
extensive documentation.[1]
Standard-Based: Built upon and fully compatible with open standards
for APIs like OpenAPI (previously Swagger) and JSON Schema.
Modern Python: Embraces modern Python features, especially type
hints (async/await) for building highly concurrent applications.[9][10]
"Batteries Included" yet Flexible: Provides many out-of-the-box
features like automatic documentation and validation, but remains
flexible due to its Starlette foundation, allowing developers to use only
what they need.[11]
4. Why FastAPI is Fast to Run & Comparisons
FastAPI's exceptional speed stems from its asynchronous nature and the
technologies it's built upon.
Key Factors for FastAPI's Speed:
ASGI (Asynchronous Server Gateway Interface): FastAPI is an
ASGI-based framework, which allows it to handle multiple
requests concurrently within a single process.[9][16] This is a
significant advantage over traditional WSGI (Web Server Gateway
Interface) servers.[8][9][17]
Asynchronous I/O (async/await): FastAPI fully supports and
encourages the use of Python's async and await keywords. This
enables efficient handling of I/O-bound tasks (like database
queries, external API calls) by allowing the server to switch to other
tasks instead of blocking while waiting for an I/O operation to
complete.[8]
Starlette: As FastAPI's underlying web framework, Starlette is a high-
performance ASGI toolkit.[3][11]
Pydantic: While primarily for validation, Pydantic's efficient data
parsing and serialization contribute to the overall performance by
minimizing overhead.
Uvicorn: FastAPI is typically run with Uvicorn, a fast,
lightweight ASGI server, optimized for asynchronous
programming.
Comparison Tables:
Flask vs. FastAPI
Feature Flask FastAPI
WSGI (Web Server ASGI (Asynchronous Server
Foundation
Gateway Interface) Gateway Interface)
Synchronous (blocking I/O
Concurrency Asynchronous (non-blocking I/O)
by default)
Good for traditional web
Exceptional for I/O-bound tasks,
Performance apps, less scalable for
high throughput, low latency[9]
high-concurrency[9]
Data Requires external libraries
Built-in via Pydantic[10][12][13][14]
Validation (e.g., Marshmallow)
Documentati Automatic OpenAPI (Swagger UI,
Manual or with extensions
on ReDoc)[5][10][11]
Heavily relies on standard Python
Type Hinting Optional type hints for validation and
autocompletion[1]
High-performance APIs,
Simple APIs, traditional
microservices, real-time
Use Case web applications, smaller
applications, I/O-heavy
projects[9]
workloads[9]
Gunicorn vs. Uvicorn
Feature Gunicorn Uvicorn
Protocol WSGI server ASGI server[2][8]
Synchronous (processes
Concurrenc Asynchronous (efficiently handles
one request at a time per
y Model concurrent connections)[2][8]
worker)[2]
Optimized WSGI frameworks (e.g., ASGI frameworks (e.g., FastAPI,
For Flask, Django)[2][8] Starlette)[2][8]
Performanc Good for synchronous Exceptional for asynchronous code
e workloads and high concurrency
Usage with Can be used as a process Recommended lightweight server
manager for Uvicorn for FastAPI, especially for
FastAPI
workers in production[2] asynchronous applications[2]
WSGI vs. ASGI
WSGI (Web Server Gateway ASGI (Asynchronous Server
Feature
Interface) Gateway Interface)
Asynchronous protocol[8]
Nature Synchronous protocol
[17]
Non-blocking I/O (can switch
Blocking I/O (each request blocks
I/O Model between tasks during I/O
a worker until complete)[8][17]
waits)[8][17]
Achieved by using multiple Achieved by async/await,
Concurrency
threads/processes event-driven[8][9][17]
Supported HTTP/1.1, HTTP/2,
HTTP/1.0, HTTP/1.1
Protocols WebSockets, SSE[8][17]
Frameworks Flask, Django (default)[17] FastAPI, Starlette[9][17]
Highly scalable for real-time
Can be limited in high-
Scalability and I/O-heavy
concurrency scenarios[8][9]
applications[8][9]
Synchronous Endpoint vs. Asynchronous Endpoint
In FastAPI, you can define both synchronous (def) and asynchronous (async
def) path operation functions.
Asynchronous Endpoint
Feature Synchronous Endpoint (def)
(async def)
Keyword def async def
Non-blocking. Allows the
Blocks the worker process/thread
server to perform other tasks
Blocking until completion. Suitable for
while waiting for I/O
Behavior CPU-bound tasks or when no I/O-
operations to finish. Ideal for
bound operations are performed.
I/O-bound tasks.[9]
Performan Can be slower for I/O-bound Faster for I/O-bound
ce operations as it waits. operations due to efficient
resource utilization.[9]
FastAPI runs def functions in a FastAPI runs async def
FastAPI
separate thread pool to avoid functions directly in the event
Handling
blocking the main event loop. loop.
When your endpoint primarily
When your endpoint involves
When to performs computations or
waiting for databases,
Use doesn't involve waiting for
external APIs, file I/O, etc.[9]
external resources.
HTTP and HTTP Methods
1. What is HTTP?
HTTP (Hypertext Transfer Protocol) is the communication protocol for
the web, enabling clients (browsers, apps) and servers to exchange data.
Key Points:
Request-Response: Clients send requests, servers send responses.
Stateless: Each request is independent; servers don't remember past
interactions by default.
Text-based: Messages are human-readable.
Resource-Oriented: Resources are identified by URLs.
Components:
o Request: Method, URL, Headers, Body (optional).
o Response: Status Code, Headers, Body (optional).
2. HTTP Methods (GPPPD)
HTTP methods (verbs) define the action to be performed on a resource.
Key Concepts:
Idempotence: Repeating the request has the same effect (e.g.,
DELETE, PUT, GET).
Safety: The request doesn't alter server state (e.g., GET, HEAD,
OPTIONS).
Common HTTP Methods in FastAPI: (GPPPD)
Metho Safe Idempoten
Purpose Body? FastAPI Decorator
d ? t?
No
Retrieve a resource
GET Yes Yes (query @[Link]("/path")
(READ)
params)
Create a new
POST resource or submit No No Yes @[Link]("/path")
data (CREATE)
Replace/Update an
@[Link]("/path/
PUT entire resource No Yes Yes
{id}")
(UPDATE/CREATE)
DELET Remove a resource @[Link]("/path/
No Yes No
E (DELETE) {id}")
Apply partial
Generally @[Link]("/path/
PATCH modifications to a No Yes
No {id}")
resource (UPDATE)
Less Common Methods (Good to Know):
HEAD: Same as GET, but only retrieves headers (no body).
OPTIONS: Describes communication options for a resource (e.g.,
supported methods, CORS preflight).
Path Params: Path parameters are dynamic part of a URL used to
identify a specific resource.
1. Pydantic: Why?
Pydantic is fundamental to FastAPI for several reasons:
Data Validation: Automatically validates request payload (body,
query, path parameters) and response data based on type hints,
catching errors early.
Data Serialization/Deserialization: Converts incoming JSON/form
data into Python objects and Python objects back into JSON for
responses.
Automatic Documentation: FastAPI uses Pydantic models to
generate OpenAPI (Swagger UI) schema, providing clear and
interactive API documentation.
Type Hint Enforcement: Leverages Python's type hints for robust,
maintainable code.
Readability & Maintainability: Centralizes data schema definitions,
making code easier to read, understand, and maintain.
2. What is Pydantic?
Pydantic is a Python library for data validation and settings management
using Python type hints. It allows you to define data schemas as Python
classes, where attributes are annotated with type hints. Pydantic then
enforces these types at runtime, providing detailed error messages if
validation fails.
BaseModel: The core class in Pydantic. You define your data schemas
by inheriting from [Link].
Type Hint Integration: Works seamlessly with standard Python type
hints (str, int, bool, List, Optional, Union, etc.).
3. Important Points for Type Validation
Pydantic extends standard Python types with specialized types for common
validation scenarios. These types perform robust validation beyond basic
type checking.
EmailStr: Validates that a string is a well-formed email address.
o Example: email: EmailStr
HttpUrl / AnyUrl:
o HttpUrl: Validates that a string is a valid HTTP or HTTPS URL.
o AnyUrl: A more general URL validator that accepts various
schemes (e.g., ftp, ws, sftp) in addition to http and https.
o Example: website: HttpUrl or resource_path: AnyUrl
IPv4Address / IPv6Address: Validates string as an IPv4 or IPv6
address.
UUID4: Validates string as a UUID version 4.
FilePath / DirectoryPath: Validates string as a valid file or directory
path on the operating system.
SecretStr / SecretBytes: For sensitive data, preventing accidental
logging or representation in string/bytes format.
4. Important Points for Data Validation (Field)
While Pydantic types handle basic type validation, the Field function from
pydantic (or [Link] which re-exports it) allows you to add more
granular validation rules and metadata.
Purpose: Provides extra validation constraints and metadata for
model fields.
Keyword Arguments: Field accepts various keyword arguments for
validation:
o default: Sets a default value if the field is not provided.
o min_length, max_length: For strings.
o gt (greater than), ge (greater than or equal), lt (less than), le
(less than or equal): For numbers.
o regex: A regular expression pattern for string validation.
o alias: An alternative name for the field in the input data.
o title, description: Metadata for documentation.
Optional Fields with Default: Optional[str] = Field(None, ...) or
name: str | None = Field(None, ...)
Required Fields with Constraints: If no default value is provided,
the field is implicitly required.
o Example: name: str = Field(min_length=3, max_length=50)
o Example: age: int = Field(gt=0, le=120)
5. Metadata with Field Function and Annotated
Both Field and Annotated are used to add metadata, but they serve slightly
different purposes and Annotated is a more modern, flexible approach
introduced in Python 3.9 and Pydantic v2+.
Metadata with Field Function
Description: Allows adding descriptive information (title, description,
example) that FastAPI uses to enrich the OpenAPI schema.
Example Usage:
Metadata with Annotated
Purpose: Annotated (from typing) provides a way to add contextual
metadata to types. Pydantic (especially v2+) and FastAPI leverage this
for more advanced validation and dependency injection.
Flexibility: It separates the type hint from the metadata, making it
cleaner for complex scenarios. It's particularly powerful when
combining multiple validators or when integrating with FastAPI's
dependency injection.
Key Distinction (Pydantic v2+):
o For simple field validation and metadata, Field used directly in
the type annotation (e.g., name: str = Field(...)) is often sufficient
and still common.
o Annotated becomes crucial when you need to apply multiple
constraints/metadata to a type, or when working with Depends in
FastAPI for dependency injection parameters. Annotated allows
you to stack multiple Field instances or other metadata objects.
1. Pydantic Field Validator
Purpose: To apply custom validation or transformation logic to a
single field after its initial type validation, but before the model is
fully constructed. This is useful for field-specific business rules.
How to Use (Pydantic v2+):
o Decorate a class method with @field_validator('<field_name>',
mode='<mode>'). The mode can be 'after' (default, runs after
Pydantic's internal validation) or 'before' (runs before, useful for
coercion).[1][2]
o The method receives cls (the model class) and value (the field's
value). It can also receive info: ValidationInfo for more context.[2]
o It must return the (potentially modified) value if valid, or raise a
ValueError for invalid data.[1][2]
Example:
2. Model Validator
Purpose: To apply custom validation logic across multiple fields
within the model, or for complex checks that depend on the overall
state of the model. This runs after all individual field validators
have completed.[3][4]
How to Use (Pydantic v2+):
o Decorate a class method with @model_validator(mode='after').
[3][4]
o The method receives self (the partially validated model
instance).[4]
o It should return self if valid, or raise a ValueError (or
ValidationError) if the cross-field logic fails.[3][4]
Example:
3. Computed Field
Purpose: To define fields whose values are derived from other
fields in the model. These fields are included when the model is
serialized (dumped), but are not expected as input data during
validation. They represent read-only calculated properties.[5][6][7]
How to Use (Pydantic v2+):
o Decorate a method (which acts like a property) with
@computed_field and @property.
o The method typically takes self and calculates a value based on
other model attributes.
Key Points:
o The return type hint is crucial for Pydantic to understand the
field's type.
o Computed fields are part of the model's output (serialization) but
not its input (validation).[6]
o FastAPI's OpenAPI documentation might not always fully reflect
computed fields by default, but they are included in
model_dump.[8]
Example:
4. Nested Model
Purpose: To represent complex, hierarchical data structures where
one Pydantic model contains instances of other Pydantic
models. This allows for robust, recursive validation and clear data
organization.[9][10][11]
How to Use: Simply use another Pydantic BaseModel as the
type hint for an attribute within a parent BaseModel.[12]
Key Points:
o Pydantic automatically handles the validation and serialization of
the nested models.[9][11]
o Enhances code readability and maintainability by structuring
complex data.[10]
Example:
5. Serialization (model_dump, model_dump_json)
Purpose: To convert a Pydantic model instance into a standard
Python dictionary or a JSON string. These methods replace the
deprecated .dict() and .json() from Pydantic v1, offering improved
performance and more features.
model_dump():
o Function: Converts a Pydantic model instance into a
Python dict.[6]
o Parameters:
include, exclude: Specify which fields to include or exclude.
[15]
by_alias: Use field aliases instead of original field names as
keys.[15]
mode: 'python' (default) to dump Python objects, 'json' to
prepare for JSON serialization (e.g., datetime objects to ISO
format strings).
exclude_unset: Only include fields that were explicitly set
when the model was created.
model_dump_json():
o Function: Converts a Pydantic model instance directly into
a JSON formatted str. This is generally more efficient than
calling model_dump() and then [Link]().[6]
o Parameters: Accepts most of the same parameters as
model_dump().
FastAPI: HTTP Methods (POST, PUT, DELETE)
1. POST Request
Purpose: Used to create new resources on the server.
Idempotency: Not idempotent. Making the same POST request
multiple times will typically result in the creation of multiple identical
resources.
Body: Usually includes a request body containing the data for the new
resource.
FastAPI Implementation: Handled by a path operation decorator
(e.g., @[Link]("/items/")). The data sent in the request body is
automatically parsed and validated by FastAPI, typically using Pydantic
models.
Response: Typically returns a 201 Created status code upon
successful resource creation, often along with the created resource's
data or ID.
2. PUT Request
Purpose: Used to update or replace an existing resource
entirely. If the resource does not exist, a PUT request might
create it (upsert operation), but its primary use is for replacement.
Idempotency: Idempotent. Sending the same PUT request multiple
times will have the same effect as sending it once; the resource will be
replaced with the same data each time, without creating duplicates.
Body: Requires a request body containing the complete, updated
representation of the resource.
FastAPI Implementation: Handled by a path operation decorator
(e.g., @[Link]("/items/{item_id}")). Requires a path parameter to
identify the resource to be updated, and a request body for the
updated data.
Response: Typically returns a 200 OK or 204 No Content status code
upon successful update. If it creates a resource, it might return 201
Created.
3. DELETE Request
Purpose: Used to remove a specified resource from the server.
Idempotency: Idempotent. Deleting a resource multiple times will
have the same effect as deleting it once (after the first successful
deletion, subsequent attempts will still result in the resource being
gone, even if they return a 404).
Body: Does not typically include a request body, as the resource to be
deleted is identified by its URI.
FastAPI Implementation: Handled by a path operation decorator
(e.g., @[Link]("/items/{item_id}")). Requires a path parameter to
identify the resource to be deleted.
Response: Typically returns a 200 OK (with an optional confirmation
message) or 204 No Content upon successful deletion. If the resource
was not found, it might return 404 Not Found.