Skip to main content

Routing

Gleece is designed to minimize HTTP routing boilerplate code, allowing developers to focus on business logic.

A route is essentially a function within a controller that is annotated with the @Route annotation.

Creating a Controller

First, create a controller struct that extends the GleeceController from Gleece's runtime. Annotate the controller with the base routing path, which will serve as the prefix for all routes in that controller.

You can also set the security schema and scopes for the entire controller (these can be overridden per route later).

import "github.com/gopher-fleece/runtime"

// @Route(/base-path)
// @Security(securitySchemaName, { scopes: ["read"] })
type ExampleController struct {
runtime.GleeceController // Embedding the GleeceController to inherit its methods
}

Creating a Route

Create a function in the controller to handle the logic and annotate it with the @Method and @Route annotations:

// @Method(GET)
// @Route(/simple-get)
func (ec *ExampleController) SimpleGet() (string, error) {
return "works", nil
}

To access data from the HTTP request, add parameters to the function along with corresponding annotations indicating their source:

// @Method(GET)
// @Route(/simple-get)
// @Query(name, { validate: "required" })
// @Response(200)
func (ec *ExampleController) SimpleGet(name string) (string, error) {
return "Hello " + name, nil
}

Parameters can be sourced from:

  • @Query - Query parameters in the URL
  • @Path - URL path parameters
  • @Header - HTTP headers
  • @Body - Request body
  • @FromField - Request urlencoded from fields

Multiple instances of @Query, @Path, @FromField, and @Header annotations is allowed in a single route.

However, only one @Body annotation is allowed per route.

info

Parameter Types

  • Primitive Types: All primitive types (and their pointer variants) are supported across all parameter sources, (exceps for @Body).
  • Struct Types: Only supported when used with the @Body parameter
warning

Body Processing Constraints

The @Body and @FromField annotations should not be used together in the same route as they represent different approaches to processing the request body payload:

  • @FromField - Processes individual fields from application/x-www-form-urlencoded request payload
  • @Body - Processes complete application/json request payload

Complete Example

Here's a comprehensive example of a controller with annotated routes:

example.ctrl.go
package controllers

import (
"github.com/google/uuid"
"github.com/gopher-fleece/runtime"
)

// @Description Example object
type Example struct {
// @Description Some text
Text string `json:"text" validate:"required"`
// @Description Some number
Number int `json:"number" validate:"gte=1"`
}

// @Tag(Example)
// @Route(/base-path)
// @Security(securitySchemaName, { scopes: ["read"] })
// @Description The Example API
type ExampleController struct {
runtime.GleeceController
}

// @Description Create an example
// @Method(POST)
// @Route(/logic/{example_name}/{example_id})
// @Query(email, { validate: "required,email" }) The exampler email
// @Path(id, { name: "example_id", validate:"gt=1" }) The example ID
// @Path(name, { name: "example_name" }) The example's name
// @Body(example) The example object
// @Header(origin, { name: "x-origin" }) The request origin
// @Header(trace) The trace ID
// @Response(200) The new ID of the example
// @ErrorResponse(500) Error when processing fails
// @Security(securitySchemaName, { scopes: ["read", "write"] })
func (ec *ExampleController) ExampleLogic(
id int,
email string,
name string,
origin string,
trace *string,
example Example) (string, error) {
newId := uuid.New()
return example.Text + " " + newId.String(), nil
}

For detailed information about all available annotations and their options, please refer to the Annotations page.