Skip to content

API UP Web framework

API UP Web Framework is a safe, fast and modern Python (3.14+) Web framework to create APIs. It is completely async, has a native and real background task execution system and include many of the most common and required features of a professional API, including support for Multi Tenant and Micro Services systems, commonly used in SaaS. Furthermore, it has an ecosystem of libraries and tools to help to create professional applications for Web, Mobile and IOT, including an Administrative UI, SDKs and a CLI tool to increase the productivity.

Take a look into the Basic Examples before jumping in to the Full documentation

Also, the Quick Reference has a good set of the main features that should be enough for most part of API implementation.


Paradigms

  • Scalable: 100% asynchronous;
  • Native embedded background task system;
  • Native embedded ODM library;
  • Authorization system per Endpoint/Collection/Document and Fields;
  • Productivity: automatic implementation of CRUD and search operations;
  • Performance oriented: automatic query optimization for most common API scenarios;
  • Security oriented: private by default, configurable for public access;
  • Clean code: Command pattern keeps each feature’s logic in one place;
  • Testable: embedded test library and simple design to test Commands;
  • Multi-Database: use different databases transparently for the application;
  • Multi-Tenant: included features good for SaaS systems;
  • Multi-Version: designed for a smooth localdevalpharelease deployment workflow;

Web Frameworks comparisons

Python and other Languages has many excellent web frameworks, each with its own strengths. For example: Django emphasizes the DRY principle, provides a powerful native ORM, and has a rich ecosystem; Ruby on Rails based on conventions to reduce settings files and the easy to user ActiveRecord system; Flask and Bottle focus on simplicity; FastAPI is designed for APIs; and Tornado offers a fully non-blocking architecture.

API UP framework aims to combine the best aspects of these frameworks, fully specializing in real, scalable, and production-ready APIs and microservices. Beyond that, it was designed to be used as a Service, which changes everything.

Security is the first priority: everything is protected by default, with a built-in, simple yet powerful authentication and authorization system. The framework is also optimized for real-world bottlenecks such as network and database performance. It is fully async, including its ODM library, and includes a native background task system.

In other words, it is much more than a web framework — it is an innovative API toolkit that covers all layers of API development, including proxy servers, gateways, databases, caching, and even continuous integration and deployment.

All of this works with zero configuration, ready for immediate use in both development and production environments.


Concepts

Architecture

The Model-View-Controller architectural pattern is the initial standard way to organize Web Frameworks, and each one has its particularities.

Unlike other frameworks, API UP does not provide any feature or integration related to the UI. This keep the API (interface) totally transparent to be used by any client in any platform (Web, Mobile, IOT, AI agents). Especially nowadays (2025+), this is an important thing to AI to communicate to each other.

The second reason for that is because most of the specialized tools and libraries provided by the frontend community are way better and powerful than the tools provided by the backend Web frameworks. Not enough, this clear separation helps not just creating professional systems, but also to manage and parallelize the development through different teams.

About the Controller layer, it has already been implemented, optimized in a standard way following good community conventions. For that reason, mostly of the API development will be focused on your real challenge: modeling the data and creating the business logic.

Another structure difference that turns API UP remarkable, is the well-defined request logic implemented using the great Command object design pattern. Usually, the Web frameworks provide loose and disconnected entities for a single business logic, which turns the code harder to understand and easier to commit mistakes. Probably you won't see this problem in the basic examples written in a couple of lines of code, where the logic can be embedded in a single and loose function but, in real world logic, that issue appears naturally. In API UP, all the request or command data and logic are sticky together, keeping logic cohesion.


Conventions

The explicit vs implicit discussion is common in Web frameworks and middleware systems. Just as implicit configuration or code through conventions could save some configuration attributes, it harms the learning curve and let the understanding more obscure. On the other hand, keeping everything explicit, even for repeatedly development tasks decreases the productivity.

So, the API UP framework attempt to use the best of both worlds to increase productivity and keep the code easy to understand. The number of conventions is minimum and are just considered in specific non-repeated scenarios, like the well-defined project structure through the apps' directory.

For the code, routing, commands and tasks which will be touched in every development routine, it will stick to clear and explicit information. Since the Web Framework fully use DRY (Don't repeat yourself) principle, the code remains simple and easy to read and maintain.

Finally, most of the repeated configuration stack for the backend, CI, CD, deploy has already been implemented and included transparently in the development cycle, removing this concern for the dev and platform teams.


AI ready

The Web Framework has been developed not just to used by backend developers, but also by AI agents, even to agents communicate to each other. The simple and well-defined standards in the communication, routing and data structure, facilitates the learning and also the integration with different services.

Even though, in the near future, the API Service will include tools, prompts and agents to strengthen the systems and productivity.


Safety first

In API UP, security is not optional. By default, it includes protections against harmful attacks in all layers of the backend. It also includes tools and strategies to handle suspicious operations. Nevertheless, in the API UP UI you can contact the Support team privately to provide any security threat you may think of, and the API UP team will act with priority.

About the framework code it already includes an authentication and authorization systems to help to protect the user and system data. Moreover, unlike other tools that use the default features opened or public even to anonymous users, in API UP it keeps private by default and you, if necessary, let the feature more flexible. That should avoid the most common issues that happens even to some big player's tools.


Performance oriented

It is well known that the main performance bottlenecks of APIs are typically related to the network and databases. Still, the API UP framework is designed to minimize its own overhead. To achieve this, performance-critical parts of the codebase are implemented in C and Rust.

In our technical benchmarks, which evaluate common features such as validation and CRUD operations, the API UP framework shows up to a 10% performance improvement compared to popular high-performance Python async frameworks, and up to a 90% improvement compared to synchronous frameworks. In practice, the difference is likely even greater, since API UP includes security, authorization checks, metrics, and many other built-in features by default—while the frameworks used for comparison were tested with only the minimal code required to handle each request.

Furthermore, API UP enforces performance best practices by default—not only internally, but also in the code generated for the final API. This contrasts with the strategy used by many other popular web frameworks, where the default code encourages writing a simple but naive implementation that requires later optimization. The risk with that approach is that performance issues may not remain isolated; they can propagate to the database and eventually impact the entire system.

Normalized benchmarks, ignoring network latency but including a small I/O overhead to simulate database/cache access.

TS Requests% RPS % RPM % Average % p50 % p90 % p95 % p99 %
python API UP 7579 247 14820 411.6ms 430.1ms 641.6ms 682.4ms 729.5ms
python asgi uvicorn 100.1 98 98 128.4 104.1 172.8 177.4 182.7
python django gunicorn 17.7 16.2 16.2 763.6 782.6 539 509.5 478.1
python fastapi uvicorn 97.6 96 96 120.3 103.6 155.2 160.1 162.7
python flask gunicorn 17.6 16.2 16.2 755 775.3 532.2 501.5 470.3
python wsgi gunicorn 18.1 16.6 16.6 747.5 770.3 522.8 492.5 461.9
go gin 104.3 103.2 103.2 98.1 87.4 120.9 125.2 129
javascript nestjs 99.1 99.3 99.3 128 110.7 169.6 175.1 178.6
ruby rails 65.3 63.2 63.2 355.6 362.1 255.5 246.1 245.6
rust actix 101.3 99.2 99.2 119.1 100.6 155.1 161.8 166.1
  • RPS: requests per second;
  • RPM: requests per minute;
  • Average: average response time in milliseconds;
  • p##: percentile of response time in milliseconds;
  • Values normalized in % for comparison with API UP results;

Testability

To create a trustable and maintainable source code, automated tests are inevitable. The API UP Web framework was developed to be automated test friendly, without any other tools or plugins.

That means that creating the Commands, Tasks and Documents for testing are straightforward, without requiring Mocks or creating complex network structures. Also, the framework already includes features to simplify testing with Database, including auto generation of random test data and other test utilities to help keeping the test code base small and fast to write.

Besides that, the Continuous Integration and Continuous Testing are already configured by default, and it is up to developer to use it during development.

Multi Version

The versioning and deploy can be critical, danger, time-consuming and stressful operation in all software systems. With API UP and API as a Service, that challenge is addressed through a pragmatic and well-defined way, through Multi version support and a well-defined versioning system: local > dev > alpha > release. It is important though to keep in mind the concepts of having multiple API versions running at the same time, to keep the data and code base ready for that.

It is important to know that the multi version is not encouraged though, it is just a tool to facilitate the lifecycle of the versions and turn API evolution process smooth. Although it can be useful for specific scenarios specially for client systems embedded into hard to update platforms.

Basic examples

Ping

Ping - apps/basic/commands.py
from apiup import Command, command, Jsonable, Permission

@command(method="GET", endpoint="/ping", permission=Permission.PUBLIC)
class Ping(Command):
    async def command(self, ctx: Context) -> Jsonable:
        return "pong"

# Request: http GET https://api/ping
# > Output: "pong"

Echo - Hello World

Hello World - apps/basic/commands.py
from apiup import Command, Context, command, F, Jsonable, Permission

@command(method="GET", endpoint="/hello-world", permission=Permission.PUBLIC)
class HelloWorld(Command):
    # Command parameters declared in a organized way, including its validations.
    echo: str = F(type="string", required=True, max=50)

    async def command(self, ctx: Context) -> Jsonable:
        return f"[APIKit] Hello {self.echo}!"

# Request: http GET https://api/hello-world echo="Alice"
# > Output: "[APIKit] Hello Alice"

Document - CRUD

Document - apps/petstore/schemas/Product.yaml
name: Product
fields:
    name:
        type: string
        max: 50
        index:
            unique: true
    description:
        type: string
        max: 200
acl:
    create: staff
    read: user
    update: staff
    delete: admin

Tip

All CRUD and Search commands are automatically implemented for every Document, including validations and authorization checking. You just need to call the endpoints.

Sample CRUD commands - apps/petstore/product_commands.py
# /$app/$doc/$action => /petstore/product/command-class-name

from apiup import Command, Context, command, F, JSONType, Jsonable, Permission, Doc

# Usage: http POST https://api/petstore/product/create name="Some product" description="Some descr."
# Just Staff users can create Products
@command(endpoint="/petstore/product/create", permission=Permission.STAFF)
class Create(Command):
    name: str = F(type="string", required=True, max=50)
    description: str = F(type="string", max=200)

    async def command(self, ctx: Context) -> Jsonable:
        Product = Doc('Product')
        p: Product = Product(name=self.name, description=self.description)
        await p.save()
        return p


# Usage: http GET https://api/petstore/product/read id="..."
# All authenticated users can see Products
@command(method="GET", endpoint="/petstore/product/read", permission=Permission.USER)
class Read(Command):
    id: str = F(format="id", required=True)

    async def command(self, ctx: Context) -> Jsonable:
        return await Product.manager().get_by_id_or_raise(self.id)


# Usage: http PUT https://api/petstore/product/update id="..."
# Just Staff users can update Products
@command(method="PUT", endpoint="/petstore/product/update", permission=Permission.STAFF)
class Update(Command):
    data: dict[str, JSONType] = F(type="dict", required=True)

    async def command(self, ctx: Context) -> Jsonable:
        p: Product = await Product.manager().get_by_id_or_raise(self.id)
        p.assign(self.data, assign_from_user=ctx.user)
        await p.save()
        return p


# Usage: http DELETE https://api/petstore/product/delete id="..."
# Just Admin users can delete Products
@command(method="DELETE", endpoint="/petstore/product/delete", permission=Permission.ADMIN)
class Delete(Command):
    id: str = F(format="id", required=True)

    async def command(self, ctx: Context) -> Jsonable:
        p: Product = await Product.manager().get_by_id_or_raise(self.id)
        await p.delete()
        return "deleted"