DEV Community

ben
ben

Posted on

Practical Combat of MAUI Embedded Web Architecture (3)Building a Scalable PicoServer REST API Framework

PicoServer
Source Code URL:
https://github.com/densen2014/MauiPicoAdmin

I. From Simple APIs to a Scalable Architecture

In the previous article Practical Combat of MAUI Embedded Web Architecture (II), we have successfully built multiple PicoServer APIs, such as:

  • /api/time
  • /api/product/list
  • /api/product/detail

These interfaces are already capable of:

  1. Handling HTTP requests
  2. Returning JSON data
  3. Supporting simple parameter reading

For example:
Access address: http://127.0.0.1:8090/api/product/list

Response:

{
  "code":0,
  "message":"ok",
  "data":[]
}
Enter fullscreen mode Exit fullscreen mode

This means our MAUI application has been equipped with local REST API service capabilities.

However, as the number of interfaces grows, new problems will gradually emerge:

  • All APIs are written in a single class
  • HTTP logic is mixed with business logic
  • Inconsistent response formats
  • Error handling becomes difficult to maintain

For example:

class PicoAdmin
{
    ProductList()
    ProductDetail()
    ProductAdd()
    ProductDelete()
}
Enter fullscreen mode Exit fullscreen mode

When the number of interfaces reaches:

  • 50+
  • 100+
  • 200+

The code will become difficult to maintain.

Therefore, this article will perform an architecture upgrade on PicoServer.

The goal is to build a:
scalable local REST API framework structure

Core objectives include:

  1. API modularization
  2. Controller/Service layered architecture
  3. Unified response structure
  4. Unified exception handling
  5. Clear project structure

II. Core Architecture of the REST API Framework

The upgraded API architecture is as follows:

HTTP Request
      │
      ▼
   PicoServer
      │
     Router
      │
   Controller
      │
    Service
      │
Data / Device / Logic
Enter fullscreen mode Exit fullscreen mode

Responsibilities of each layer:

Layer Function
Router Route distribution
Controller HTTP request handling
Service Business logic processing
Data / Device Data or device operations

This structure is very similar to common web frameworks (e.g., ASP.NET Core).

III. Recommended Project Directory Structure

To make the API more maintainable, the following directory structure can be adopted:

Server
 ├─ Controllers
 │   ├─ ProductController.cs
 │   └─ SystemController.cs
 │
 ├─ Services
 │   └─ ProductService.cs
 │
 ├─ Models
 │   └─ ApiResult.cs
 │
 └─ PicoServerHost.cs
Enter fullscreen mode Exit fullscreen mode

Directory responsibility description:

Directory Function
Controllers API route handling
Services Business logic implementation
Models Data models definition
PicoServerHost Server startup and route registration

This structure ensures clear, modularized code.

IV. Unified API Response Structure

In an API system, a unified response format is extremely important.

First, we define a response model:

ApiResult.cs

public class ApiResult
{
    public int Code { get; set; }
    public string Message { get; set; }
    public object Data { get; set; }

    public static ApiResult Success(object data)
    {
        return new ApiResult
        {
            Code = 0,
            Message = "ok",
            Data = data
        };
    }

    public static ApiResult Error(string msg)
    {
        return new ApiResult
        {
            Code = 1,
            Message = msg
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

Unified JSON response format:

{
  "code":0,
  "message":"ok",
  "data":{}
}
Enter fullscreen mode Exit fullscreen mode

Advantages:

  1. Unified front-end parsing
  2. Simplified error handling
  3. Standardized API structure

V. Service Layer (Business Logic)

Business logic should be separated from HTTP processing.

Create:

ProductService.cs

public class ProductService
{
    public List<object> GetProducts()
    {
        return new List<object>
        {
            new { id = 1, name = "Apple", price = 10 },
            new { id = 2, name = "Orange", price = 8 }
        };
    }

    public object GetProduct(string id)
    {
        return new { id = id, name = "Demo Product", price = 100 };
    }
}
Enter fullscreen mode Exit fullscreen mode

Responsibilities:

  1. Controller → calls Service
  2. Service → processes business logic

Benefits:

  1. Reusable business logic
  2. Simpler Controllers
  3. Easier maintenance and expansion

VI. Controller Layer (API Entry)

The Controller is responsible for:

  1. Receiving HTTP requests
  2. Reading parameters
  3. Calling Services
  4. Returning JSON

Create:

ProductController.cs

public class ProductController
{
    private ProductService service = new ProductService();

    public async Task List(HttpListenerRequest request, HttpListenerResponse response)
    {
        var data = service.GetProducts();

        var result = ApiResult.Success(data);

        string json = JsonSerializer.Serialize(result);

        response.ContentType = "application/json";
        await response.WriteAsync(json);
    }

    public async Task Detail(HttpListenerRequest request, HttpListenerResponse response)
    {
        string id = request.QueryString["id"];

        var data = service.GetProduct(id);

        var result = ApiResult.Success(data);

        string json = JsonSerializer.Serialize(result);

        response.ContentType = "application/json";
        await response.WriteAsync(json);
    }
}
Enter fullscreen mode Exit fullscreen mode

The responsibilities of the Controller are very clear:

HTTP Request
      ↓
Read Parameters
      ↓
Call Service
      ↓
Return JSON
Enter fullscreen mode Exit fullscreen mode

VII. Unified Route Registration

Next, create the server startup class:

PicoServerHost.cs

public class PicoServerHost
{
    private readonly WebAPIServer api = new WebAPIServer();

    public PicoServerHost()
    {
        RegisterRoutes();
        api.StartServer();
    }

    private void RegisterRoutes()
    {
        var product = new ProductController();

        api.AddRoute("/api/product/list", product.List);
        api.AddRoute("/api/product/detail", product.Detail);
    }
}
Enter fullscreen mode Exit fullscreen mode

The complete call flow becomes:

HTTP Request
      ↓
PicoServer Router
      ↓
Controller
      ↓
Service
      ↓
Data / Device
Enter fullscreen mode Exit fullscreen mode

This structure is already very close to a lightweight web framework.

VIII. Unified JSON Output Utility

To make Controllers more concise, we can encapsulate a utility method.

public static class HttpHelper
{
    public static async Task WriteJson(HttpListenerResponse response, object obj)
    {
        string json = JsonSerializer.Serialize(obj);
        await response.WriteAsync(json, contentType: "application/json");
    }
}
Enter fullscreen mode Exit fullscreen mode

Then the Controller can be written as:

await HttpHelper.WriteJson(response, ApiResult.Success(data));
Enter fullscreen mode Exit fullscreen mode

The code becomes much cleaner.

IX. Unified Exception Handling

In an API system, it is recommended to capture exceptions uniformly:

try
{
    var data = service.GetProducts();
    await HttpHelper.WriteJson(response, ApiResult.Success(data));
}
catch(Exception ex)
{
    await HttpHelper.WriteJson(response, ApiResult.Error(ex.Message));
}
Enter fullscreen mode Exit fullscreen mode

This ensures that:

  1. APIs always return JSON
  2. No HTML error pages will appear
  3. Frontends can handle errors uniformly

Finally, remove the class PicoAdmin from MauiProgram.cs, and change the initialization new PicoAdmin() to:

var picoAdmin = new PicoServerHost(); // Instantiate PicoServerHost to start PicoServer
var picoAdmin = new PicoServerHost();
Enter fullscreen mode Exit fullscreen mode

X. Complete Upgraded Architecture

After the transformation in this article, the overall system structure is as follows:

Browser / WebView
        ↓
     HTTP
        ↓
    PicoServer
        ↓
     Router
        ↓
    Controller
        ↓
     Service
        ↓
   Data / Device
Enter fullscreen mode Exit fullscreen mode

Advantages:

  1. Clear API structure
  2. Modular architecture
  3. Easy to extend
  4. Easy to maintain

At this point, we have built a:
lightweight embedded REST API framework

XI. Further Expansion Capabilities

Based on the current architecture, many additional capabilities can be extended, such as:

  1. Middleware system
  2. Logging
  3. Authentication
  4. Request filtering
  5. CORS
  6. Token-based login system
    • /api/login
    • /api/user/info
  7. Web Admin backend

Integrate with frontend frameworks:

  • Vue
  • React
  • Admin Dashboard

To implement a complete management system.

XII. Summary of This Article

In this article, we completed the architecture upgrade of the PicoServer API.

New capabilities added:

  1. API layered architecture
  2. Controller/Service architecture
  3. Unified JSON response
  4. Unified route registration
  5. Exception handling mechanism

At this point, our MAUI application has been equipped with:
a scalable local REST API service framework

This also serves as the foundation for building the Web Admin backend in subsequent steps.

Next Article Preview

The next article will cover a very critical part:

Practical Combat of MAUI Embedded Web Architecture (IV)
Static File Hosting and Frontend Framework Integration

We will implement:

  1. Hosting HTML/CSS/JS files
  2. Hosting Vue/React build artifacts
  3. Setting default homepage
  4. Building a true local Web Admin system

The final architecture will be:

Browser
   ↓
localhost:8090
   ↓
Web Admin UI
   ↓
PicoServer API
   ↓
MAUI Local Logic
Enter fullscreen mode Exit fullscreen mode

Top comments (0)