# Motoko Showcase: Liminal - An HTTP framework

**URL:** <https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159>\
**Category:** Showcase\
**Created:** [July 1, 2025, 12:56am UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159 "2025-07-01T00:56:48Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gekctek](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/gekctek/32/6863_2.png) [@Gekctek](https://forum.dfinity.org/u/Gekctek)\
**Post date:** [July 1, 2025, 12:56am UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/1 "2025-07-01T00:56:48Z")

</div>

I recently completed a Dfinity grant focused on improving the Motoko ecosystem by providing better HTTP support for developers. The goal was to create a framework so that not everyone has to write HTTP handling from scratch when building web applications on the Internet Computer. I’m looking forward to any and all feedback from the community.

## **Project highlights**

Liminal is a middleware-based HTTP framework designed for building web applications and APIs with Motoko on the Internet Computer. It targets Motoko developers who want a solid foundation for their web services without having to build HTTP handling from scratch.

The framework addresses the need for common web development features on IC, including middleware composition, routing, authentication, content negotiation, file uploads, and integration with IC-specific features like asset canisters. Liminal brings familiar web development patterns to the IC ecosystem while working with the unique query/update call model.

## **Features**

- **🔄 Middleware Pipeline** : Compose your application using reusable middleware components - create custom middleware or use built-in ones, with automatic query/update flow handling
- **🛣 Advanced Routing** : Route matching with parameter extraction (`/users/{id}`), wildcards (`*`, `**`), and nested route groups
- **🔒 Security** : Built-in CORS, CSP (Content Security Policy), CSRF protection, and rate limiting
- **🔐 Authentication** : JWT parsing/validation and OAuth 2.0 with PKCE support (Google, GitHub, custom providers)
- **📦 Asset Integration** : Interface with Internet Computer’s certified asset canisters
- **🚀 Performance** : Automatic response compression (gzip) and content negotiation
- **📤 File Uploads** : Parse multipart/form-data for handling file uploads (up to 2MB)
- **🔀 Content Negotiation** : Automatically convert Candid data to JSON, CBOR, XML based on Accept headers
- **📝 Session Management** : Configurable session storage with cookie handling
- **🛡 Rate Limiting** : Protect APIs from abuse with flexible rate limiting strategies
- **📊 Logging** : Built-in logging system with configurable levels and scoped loggers

## **How to install**

Liminal uses the MOPS package manager. First, set up MOPS following the instructions from [MOPS Site](https://mops.one), then add Liminal to your project:

```bash
mops add liminal

```

## **Usage Example**

Here’s a minimal example to get started:

```motoko
import Liminal "mo:liminal";
import Route "mo:liminal/Route";
import Router "mo:liminal/Router";
import RouteContext "mo:liminal/RouteContext";
import RouterMiddleware "mo:liminal/Middleware/Router";
import CORSMiddleware "mo:liminal/Middleware/CORS";

actor {
    // Define your routes
    let routerConfig = {
        prefix = ?"/api";
        identityRequirement = null;
        routes = [
            Router.getQuery(
                "/hello/{name}",
                func(context : RouteContext.RouteContext) : Route.HttpResponse {
                    let name = context.getRouteParam("name");
                    context.buildResponse(#ok, #text("Hello, " # name # "!"));
                }
            )
        ]
    };

    // Create the HTTP App with middleware
    let app = Liminal.App({
        middleware = [
            CORSMiddleware.default(),
            RouterMiddleware.new(routerConfig),
        ];
        errorSerializer = Liminal.defaultJsonErrorSerializer;
        candidRepresentationNegotiator = Liminal.defaultCandidRepresentationNegotiator;
        logger = Liminal.buildDebugLogger(#info);
    });

    // Expose standard HTTP interface
    public query func http_request(request : Liminal.RawQueryHttpRequest) : async Liminal.RawQueryHttpResponse {
        app.http_request(request)
    };

    public func http_request_update(request : Liminal.RawUpdateHttpRequest) : async Liminal.RawUpdateHttpResponse {
        await* app.http_request_update(request)
    };
}

```

## **Known Quirks**

Before diving in, here are some current limitations and quirks to be aware of:

- **HTTP Assets Inflexibility** : Asset canisters are somewhat rigid - they can only be accessed from one URL and require using the icx-asset syncing process for deployment
- **Limited dfx Asset Support** : Unlike Rust asset canisters, Motoko asset canisters don’t have built-in dfx support, requiring manual setup
- **Verbose Asset Integration** : Motoko requires manually implementing all asset canister HTTP endpoints, making the integration more verbose than ideal
- **Serialization Challenges** : Motoko lacks automatic JSON/CBOR/XML serialization, so you either implement it manually or use the ‘serde’ library (which has some rough edges)
- **Query/Update Complexity** : The automatic query→update upgrade process can be complex to understand - when an upgrade happens, the entire request starts over from the beginning of the middleware pipeline
- **No Auto API Mapping** : There’s currently no automatic mapping between Candid APIs and HTTP APIs - you need to define both separately

These are largely ecosystem-level challenges rather than framework-specific issues, and the framework aims to smooth over what it can.

## **Documentation**

The framework includes documentation with examples for:

- **Middleware Development** : Creating custom middleware components
- **Routing Patterns** : Path matching including wildcards and parameters
- **Authentication Flows** : JWT validation and OAuth integration
- **Asset Management** : Working with IC asset canisters
- **File Upload Handling** : Processing multipart form data

Full documentation and examples are available in the GitHub repository. [https://github.com/edjcase/liminal](https://github.com/edjcase/liminal)

## **Dependencies**

Liminal builds on several Motoko libraries:

- **new-base** (0.4.0) - Enhanced base library
- **jwt** (1.0.1) - JWT token handling
- **compression** (0.2.0) - Response compression
- **serde** (3.2.2) - Serialization/deserialization
- **http-assets** (0.0.7) - Asset canister integration
- **url-kit** (0.0.9) - URL parsing utilities

All dependencies are automatically managed through MOPS.

## **License**

Liminal is open source under the **MIT License** , allowing free use, modification, and distribution in both commercial and non-commercial projects.

## **Resources**

- **GitHub Repository** : [https://github.com/edjcase/liminal](https://github.com/edjcase/liminal)
- **MOPS Package** : [https://mops.one/liminal](https://mops.one/liminal)
- **Examples** : Complete working examples in the `/examples` directory
- **API Documentation** : Inline documentation throughout the codebase

## **Future Plans**

The project is in active development with plans to:

- **Enhance Developer Experience** : Gather community feedback to refine APIs and improve ergonomics
- **Expand Middleware Ecosystem** : Add more built-in middleware for common use cases (validation, caching, etc.)
- **Query/Update Model Refinement** : The automatic query→update upgrade system is new and untested at scale - looking for real-world feedback to optimize this approach
- **Performance Optimization** : Benchmark and optimize the middleware pipeline performance
- **Tooling Integration** : Develop dev tools and generators to streamline Liminal application development

The framework introduces an approach to handling IC’s query/update call model automatically through middleware, and I’m particularly interested in feedback from the community on this design pattern.

* * *

_Have you tried building HTTP services on IC? I’d love to hear about your experiences and get feedback on whether Liminal addresses the pain points you’ve encountered!_

---

<div class="post-metadata">

**Author:** ![dfxjesse](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/dfxjesse/32/17424_2.png) [@dfxjesse](https://forum.dfinity.org/u/dfxjesse)\
**Post date:** [July 1, 2025, 1:57am UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/2 "2025-07-01T01:57:10Z")

</div>

Looks very cool at a glance! Thanks for publishing, I will keep it in mind for future projects.

---

<div class="post-metadata">

**Author:** ![ohsalmeron](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/ohsalmeron/32/30099_2.png) [@ohsalmeron](https://forum.dfinity.org/u/ohsalmeron)\
**Post date:** [July 1, 2025, 2:03am UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/3 "2025-07-01T02:03:13Z")

</div>

> [@Gekctek](#):
>
> Liminal builds on several Motoko libraries:
> 
> - **new-base** (0.4.0) - Enhanced base library
> - **jwt** (1.0.1) - JWT token handling
> - **compression** (0.2.0) - Response compression
> - **serde** (3.2.2) - Serialization/deserialization
> - **http-assets** (0.0.7) - Asset canister integration
> - **url-kit** (0.0.9) - URL parsing utilities
> 
> All dependencies are a

Great contribution! I’ll give it a try for OAuth on-chain validation with JWTs 🚀

---

<div class="post-metadata">

**Author:** ![tiago89](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/tiago89/32/22332_2.png) [@tiago89](https://forum.dfinity.org/u/tiago89)\
**Post date:** [July 1, 2025, 6:39am UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/4 "2025-07-01T06:39:33Z")

</div>

Looks, great. Very useful. Thanks for building this.

---

<div class="post-metadata">

**Author:** ![mahmudsudo](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/mahmudsudo/32/10203_2.png) [@mahmudsudo](https://forum.dfinity.org/u/mahmudsudo)\
**Post date:** [July 7, 2025, 2:57pm UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/5 "2025-07-07T14:57:11Z")

</div>

Do you have open roles or need contributors ?  
I would love to be a part of this

---

<div class="post-metadata">

**Author:** ![Gekctek](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/gekctek/32/6863_2.png) [@Gekctek](https://forum.dfinity.org/u/Gekctek)\
**Post date:** [July 9, 2025, 10:44pm UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/6 "2025-07-09T22:44:01Z")

</div>

@mahmudsudo No open roles, just myself right now  
Always open to contributions on this or any of my other Motoko work  
Send me a DM if you want to contribute or put up a PR on github with any changes

---

<div class="post-metadata">

**Author:** ![mahmudsudo](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/mahmudsudo/32/10203_2.png) [@mahmudsudo](https://forum.dfinity.org/u/mahmudsudo)\
**Post date:** [July 10, 2025, 5:11pm UTC](https://forum.dfinity.org/t/motoko-showcase-liminal-an-http-framework/52159/7 "2025-07-10T17:11:10Z")

</div>

I am unable to dm and I will love to contribute
