How to Add New API Endpoints in CasaOS: v1 vs v2 Routes Explained

To add new API endpoints in CasaOS, register Echo handlers manually in route/v1/route.go for the legacy v1 layer, or extend the OpenAPI specification and implement the generated ServerInterface methods for the modern v2 layer.

CasaOS is an open-source home cloud system that exposes two parallel HTTP API routing layers. When you need to add new API endpoints in CasaOS, you must understand the architectural differences between the hand-written v1 Echo router and the code-generated v2 OpenAPI server, as each requires a distinct implementation workflow.

Understanding CasaOS API Architecture (v1 vs v2)

CasaOS maintains two simultaneous API versions with different technical implementations:

v1 (Echo) Routing Layer

The v1 API uses explicit Echo framework routing. Each endpoint is registered manually in the InitV1Router() function found in route/v1/route.go. Handler files reside in route/v1/*.go (e.g., route/v1/file.go, route/v1/system.go) and follow standard Echo handler signatures: func(echo.Context) error.

v2 (OpenAPI-generated) Routing Layer

The v2 API is generated from an OpenAPI specification. The router builds automatically from a ServerInterface implementation provided by the CasaOS struct in route/v2/route.go. After modifying the spec in codegen/openapi.yaml, you run the code generator to create new interface methods, which you then implement in the CasaOS receiver.

Adding Endpoints to the CasaOS v1 API

To add a new endpoint to the legacy v1 layer, follow the manual registration pattern used by existing handlers.

Step 1: Create the Handler Function

Create a new file in route/v1/ or add to an existing handler file. The function must accept echo.Context and return an error.

// route/v1/hello.go
package v1

import "github.com/labstack/echo/v4"

// Hello returns a simple greeting for v1 clients.
func Hello(c echo.Context) error {
    return c.String(200, "Hello from CasaOS v1")
}

Step 2: Register the Route in InitV1Router

Edit route/v1/route.go to wire your handler to a path inside the InitV1Router() function.

// route/v1/route.go
func InitV1Router(e *echo.Echo) {
    v1Group := e.Group("/v1")
    {
        // ... existing routes ...
        v1Group.GET("/hello", Hello)  // ← new endpoint registration
    }
}

No code generation is required. Rebuild the binary to expose the new endpoint.

Adding Endpoints to the CasaOS v2 API

The v2 layer requires a contract-first approach using OpenAPI code generation.

Step 1: Extend the OpenAPI Specification

Add your new path and operation to the specification file, typically located at codegen/openapi.yaml.


# codegen/openapi.yaml

paths:
  /hello:
    get:
      summary: Simple greeting
      responses:
        '200':
          description: Greeting text
          content:
            text/plain:
              schema:
                type: string

Step 2: Regenerate the Server Code

Run the repository's code generation command to update the ServerInterface and router wiring.

make codegen

# or: go generate ./...

This creates a new method signature in the generated ServerInterface type (e.g., GetHello(ctx echo.Context) error) and updates the automatic routing logic.

Step 3: Implement the Generated Interface Method

Create or edit a file in route/v2/ to implement the method on the CasaOS struct. The method name matches the generated interface.

// route/v2/hello.go
package v2

import "github.com/labstack/echo/v4"

// GetHello implements the ServerInterface method generated from openapi.yaml.
func (c *CasaOS) GetHello(ctx echo.Context) error {
    return ctx.String(200, "Hello from CasaOS v2")
}

The generated router automatically maps /v2/hello to your GetHello method using the spec-defined HTTP method and path.

Choosing Between v1 and v2 for New Endpoints

Consider these factors when deciding which layer to extend:

  • Deployment speed: v1 allows rapid prototyping without build-time code generation. v2 requires regenerating server stubs after every OpenAPI change.
  • API contract stability: v2 guarantees consistency between the specification and implementation, making it ideal for external client integrations. v1 relies on manual documentation.
  • Client compatibility: Most existing CasaOS UI and integrations still consume v1 endpoints. Newer official clients (e.g., mobile apps) target v2.
  • Maintenance burden: v1 handlers are isolated, while v2 changes require synchronizing the spec, generated code, and implementation.

Use v1 for internal tooling or temporary endpoints. Use v2 for production-grade features that require versioned, documented contracts.

Complete Code Examples

v1 Example: Adding a /hello Endpoint

Handler implementation in route/v1/hello.go:

package v1

import "github.com/labstack/echo/v4"

func Hello(c echo.Context) error {
    return c.String(200, "Hello from CasaOS v1")
}

Registration in route/v1/route.go:

v1Group := e.Group("/v1")
{
    v1Group.GET("/hello", Hello)
}

v2 Example: Adding a /hello Endpoint

OpenAPI specification fragment in codegen/openapi.yaml:

/hello:
  get:
    summary: Simple greeting
    responses:
      '200':
        description: Greeting
        content:
          text/plain:
            schema:
              type: string

Implementation in route/v2/hello.go:

package v2

import "github.com/labstack/echo/v4"

func (c *CasaOS) GetHello(ctx echo.Context) error {
    return ctx.String(200, "Hello from CasaOS v2")
}

Key Files and Locations

  • route/v1/route.go – Echo router bootstrap where v1 endpoints are explicitly linked to handlers via InitV1Router().
  • route/v1/*.go – Concrete v1 handler implementations (e.g., file.go, system.go).
  • route/v2/route.go – Provides the ServerInterface implementation through the CasaOS struct for the generated v2 router.
  • codegen/openapi.yaml – Source OpenAPI specification that drives v2 code generation.
  • codegen/* – Auto-generated server code containing the ServerInterface type and automatic router wiring.
  • service/* – Business logic services consumed by both v1 and v2 handlers (e.g., service/file_upload.go).

Summary

  • For v1: Write a standard Echo handler function and register it manually in InitV1Router() inside route/v1/route.go.
  • For v2: Extend codegen/openapi.yaml, run make codegen, and implement the resulting method on the CasaOS struct in route/v2/.
  • Both API versions coexist in CasaOS, allowing you to select the appropriate layer based on your need for rapid development versus API contract stability.

Frequently Asked Questions

Can I mix v1 and v2 endpoints in the same CasaOS build?

Yes, both routing layers run simultaneously. The v1 router mounts under /v1 and the generated v2 router mounts under /v2, allowing gradual migration of functionality between versions without breaking existing clients.

Do I need to regenerate code for every v2 API change?

You only need to regenerate code when you modify the OpenAPI specification in codegen/openapi.yaml. If you are only changing the implementation logic within the existing interface methods, a standard go build suffices.

Which API version should I use for new features?

Use v2 for production-grade features that require API contract stability and external client support. Use v1 only for internal tooling, rapid prototypes, or when integrating with legacy CasaOS UI components that exclusively consume v1 routes.

Where is the OpenAPI specification located for v2 routes?

The specification is located at codegen/openapi.yaml (or the specific YAML file referenced by the codegen package in your CasaOS checkout), which serves as the single source of truth for the v2 API contract.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →