Skip to main content
Version: 0.4.x(Latest)

Introduction​

Route declarations cover the registration and binding of plugin HTTP routes. Source plugins register route contribution callbacks through pluginhost.Declarations.HTTP(), which are triggered uniformly when the host starts. Dynamic plugins declare route group bindings through pluginbridge.Declarations.Routes().

Capability Phase: Declaration

Supported Plugin Types: Source plugins, dynamic plugins

Capability Design​

Route Registration Model​

API Namespace​

All plugin routes are mounted under the /x/{plugin-id}/ namespace:

ConstantValueDescription
PluginAPINamespaceSegmentxAPI path segment
PluginAPINamespacePrefix/xAPI path prefix

The source plugin's RouteRegistrar.APIPrefix() returns /x/{plugin-id}. Dynamic plugin route prefixes follow the same convention.

Middleware System​

Source plugins access eight standard middlewares provided by the host through RouteMiddlewares:

MiddlewareDescription
NeverDoneCtxPrevents request context timeout
HandlerResponseUnified response format middleware
CORSCross-Origin Resource Sharing middleware
RequestBodyLimitRequest body size limit middleware
CtxRequest context injection middleware
AuthAuthentication middleware
TenancyTenant isolation middleware
PermissionPermission validation middleware

Global Middleware​

Source plugins can register global middleware through GlobalMiddlewareRegistrar that applies to all requests:

FieldDescription
scopeMiddleware scope
handlerMiddleware handler function

Route Binding​

Route bindings define the mapping between HTTP methods, paths, and handlers. Each binding includes the following metadata:

FieldDescription
MethodHTTP method (GET, POST, PUT, DELETE, etc.)
PathRoute path relative to the API prefix
AccessAccess mode: public (open) or login (requires authentication)
PermissionPermission identifier in the format {plugin-id}:{resource}:{action}
SummaryAPI summary
DescriptionAPI description

Interface Definition​

Source Plugin Interface​

Source plugins register route contribution callbacks through HTTP():

MethodDescription
RegisterRoutesRegisters a route contribution callback, triggered uniformly when the host starts

Callback handlers access route registration capabilities through HTTPRegistrar:

MethodDescription
Routes()Returns RouteRegistrar for registering route groups
GlobalMiddlewares()Returns GlobalMiddlewareRegistrar for registering global middleware
Services()Returns Services for accessing host capabilities

RouteRegistrar interface:

MethodDescription
APIPrefix()Returns the current plugin's API prefix
Group()Registers a route group
Middlewares()Returns the standard middleware collection
RouteBindings()Returns the list of registered route bindings
Err()Returns errors encountered during registration

The RouteGroup interface supports standard HTTP method registration:

MethodDescription
ALLRegisters routes for all methods
GETRegisters a GET route
POSTRegisters a POST route
PUTRegisters a PUT route
DELETERegisters a DELETE route
PATCHRegisters a PATCH route
HEADRegisters a HEAD route
CONNECTRegisters a CONNECT route
OPTIONSRegisters an OPTIONS route
TRACERegisters a TRACE route
GroupNested route group
MiddlewareRegisters group-level middleware
BindBinds a route handler
Err()Returns errors encountered during registration

Dynamic Plugin Interface​

Dynamic plugins declare route group bindings through pluginbridge.Declarations.Routes():

MethodDescription
GroupDeclares a route group binding with the specified API prefix and route package

Dynamic plugin routes are defined through RouteContract:

FieldTypeDescription
pathstringRoute path, must start with /
methodstringHTTP method, automatically converted to uppercase
accessstringAccess mode: public or login
permissionstringPermission identifier
summarystringAPI summary
descriptionstringAPI description
requestTypestringRequest DTO name

Usage​

Source Plugin Usage​

Source plugins register route contribution callbacks in init(), then use HTTPRegistrar within the callback to register routes:

func init() {
plugin := pluginhost.NewDeclarations("my-author-my-domain-my-cap")
if err := plugin.HTTP().RegisterRoutes(
pluginhost.ExtensionPointHTTPRouteRegister,
pluginhost.CallbackExecutionModeBlocking,
registerRoutes,
); err != nil {
panic(err)
}

if err := pluginhost.RegisterSourcePlugin(plugin); err != nil {
panic(err)
}
}

// In the registration callback
func registerRoutes(ctx context.Context, registrar pluginhost.HTTPRegistrar) error {
routes := registrar.Routes()
middlewares := routes.Middlewares()

routes.Group("/reports", func(group pluginhost.RouteGroup) {
group.Middleware(middlewares.Auth())
group.Middleware(middlewares.Tenancy())
group.Middleware(middlewares.Permission())

group.GET("/", listReports)
group.GET("/:id", getReport)
group.POST("/", createReport)
group.PUT("/:id", updateReport)
group.DELETE("/:id", deleteReport)
})

return routes.Err()
}

Registering global middleware:

func registerGlobalMiddleware(ctx context.Context, registrar pluginhost.HTTPRegistrar) error {
return registrar.GlobalMiddlewares().Bind(
"", // Empty string defaults to matching all paths "/*"
func(r *ghttp.Request) {
// Global middleware logic
r.Middleware.Next()
},
)
}

Dynamic Plugin Usage​

Dynamic plugins declare route group bindings through Routes():

func RegisterPlugin(ctx context.Context) error {
decl := pluginbridge.NewDeclarations()

// Declare route group binding
err := decl.Routes().Group("/reports", "controllers")
if err != nil {
return err
}

return nil
}

Dynamic plugin route controllers use standard HTTP method signatures:

//go:build wasm

package controllers

type ReportController struct{}

func (c *ReportController) Get(ctx context.Context, req *GetReportReq) (*ReportResp, error) {
// Handle GET request
}

func (c *ReportController) Post(ctx context.Context, req *CreateReportReq) (*ReportResp, error) {
// Handle POST request
}

The build tool automatically generates RouteContract and embeds it in the lina.plugin.backend.routes custom section of the .wasm artifact.

Design Constraints​

  • Routes are mounted under the plugin namespace. All plugin routes must be under the /x/{plugin-id}/ prefix.
  • Registration callbacks trigger at startup. Source plugin route registration callbacks are triggered uniformly when the host starts, not as runtime dynamic registration.
  • Middleware chains are assembled by plugins. Plugins select and compose middleware based on business needs; the host does not enforce middleware ordering.
  • Permission identifiers must follow convention. Permission identifiers must match the {plugin-id}:{resource}:{action} format.
  • Dynamic plugin routes are declared through contracts. Dynamic plugin routes are declared at build time through RouteContract and do not support runtime dynamic registration.
  • Route paths must start with /. The host validates route path format and rejects invalid paths.