okapi

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 24, 2026 License: MIT Imports: 45 Imported by: 11

README

OKAPI - Lightweight Go Web Framework with OpenAPI 3 & Swagger UI

Tests Go Report Card Go Go Reference codecov GitHub Release

Okapi is a modern, minimalist HTTP web framework for Go, inspired by FastAPI's elegance. Designed for simplicity, performance, and developer happiness, it helps you build fast, scalable, and well-documented APIs with minimal boilerplate.

The framework is named after the okapi (/oʊˈkɑːpiː/), a rare and graceful mammal native to the rainforests of the northeastern Democratic Republic of the Congo. Just like its namesake, which resembles a blend of giraffe and zebra. Okapi blends simplicity and strength in a unique, powerful package.

Okapi logo


Key Features

Intuitive & Expressive API – Clean, declarative syntax for effortless route and middleware definition.

Automatic Request Binding – Seamlessly parse JSON, XML, form data, query params, headers, and path variables into structs.

Built-in Auth & Security – Native support for JWT, Basic Auth, and custom middleware.

Standard Library Compatibility - Integrates seamlessly with Go’s net/http standard library.

Blazing Fast Routing – Optimized HTTP router with low overhead for high-performance applications.

First-Class DocumentationOpenAPI 3.0 & Swagger UI integrated out of the box—auto-generate API docs with minimal effort.

✔ Dynamic Route Management – Easily enable or disable individual routes or groups, with automatic Swagger sync and no code commenting.

Modern Tooling

  • Route grouping & middleware chaining
  • Static file serving
  • Templating engine support
  • CORS management
  • Fine-grained timeout controls

Developer Experience

  • Minimal boilerplate
  • Clear error handling
  • Structured logging
  • Easy testing

Built for speed, simplicity, and real-world use whether you're prototyping or running in production.


Why Choose Okapi?
  • Easy to Learn: With familiar Go syntax and intuitive APIs, you can be productive in minutes—even on your first project.
  • Lightweight and Unopinionated: Okapi is built from the ground up and doesn’t wrap or build on top of another framework. It gives you full control without unnecessary abstraction or bloat.
  • Highly Flexible: Designed to adapt to your architecture and workflow—not the other way around.
  • Built for Production: Fast, reliable, and efficient under real-world load. Okapi is optimized for performance without sacrificing developer experience.
  • Standard Library Compatibility: Integrates seamlessly with Go’s net/http standard library, making it easy to combine Okapi with existing Go code and tools.
  • Automatic OpenAPI Documentation: Generate comprehensive OpenAPI specs automatically for every route, keeping your API documentation always up to date with your code.
  • Dynamic Route Management: Enable or disable routes and route groups at runtime. No need to comment out code, just toggle behavior cleanly and efficiently.

Ideal for:

  • High-performance REST APIs
  • Composable microservices
  • Rapid prototyping
  • Learning & teaching Go web development

Whether you're building your next startup, internal tools, or side projects, Okapi scales with you.


Installation

mkdir myapi && cd myapi
go mod init myapi
go get github.com/jkaninda/okapi@latest

Quick Start

Create a file named main.go:

Example
Hello
package main

import (
  "github.com/jkaninda/okapi"
)
func main() {

	o := okapi.Default()
	
	o.Get("/", func(c *okapi.Context) error {
		return c.OK(okapi.M{"message": "Hello from Okapi Web Framework!","License":"MIT"})
	})
	// Start the server
	if err := o.Start(); err != nil {
		panic(err)
	}
}

Run your server:

go run main.go

Visit http://localhost:8080 to see the response.

{
  "License": "MIT",
  "message": "Hello from Okapi Web Framework!"
}
Simple HTTP POST
package main

import (
  "github.com/jkaninda/okapi"
  "net/http"
)

type Response struct {
  Success bool   `json:"success"`
  Message string `json:"message"`
  Data    Book   `json:"data"`
}
type Book struct {
  Name  string `json:"name"  maxLength:"50" minLength:"5" required:"true" description:"Book name"`
  Price int    `json:"price" min:"1" max:"100" required:"true" description:"Book price"`
}
type ErrorResponse struct {
  Success bool        `json:"success"`
  Status  int         `json:"status"`
  Details any `json:"details"`
}

func main() {
  // Create a new Okapi instance with default config
  o := okapi.Default()

  o.Post("/books", func(c *okapi.Context) error {
    book := Book{}
    err := c.Bind(&book)
    if err != nil {
      return c.ErrorBadRequest(ErrorResponse{Success: false, Status: http.StatusBadRequest, Details: err.Error()})
    }
    response := Response{
      Success: true,
      Message: "This is a simple HTTP POST",
      Data:    book,
    }
    return c.OK(response)
  },
    // OpenAPI Documentation
    okapi.DocSummary("Create a new Book"), // Route Summary
    okapi.DocRequestBody(Book{}),                                   //  Request body
    okapi.DocResponse(Response{}),                                  // Success Response body
    okapi.DocResponse(http.StatusBadRequest, ErrorResponse{}), // Error response body

  )
  o.Get("/books/{id:int}", func(c *okapi.Context) error {
        bookId := c.Param("id") 
		return c.JSON(200, okapi.M{"book_id": bookId})
	})

    // Start the server
  if err := o.Start(); err != nil {
    panic(err)
  }
}
Interactive API docs

Now go to http://localhost:8080/docs to see the interactive API documentation generated by Okapi.

Alternative API docs

And now, go to http://localhost:8080/redoc to see the Redoc documentation.


Routing

Okapi supports all standard HTTP methods:

o.Get("/books", getBooks)
o.Post("/books", createBook)
o.Get("/books/:id", getBook)
o.Put("/books/:id", updateBook)
o.Delete("/books/:id", deleteBook)
Route Groups

Route groups in Okapi allow you to organize your routes under a common path prefix, apply middleware selectively, and control group-level behaviors like deprecation or disabling. This feature makes it easy to manage API versioning, logical route separation, and access control.

Features:
  • Nesting: Define sub-groups within a parent group to build hierarchical route structures.
  • Middleware: Attach middleware to a group to apply it to all nested routes.
  • Deprecation: Mark a group as deprecated to indicate it's being phased out (useful for OpenAPI documentation).
  • Disabling: Temporarily disable a group to return 404 Not Found for all its routes.
  • Tagging: Automatically tag routes in OpenAPI documentation based on group names.
Example:
o := okapi.Default()

// Create the main API group
api := o.Group("/api")

// Versioned subgroups
v1 := api.Group("/v1").Deprecated()        // Marked as deprecated
v2 := api.Group("/v2")                     // Active version
v3 := api.Group("v3", testMiddleware).Disable() // Disabled, returns 404

// Define routes
v1.Get("/books", getBooks)
v2.Get("/books", v2GetBooks)
v3.Get("/books", v3GetBooks) // Will not be accessible

// Admin subgroup with middleware
admin := api.Group("/admin", adminMiddleware)
admin.Get("/dashboard", getDashboard)

This structure improves route readability and maintainability, especially in larger APIs.


Path Syntax Examples

Okapi supports flexible and expressive route path patterns, including named parameters and wildcards:

o.Get("/books/{id}", getBook)       // Named path parameter using curly braces
o.Get("/books/{id:int}", getBook)    // Named path parameter using curly braces, "id" documented as integer in OpenAPI
o.Get("/books/:id", getBook)        // Named path parameter using colon prefix
o.Get("/*", getBook)                // Catch-all wildcard (matches everything)
o.Get("/*any", getBook)             // Catch-all with named parameter (name is ignored)
o.Get("/*path", getBook)            // Catch-all with named parameter

Use whichever syntax feels most natural — Okapi normalizes both {} and : styles for named parameters and supports glob-style wildcards for flexible matching.


Request Handling

Path Parameters
o.Get("/books/:id", func(c *okapi.Context) error {
	id := c.Param("id")
	return c.String(http.StatusOK, id)
})
Query Parameters
o.Get("/books", func(c *okapi.Context) error {
	name := c.Query("name")
	return c.String(http.StatusOK, name)
})

Handling Form Data

Multipart Form (multipart/form-data)

Handle standard form fields and file uploads:

o.Post("/books", func(c *okapi.Context) error {
	name := c.FormValue("name")
	price := c.FormValue("price")

	logo, err := c.FormFile("logo")
	if err != nil {
        return c.AbortBadRequest("Bad request", err)
	}
	file, err := logo.Open()
	if err != nil {
            return c.AbortBadRequest("Bad request", err)
	}
	defer file.Close()
	// You can now read or save the uploaded file
	return c.String(http.StatusOK, "File uploaded successfully")
})

Struct Binding

Okapi provides powerful and flexible request binding that automatically maps incoming request data into Go structs. It supports two complementary binding styles:


1. Flat Binding

In Flat Binding, you define a single struct where each field can be sourced from any part of the request.

This style allows you to mix request body fields (JSON, XML, YAML, Protobuf, Form) with query parameters, headers, cookies, and path parameters — all within a single struct.

type Book struct {
	ID     int    `json:"id" path:"id" query:"id" form:"id"`
	Name   string `json:"name" xml:"name" form:"name" minLength:"4" maxLength:"50" required:"true"`
	Price  int    `json:"price" form:"price" required:"true"`
	Logo   *multipart.FileHeader `form:"logo" required:"true"`
	Content string `header:"Content-Type" json:"content-type" xml:"content-type" required:"true"`
	// Supports both ?tags=a&tags=b and ?tags=a,b
	Tags []string `form:"tags" query:"tags" default:"a,b"`
    Year  int    `json:"year"  yaml:"year" description:"Book price" deprecated:"true"`

}

o.Post("/books", func(c *okapi.Context) error {
	book := &Book{}
	if err := c.Bind(book); err != nil {
		return c.ErrorBadRequest(err)
	}
	return c.JSON(http.StatusOK, book)
})

In Body Field Binding, your struct defines a dedicated Body field (or a field tagged as body) that represents the main request payload. Other fields in the struct represent query params, headers, cookies, or path parameters.

This pattern promotes a clean separation between metadata and the request content, making it ideal for larger APIs and OpenAPI generation.

type BookRequest struct {
	Body struct {
		Name  string `json:"name" minLength:"4" maxLength:"50" required:"true"`
		Price int    `json:"price" required:"true"`
		Logo  *multipart.FileHeader `form:"logo" required:"true"`
	} `json:"body"` // Request body

	ID        int      `json:"id" param:"id" query:"id"`        // from path or query
	Tags      []string `query:"tags" default:"a,b"`             // supports ?tags=a&tags=b and ?tags=a,b
	APIKey    string   `header:"X-API-Key" required:"true"`     // from header
	SessionID string   `cookie:"session_id" json:"session_id"`  // from cookie
}

o.Post("/books", func(c *okapi.Context) error {
	bookReq := &BookRequest{}
	if err := c.Bind(bookReq); err != nil {
		return c.ErrorBadRequest(err)
	}
	return c.Respond(bookReq)
})

Supported Sources

Source Tag(s) Description
Path parameters path, param Extracted from path variables (e.g. /books/:id or /books/{id:int}).
Query parameters query Parses query strings; supports repeated arrays (?tags=a&tags=b) and comma-separated values.
Headers header Reads values from HTTP request headers.
Cookies cookie Reads values from cookies.
Form fields form Supports both application/x-www-form-urlencoded and multipart/form-data (file uploads).
JSON body json Decodes when Content-Type: application/json.
XML body xml Decodes when Content-Type: application/xml.
OpenAPI & Documentation Tags

These tags influence generated OpenAPI documentation:

Tag(s) Description
description, doc Adds documentation metadata to the field.
deprecated:"true" Marks the field as deprecated in OpenAPI.
hidden:"true" Excludes the field from the generated OpenAPI documentation.

Validation and Default Values

Okapi provides declarative validation and automatic default value assignment using struct tags. This allows developers to enforce constraints on input data and ensure fields have sensible defaults.

Basic Validation Tags
Field Type Tag Description
string minLength:"10" Ensures the string has at least 10 characters.
string maxLength:"50" Ensures the string does not exceed 50 characters.
number min:"5" Ensures the number is at least 5.
number max:"100" Ensures the number does not exceed 100.
any default:"..." Assigns a default value if the field is empty.
any required:"true" Marks the field as mandatory.
any format:"" Enables format validation for the field.
Data Type & Format Validation
Field Type Tag / Attribute Description
date format:"date" Validates the field as a date (YYYY-MM-DD).
date-time format:"date-time" Validates the field as a date and time (RFC3339).
email format:"email" Validates the field as a valid email address.
duration format:"duration" Validates the field as a Go duration (e.g., 1h30m).
regex format:"regex" pattern="^\+?[1-9]\d{1,14}$" Validates the field using a custom regular expression.
enum enum:"pending,paid,canceled" Restricts the field to one of the listed values.

Response Struct Binding

When using c.Respond(), Okapi automatically serializes the response struct into the HTTP response.

It inspects struct tags to determine:

  • the HTTP status code
  • response headers
  • cookies
  • and the response body (encoded according to the Accept header).
type BookResponse struct {
	// HTTP status code (default: 200)
	Status int `status:"true" json:"status"`

	// Response body
	Body struct {
		ID    int    `json:"id"`
		Name  string `json:"name"`
		Price int    `json:"price"`
	} `json:"body"`

	// Custom headers
	XRequestID string `header:"X-Request-ID" json:"x-request-id"`

	// Cookies
	SessionID string `cookie:"session_id" json:"session_id"`
}

o.Get("/books/:id", func(c *okapi.Context) error {
	book := BookResponse{
		Status: http.StatusOK,
		Body: struct {
			ID    int    `json:"id"`
			Name  string `json:"name"`
			Price int    `json:"price"`
		}{
			ID:    1,
			Name:  "The Great Go Book",
			Price: 20,
		},
		XRequestID: "req-12345",
		SessionID:  "sess-67890",
	}
	return c.Respond(book)
})

Middleware

Built-in Example (Basic Auth)
auth := okapi.BasicAuth{
	Username: "admin",
	Password: "password",
	Realm:    "Restricted",
    ContextKey: "user",// where to store the username e.g. "user", default(username)

}
// Global middleware
o.Use(auth.Middleware)
// Attach SingleRouteMiddleware to this route only, without affecting others
o.Get("/", SingleRouteMiddlewareHandler).Use(SingleRouteMiddleware)

// Group middleware
o.Get("/admin", adminHandler)

JWT Middleware

Okapi includes powerful and flexible JWT middleware to secure your routes with JSON Web Tokens. It supports multiple signing mechanisms, key sources, claim validation strategies, and OpenAPI integration.

Features
  • HS256 symmetric signing via SigningSecret
  • RS256 and other asymmetric algorithms via RSAKey
  • Remote JWKS discovery via JwksUrl (e.g., OIDC or Auth0)
  • Local JWKS via JwksFile
  • Claims validation with ClaimsExpression or ValidateClaims
  • OpenAPI integration with .WithBearerAuth()
  • Selective claim forwarding using ForwardClaims
Example: Basic HS256 Authentication
jwtAuth := okapi.JWTAuth{
    SigningSecret: []byte("supersecret"),      // Shared secret for HS256
    TokenLookup:   "header:Authorization",     // Token source: header, query, or cookie (default: header:Authorization)
    ContextKey:    "user",                     // Key under which claims are stored in context
}
Example: Remote JWKS (OIDC, Auth0)
jwtAuth := okapi.JWTAuth{
    JwksUrl:     "https://example.com/.well-known/jwks.json",  // Remote JWKS URL
    TokenLookup: "header:Authorization",
    ContextKey:  "user",
}
Claims Expression (Optional)

Use ClaimsExpression to define rules for validating claims using simple expressions. This is ideal for access control based on roles, scopes, or other custom claim logic.

Supported Functions
  • Equals(field, value)
  • Prefix(field, prefix)
  • Contains(field, val1, val2, ...)
  • OneOf(field, val1, val2, ...)
Logical Operators
  • ! — NOT
  • && — AND (evaluated before OR)
  • || — OR (evaluated after AND)

Example:

jwtAuth := okapi.JWTAuth{
    SigningSecret:    []byte("supersecret"),
    ClaimsExpression: "Equals(`email_verified`, `true`) && Equals(`user.role`, `admin`) && Contains(`tags`, `gold`, `silver`)",
    TokenLookup:      "header:Authorization",
    ContextKey:       "user",
    ForwardClaims: map[string]string{
        "email": "user.email",
        "role":  "user.role",
        "name":  "user.name",
    },
}
Forwarding Claims to Context

ForwardClaims lets you expose specific claims to your handlers via the request context. This keeps handlers decoupled from the full JWT while retaining useful information.

Supports dot notation for nested claims.

Example:

jwtAuth.ForwardClaims = map[string]string{
    "email": "user.email",
    "role":  "user.role",
    "name":  "user.name",
}

Get these claims in your handler:

func whoAmIHandler(c *okapi.Context) error {
    email := c.GetString("email")
    if email == "" {
        return c.AbortUnauthorized("Unauthorized", fmt.Errorf("user not authenticated"))
    }
	slog.Info("Who am I am ", "email", email, "role", c.GetString("role"), "name", c.GetString("name"))
// Respond with the current user information
    return c.JSON(http.StatusOK, M{
                "email": email,
                "role":  c.GetString("role"),
                "name":  c.GetString("name"),
		}, )
}
Custom Claim Validation

You can define your own ValidateClaims function to fully control claim checks. Use this for advanced logic beyond what ClaimsExpression supports. You can combine this with ClaimsExpression for more complex scenarios.

Example:

jwtAuth.ValidateClaims = func(c *Context, claims jwt.Claims) error {
    method := c.Request().Method
    slog.Info("Request method,", "method", method)
    mapClaims, ok := claims.(jwt.MapClaims)
    if !ok {
        return errors.New("invalid claims type")
    }

    if emailVerified, _ := mapClaims["email_verified"].(bool); !emailVerified {
        return errors.New("email not verified")
    }

    if role, _ := mapClaims["role"].(string); role != "admin" {
        return errors.New("unauthorized role")
    }

    return nil
}
Custom Error Handling

The OnUnauthorized handler lets you customize responses for failed JWT validations, including:

  • Missing or malformed tokens
  • Expired tokens
  • Failed claims validation (via either ClaimsExpression or ValidateClaims)

Example Implementation:

auth := okapi.JWTAuth{
    Audience:      "okapi.example.com",
    SigningSecret: SigningSecret,
    // ... other configurations
    OnUnauthorized: func(c *okapi.Context) error {
        // Return custom unauthorized response
        return c.ErrorUnauthorized("Unauthorized")
    },
}
Protecting Routes

Apply the JWT middleware to route groups or individual routes to require authentication.

// Apply middleware globally (optional)
o.Use(jwtAuth.Middleware)

admin := o.Group("/admin", jwtAuth.Middleware). // Protect /admin routes
    WithBearerAuth()                            // Adds Bearer auth to OpenAPI docs

admin.Get("/users", adminGetUsersHandler)       // Secured route

// Attach SingleRouteMiddleware to this route only, without affecting others
o.Get("/", SingleRouteMiddlewareHandler).Use(SingleRouteMiddleware)

CORS middleware
cors := okapi.Cors{AllowedOrigins: []string{"http://localhost:8080", "https://example.com"}, AllowedHeaders: []string{}}
o := okapi.New(okapi.WithCors(cors))
	o.Get("/", func(c *okapi.Context) error {
		return c.String(http.StatusOK, "Hello World!")
	})
Custom Middleware
func customMiddleware(next okapi.HandlerFunc) okapi.HandlerFunc {
	return func(c *okapi.Context) error {
		start := time.Now()
		err := next(c)
		log.Printf("Request took %v", time.Since(start))
		return err
	}
}

o.Use(customMiddleware)
Std Middleware
o.UseMiddleware(func(handler http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			slog.Info("Hello Go standard HTTP middleware function")
			handler.ServeHTTP(w, r)
		})

	})

OpenAPI / Swagger Integration

Okapi provides automatic OpenAPI (Swagger) documentation generation with a built-in interactive UI. The documentation is dynamically generated from your route definitions, ensuring it always stays in sync with your API implementation.

Quick Start
  • Using okapi.Default() Documentation is enabled by default and served at /docs.
o := okapi.Default() // Docs available at /docs
  • Using okapi.New() with WithOpenAPIDocs() If you initialize Okapi with okapi.New(), documentation is disabled by default. You can enable it with WithOpenAPIDocs(), this approach also allows you to dynamically disable the documentation at runtime (e.g., in production) based on environment variables or configuration.
o := okapi.New() // Disabled
if os.Getenv("ENABLE_DOCS") == "true" {
	o.WithOpenAPIDocs() 
}
Enabling with Custom Configuration

You can customize the OpenAPI documentation by passing a configuration object to WithOpenAPIDocs().

o := okapi.New().WithOpenAPIDocs(
    okapi.OpenAPI{
        Title:      "Example API",
        Version:    "1.0.0",
        Contact: okapi.Contact{
            Name:  "API Support",
            Email: "support@example.com",
        },
    },
)
Security Schemes

You can define authentication mechanisms for your API, such as Basic Auth, Bearer tokens, and OAuth2 flows.

o.WithOpenAPIDocs(okapi.OpenAPI{
    Title:   "Okapi Web Framework Example",
    Version: "1.0.0",
    License: okapi.License{Name: "MIT"},
    SecuritySchemes: okapi.SecuritySchemes{
        {
            Name:   "basicAuth",
            Type:   "http",
            Scheme: "basic",
        },
        {
            Name:         "bearerAuth",
            Type:         "http",
            Scheme:       "bearer",
            BearerFormat: "JWT",
        },
        {
            Name: "OAuth2",
            Type: "oauth2",
            Flows: &okapi.OAuthFlows{
                AuthorizationCode: &okapi.OAuthFlow{
                    AuthorizationURL: "https://auth.example.com/authorize",
                    TokenURL:         "https://auth.example.com/token",
                    Scopes: map[string]string{
                        "read":  "Read access",
                        "write": "Write access",
                    },
                },
            },
        },
    },
})
Applying Security Schemes to Routes

You can apply security schemes to individual routes or entire route groups.

Example – Applying to a Single Route
var bearerAuthSecurity = []map[string][]string{
    {"bearerAuth": {}},
}

o.Get("/books", getBooksHandler).WithSecurity(bearerAuthSecurity...)
Example Applying to a Group of Routes
api := o.Group("/api", jwtMiddleware).WithSecurity(bearerAuthSecurity)
api.Get("/", apiHandler)

Tip: If you are defining routes using RouteDefinition, you can also set security directly using the Security field.


Documenting Routes in Okapi

Okapi makes it simple to attach OpenAPI documentation to your routes. You can choose between composable functions for concise definitions or a fluent builder for more flexibility.


1. Composable Functions (Direct Style)

This is the simplest and most readable approach — ideal for small or medium routes. Each okapi.Doc* function documents a specific part of your endpoint.

o.Get("/books", getBooksHandler,
    okapi.DocSummary("List all available books"),
    okapi.DocTags("Books"),
    okapi.DocQueryParam("author", "string", "Filter by author name", false),
    okapi.DocQueryParam("limit", "int", "Maximum results to return (default 20)", false),
    okapi.DocResponseHeader("X-Client-Id", "string", "Client ID of the request"),
    okapi.DocResponse([]Book{}), // Shorthand for DocResponse(200, value)
    okapi.DocResponse(400, ErrorResponse{}),
    okapi.DocResponse(401, ErrorResponse{}),
)

When to use: Use this style for routes with straightforward request/response documentation.


2. Fluent Builder Style

For more complex or dynamic documentation setups, use the builder pattern via okapi.Doc().

This approach allows chaining multiple configuration methods and calling .Build() (or .AsOption()) at the end.

o.Post("/books", createBookHandler,
    okapi.Doc().
        Summary("Add a new book to the inventory").
        Tags("Books").
        BearerAuth().
        ResponseHeader("X-Client-Id", "string", "Client ID of the request").
        RequestBody(BookRequest{}).
        Response(201, Book{}).
        Response(400, ErrorResponse{}).
        Response(401, ErrorResponse{}).
        Build(),
)

When to use: Use this style for advanced or reusable route documentation — for example, when generating parts dynamically or reusing shared doc definitions.


3. Available Documentation Options
Method Description
DocSummary() / Doc().Summary() Short endpoint summary
DocTags() / Doc().Tags() Group endpoints under tags
DocBearerAuth() / Doc().BearerAuth() Enable Bearer token authentication
DocRequestBody() / Doc().RequestBody() Document request body schema
DocResponse() / Doc().Response() Document response schema or status codes
DocPathParam() / Doc().PathParam() Document path parameters
DocQueryParam() / Doc().QueryParam() Document query parameters
DocHeader() / Doc().Header() Document request headers
DocResponseHeader() / Doc().ResponseHeader() Document response headers
DocDeprecated() / Doc().Deprecated() Mark route as deprecated

4. Body Field Style (Advanced Struct Binding)

The Body Field Style allows you to define a struct where a dedicated Body field (or a field tagged as body) represents the main request payload. Other fields in the same struct can represent query parameters, headers, cookies, or path parameters.

// BookRequest defines a request with structured fields and validations.
type BookRequest struct {
  Body struct {
    Name  string                `json:"name" minLength:"4" maxLength:"50" required:"true"`
    Price int                   `json:"price" required:"true"`
    Logo  *multipart.FileHeader `form:"logo" required:"true"`
  } `json:"body"` // Request body section

  ID        int      `param:"id" query:"id"`             // from path or query
  Tags      []string `query:"tags" default:"a,b"`        // supports ?tags=a&tags=b and ?tags=a,b
  APIKey    string   `header:"X-API-Key" required:"true"`// from header
  SessionID string   `cookie:"session_id"`               // from cookie
}
type BookResponse struct {
	Version string `header:"X-Version"`
	Status  int // Response Status Code
	Body    Book // Response Body
}

5. Registering Routes with Body Field Style
Using okapi.Request() and okapi.Response()
o.Post("/books", func(c *okapi.Context) error {
    req := &BookRequest{}
	// Validate request body
    if err := c.Bind(req); err != nil {
        return c.ErrorBadRequest(err)
    }
	// Respond
    return c.Respond(req)
},
    okapi.Request(&BookRequest{}),  // Request body
    okapi.Response(&BookResponse{}), // Response body
)

Respond serializes the output struct into the HTTP response. It inspects struct tags to automatically set headers, cookies, and status code, and encodes the response body in the format requested by the Accept header.

Using .WithIO() for request and response
o.Post("/books", func(c *okapi.Context) error {
    req := &BookRequest{}
    if err := c.Bind(req); err != nil {
        return c.ErrorBadRequest(err)
    }
    return c.Respond(req)
}).WithIO(&BookRequest{}, &BookRequest{}) // Both request & response
Using .WithInput() for request only
o.Post("/books", func(c *okapi.Context) error {
    req := &BookRequest{}
    if err := c.Bind(req); err != nil {
        return c.ErrorBadRequest(err)
    }
    return c.Respond(req)
}).WithInput(&BookRequest{}) // Request only
Using .WithOutput() for response only
o.Post("/books", func(c *okapi.Context) error {
    req := &BookRequest{}
    if err := c.Bind(req); err != nil {
        return c.ErrorBadRequest(err)
    }
    return c.Respond(req)
}).WithOutput(&BookRequest{}) // Response only

Summary
Style Best For
Composable Functions Simple, direct, quick to write
Fluent Builder (Doc()) Complex or reusable route docs
Body Field Style Declarative binding & validation
WithIO / WithInput / WithOutput Auto-document request/response schemas

Swagger UI Preview

Okapi automatically generates Swagger UI for all routes:

Okapi Swagger Interface

Redoc Preview

Okapi Redoc Interface


Enabling and Disabling Routes & Groups

Okapi gives you flexible control over your API by allowing routes and route groups to be dynamically enabled or disabled. This is a clean and efficient alternative to commenting out code when you want to temporarily remove endpoints.

Overview

You can disable:

  • Individual routes — blocks access to a specific endpoint
  • Route groups — disables an entire section of your API, including all nested routes

This behavior is reflected both in runtime responses and API documentation.

Type HTTP Response Swagger Docs Affects Child Routes
Disabled Route 404 Not Found Hidden N/A
Disabled Group 404 Not Found Hidden Yes — all nested
Key Features
  • Disabled routes/groups return a 404 Not Found
  • Automatically excluded from Swagger/OpenAPI documentation
  • Disabling a group recursively disables all nested routes and sub-groups
  • No need to comment out code — just call .Disable() or .Enable()
Use Cases
  • Temporarily removing endpoints during maintenance
  • Controlling access based on feature flags
  • Deprecating old API versions
  • Creating toggleable test or staging routes
Usage Example
app := okapi.Default()

// Create the root API group
api := app.Group("api")

// Define and disable v1 group
v1 := api.Group("v1").Disable() // All v1 routes return 404 and are hidden from docs
v1.Get("/", func(c *okapi.Context) error {
    return c.OK(okapi.M{"version": "v1"})
})

// Define active v2 group
v2 := api.Group("v2")
v2.Get("/", func(c *okapi.Context) error {
    return c.OK(okapi.M{"version": "v2"})
})

// Start the server
if err := app.Start(); err != nil {
    panic(err)
}
Behavior Details
  • Disabled Route:

    • Responds with 404 Not Found
    • Excluded from Swagger docs
  • Disabled Group:

    • All nested routes and sub-groups are recursively disabled
    • All affected routes are hidden from Swagger

To re-enable any route or group, simply call the .Enable() method or remove the .Disable() call.


Templating

Using a Custom Renderer
o.Renderer = okapi.RendererFunc(func(w io.Writer, name string, data interface{}, c *okapi.Context) error {
	tmpl, err := template.ParseFiles("templates/" + name + ".html")
	if err != nil {
		return err
	}
	return tmpl.ExecuteTemplate(w, name, data)
})
Or Using a Struct-Based Renderer
type Template struct {
	templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c *okapi.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

tmpl := &Template{
	templates: template.Must(template.ParseGlob("templates/*.html")),
}
o.With().WithRenderer(&Template{templates: template.Must(template.ParseGlob("public/views/*.html"))})

// or
// o.With().WithRenderer(tmpl)

Rendering a View
o.Get("/", func(c *okapi.Context) error {
	return c.Render(http.StatusOK, "welcome", okapi.M{
		"title":   "Welcome Page",
		"message": "Hello from Okapi!",
	})
})

Static File Serving

Serve static assets and individual files:

// Serve a single file
o.Get("/favicon.ico", func(c *okapi.Context) error {
	c.ServeFile("public/favicon.ico")
	return nil
})

// Serve an entire directory
o.Static("/static", "public/assets")

TLS Server

// Initialize TLS configuration for secure HTTPS connections
    tls, err := okapi.LoadTLSConfig("path/to/cert.pem", "path/to/key.pem", "", false)
    if err != nil {
    panic(fmt.Sprintf("Failed to load TLS configuration: %v", err))
    }
    // Create a new Okapi instance with default config
    // With OpenAPI enabled, /docs
    o := okapi.Default()
    // Use HTTPS
    // o := okapi.New(okapi.WithTLS(tls))
    
    // Configure a secondary HTTPS server listening on port 8443
    // This creates both HTTP (8080) and HTTPS (8443) endpoints
    o.With(okapi.WithTLSServer(":8443", tls))
    
    // Register application routes and handlers
    o.Get("/", func(c *okapi.Context) error {
    return c.JSON(http.StatusOK, okapi.M{
    "message": "Welcome to Okapi!",
    "status":  "operational",
    })
    })
    // Start the servers
    // This will launch both HTTP and HTTPS listeners in separate goroutines
    log.Println("Starting server on :8080 (HTTP) and :8443 (HTTPS)")
    if err := o.Start(); err != nil {
    panic(fmt.Sprintf("Server failed to start: %v", err))
    }
    }

Context

Okapi provides a powerful and lightweight Context object that wraps the HTTP request and response. It is designed to simplify handling HTTP requests by offering a clean and expressive API for accessing request data, binding parameters, sending responses, and managing errors.

The Context is passed to all route handlers and supports:

  • Accessing path parameters, query parameters, form values, file uploads, and headers
  • Binding request data to structs using various formats (JSON, XML, YAML, form data, etc.)
  • Sending structured responses (JSON, text, HTML, XML, file)
  • Handling cookies, headers, and other request metadata
  • Managing the request lifecycle (e.g., aborting early)
  • Built-in helpers for standardized error responses
  • Access to the underlying *http.Request and http.ResponseWriter for low-level control

This makes it easy to focus on business logic without worrying about low-level HTTP details.

Context Fields
Method Description
Request() The underlying *http.Request for accessing request data
Response() The underlying http.ResponseWriter for sending responses
Binding Methods

The context supports multiple binding mechanisms depending on content type and request source


Response Methods

Okapi provides a rich set of response methods to send various types of responses back to the client. These methods automatically set the appropriate HTTP status codes and content types.


Error Handling

Okapi provides a comprehensive error-handling system. You can return an error directly from your route handler, and Okapi will format the response automatically.

Additionally, the Context includes many helper methods to send standardized HTTP error responses with custom messages and optional wrapped errors.

These helpers provide consistency and reduce boilerplate when handling errors in your handlers or middleware.


Route Definition

Okapi provides a clean, declarative way to define and register routes. It supports all standard HTTP methods, including GET, POST, PUT, DELETE, PATCH, and OPTIONS.

You can define routes individually or register multiple routes at once using the okapi.RegisterRoutes function and the RouteDefinition struct, which is especially useful when organizing routes by controller or feature module.

Defining Routes with RouteDefinition

To group and manage routes more effectively, you can define them as a slice of okapi.RouteDefinition. This pattern is ideal for structuring routes in controllers or services layers.

Example: Book Service
type BookService struct{}

func (bc *BookService) GetBooks(c *okapi.Context) error {
	// Simulate fetching books from a database
	return c.OK(okapi.M{"success": true, "message": "Books retrieved successfully"})
}

func (bc *BookService) CreateBook(c *okapi.Context) error {
	// Simulate creating a book in a database
	return c.Created(okapi.M{
		"success": true,
		"message": "Book created successfully",
	})
}
Defining Service Routes
func (bc *BookService) BookRoutes() []okapi.RouteDefinition {
	apiGroup := &okapi.Group{Prefix: "/api"}
	return []okapi.RouteDefinition{
		{
			Method:  http.MethodGet,
			Path:    "/books",
			Handler: bc.GetBooks,
			Group:   apiGroup,
            Summary:     "List Books",
            Description: `Retrieve a list of all books in the inventory.`,
            Request:     &BookRequest{}, // OpenAPI documentation using Body field style
			Response:    &BooksResponse{}, // OpenAPI documentation using Body field style
		},
		{
			Method:  http.MethodPost,
			Path:    "/books",
			Handler: bc.CreateBook,
			Group:   apiGroup,
			Middlewares: []okapi.Middleware{customMiddleware}
			Security: bearerAuthSecurity, // Apply Bearer Auth security scheme
			// Using RouteOption
            Options: []okapi.RouteOption{
            okapi.DocSummary("Create Book"), // OpenAPI documentation
            okapi.DocDescription("Create Book"),
            okapi.DocRequestBody(&models.Book{}),
            okapi.DocResponse(&models.Book{}), // Success Response
            okapi.DocResponse(http.StatusUnauthorized, models.AuthResponse{}), // Error response
        
        },

        },
	}
}
Registering Routes

You can register routes using one of the following approaches:

app := okapi.Default()
bookController := &BookController{}

// Method 1: Register directly to the app instance
app.Register(bookController.Routes()...)

// Using a route group
// apiGroup := app.Group("/api")
// apiGroup.Register(bookController.Routes()...)


// Method 2: Use the global helper to register with the target instance
okapi.RegisterRoutes(app, bookController.Routes())

Both methods achieve the same result, choose the one that best fits your project’s style.

See the example in the examples/route-definition directory for a complete application using this pattern.

Standard Library Compatibility

Okapi integrates seamlessly with Go’s net/http standard library, enabling you to:

  1. Use existing http.Handler middleware
  2. Register standard http.HandlerFunc handlers
  3. Combine Okapi-style routes with standard library handlers

This makes Okapi ideal for gradual adoption or hybrid use in existing Go projects.

Middleware Compatibility

Okapi’s UseMiddleware bridges standard http.Handler middleware into Okapi’s middleware system. This lets you reuse the wide ecosystem of community-built middleware—such as logging, metrics, tracing, compression, and more.

Signature
func (o *Okapi) UseMiddleware(middleware func(http.Handler) http.Handler)
Example: Injecting a Custom Header
o := okapi.Default()

// Add a custom version header to all responses
o.UseMiddleware(func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-Version", "v1.2.0")
        next.ServeHTTP(w, r)
    })
})
Handler Compatibility

You can register any http.HandlerFunc using HandleStd, or use full http.Handler instances via HandleHTTP. These retain Okapi’s routing and middleware features while supporting familiar handler signatures.

HandleStd Signature
func (o *Okapi) HandleStd(method, path string, handler http.HandlerFunc, opts ...RouteOption)
Example: Basic Standard Library Handler
o := okapi.Default()

o.HandleStd("GET", "/greeting", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello from Okapi!"))
})

Migration Tips

Migrating an existing net/http application? Okapi makes it painless.

Mixed Routing Support

You can mix Okapi and standard handlers in the same application:

// Okapi-style route
o.Handle("GET", "/okapi", func(c *okapi.Context) error {
    return c.OK(okapi.M{"status": "ok"})
})

// Standard library handler
o.HandleStd("GET", "/standard", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("standard response"))
})
Error Handling Differences
  • http.HandlerFunc: must manually call w.WriteHeader(...)
  • okapi.Handle: can return an error or use helpers like c.JSON, c.Text, c.OK, c.ErrorNotFound() or c.AbortBadRequest()

Testing

Okapi provides comprehensive testing utilities to help you write robust tests for your handlers and middleware. The okapitest package offers two approaches: a fluent client API and standalone request helpers.

Quick Start
import (
    "testing"
    "github.com/jkaninda/okapi"
    "github.com/jkaninda/okapi/okapitest"
)

func TestGetBooksHandler(t *testing.T) {
    // Create a test server
    server := okapi.NewTestServer(t)
    server.Get("/books", GetBooksHandler)
    
    // Make request and assert response
    okapitest.GET(t, server.BaseURL+"/books").
        ExpectStatusOK().
        ExpectBodyContains("The Go Programming Language")
}
Testing Approaches

The test client provides a fluent API for making multiple requests with shared configuration:

func TestBooksAPI(t *testing.T) {
    // Setup test server
    server := okapi.NewTestServer(t)
    server.Get("/books", GetBooksHandler)
    server.Get("/books/:id", GetBookHandler)
    server.Post("/books", CreateBookHandler)
    
    // Create reusable client
    client := okapitest.NewClient(t, server.BaseURL)
    
    // Test listing books
    client.GET("/books").
        ExpectStatusOK().
        ExpectBodyContains("The Go Programming Language").
        ExpectHeader("X-Version", "1.0.0")


// Test getting a specific book
    client.GET("/books/1").
        ExpectStatusOK().
        ExpectBodyContains("The Go Programming Language")
    
    // Test book not found
    client.GET("/books/999").
        ExpectStatusNotFound().
        ExpectBodyContains("Book not found")
    
    // Test creating a book
    newBook := Book{
        ID:    6,
        Name:  "Sample Book",
        Price: 20,
        Year:  2024,
        Qty:   5,
    }
    client.POST("/books").
        JSONBody(newBook).
        ExpectStatusCreated().
        ExpectBodyContains("Sample Book")
}
2. Using Standalone Request Helpers

For simpler test cases or one off requests:

func TestGetBookHandler(t *testing.T) {
    server := okapi.NewTestServer(t)
    server.Get("/books/:id", GetBookHandler)
    
    // Test successful retrieval
    okapitest.GET(t, server.BaseURL+"/books/1").
        ExpectStatusOK().
        ExpectBodyContains("The Go Programming Language")
    
    // Test not found scenario
    okapitest.GET(t, server.BaseURL+"/books/999").
        ExpectStatusNotFound().
        ExpectBodyContains("Book not found")
}

func TestCreateBookHandler(t *testing.T) {
    server := okapi.NewTestServer(t)
    server.Post("/books", CreateBookHandler)
    
    book := Book{
        ID:    6,
        Name:  "Sample Book",
        Price: 20,
        Year:  2024,
        Qty:   5,
    }
    
    okapitest.POST(t, server.BaseURL+"/books").
        JSONBody(book).
        ExpectStatusCreated().
        ExpectBodyContains("Sample Book")
}
Available Assertions

The test utilities support various assertions:

// Status code assertions
.ExpectStatusOK()           // 200
.ExpectStatusCreated()      // 201
.ExpectStatusNotFound()     // 404
.ExpectStatus(code int)     // Custom status code

// Body assertions
.ExpectBodyContains(text string)
.ExpectBodyEquals(text string)
.ExpectJSONBody(expected interface{})

// Header assertions
.ExpectHeader(key, value string)
Testing with Custom Headers
func TestAuthenticatedRequest(t *testing.T) {
    server := okapi.NewTestServer(t)
    server.Get("/protected", ProtectedHandler)
    
    client := okapitest.NewClient(t, server.BaseURL)
    
    client.GET("/protected").
        Header("Authorization", "Bearer token123").
        ExpectStatusOK()
}
Testing Middleware
func TestAuthMiddleware(t *testing.T) {
    server := okapi.NewTestServer(t)
    server.Use(AuthMiddleware)
    server.Get("/protected", ProtectedHandler)
    
    client := okapitest.NewClient(t, server.BaseURL)
    
    // Test without auth - should fail
    client.GET("/protected").
        ExpectStatus(401)
    
    // Test with auth - should succeed
    client.GET("/protected").
        Header("Authorization", "Bearer valid-token").
        ExpectStatusOK()
}

Explore Another Project: Goma Gateway

Are you building a microservices architecture? Do you need a powerful yet lightweight API Gateway or a high-performance reverse proxy to secure and manage your services effortlessly?

Check out my other project — Goma Gateway.

Goma Gateway is a high-performance, declarative API Gateway built for modern microservices. It comes with a rich set of built-in middleware, including:

  • Basic, JWT, OAuth2, LDAP, and ForwardAuth authentication
  • Caching and rate limiting
  • Canary deployment
  • Bot detection
  • Built-in load balancing
  • Simple configuration with minimal overhead
  • ...and more!

Protocol support: REST, GraphQL, gRPC, TCP, and UDP

Security: Automatic HTTPS via Let’s Encrypt or use your own TLS certificates

Whether you're managing internal APIs or exposing public endpoints, Goma Gateway helps you do it efficiently, securely, and with minimal complexity.


Contributing

Contributions are welcome!

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. Push to your fork
  5. Open a Pull Request

🌟 Star History

⭐ If you find Okapi useful, please consider giving it a star on GitHub!

Star History Chart

Support & Community

License

This project is licensed under the MIT License. See the LICENSE file for details.


Made with ❤️ for the Go community

⭐ Star us on GitHub — it helps!

Copyright (c) 2025 Jonas Kaninda

Documentation

Overview

Package okapi is a modern, minimalist HTTP web framework for Go, inspired by FastAPI's elegance. Designed for simplicity, performance, and developer happiness, it helps you build fast, scalable, and well-documented APIs with minimal boilerplate.

The framework is named after the okapi (/oʊˈkɑːpiː/), a rare and graceful mammal native to the rainforests of the northeastern Democratic Republic of the Congo. Just like its namesake — which resembles a blend of giraffe and zebra — Okapi blends simplicity and strength in a unique, powerful package.

Key Features:

  • Intuitive & Expressive API: Clean, declarative syntax for effortless route and middleware definition.

  • Automatic Request Binding: Seamlessly parse JSON, XML, form data, query params, headers, and path variables into structs.

  • Built-in Auth & Security: Native support for JWT, OAuth2, Basic Auth, and custom middleware.

  • First-Class Documentation: OpenAPI 3.0 & Swagger UI integrated out of the box—auto-generate API docs with minimal effort.

  • Modern Tooling: Route grouping, middleware chaining, static file serving, templating engine support, CORS management, fine-grained timeout controls.

  • Developer Experience: Minimal boilerplate, clear error handling, structured logging, and easy testing.

Okapi is built for speed, simplicity, and real-world use—whether you're prototyping or running in production.

For more information and documentation, visit: https://github.com/jkaninda/okapi

Index

Constants

View Source
const (
	JSON           = "application/json"
	XML            = "application/xml"
	HTML           = "text/html"
	FORM           = "application/x-www-form-urlencoded"
	FormData       = "multipart/form-data"
	PLAINTEXT      = "text/plain"
	CSV            = "text/csv"
	JAVASCRIPT     = "application/javascript"
	YAML           = "application/yaml"
	YamlX          = "application/x-yaml"
	YamlText       = "text/yaml"
	PROTOBUF       = "application/protobuf"
	FormURLEncoded = "application/x-www-form-urlencoded"
)

Mime types

Variables

View Source
var (
	ErrNoRenderer = errors.New("no renderer set for context")
)

Functions

func GenerateJwtToken

func GenerateJwtToken(secret []byte, claims jwt.MapClaims, ttl time.Duration) (string, error)

GenerateJwtToken generates a JWT with custom claims and expiry

func IsClientError added in v0.0.5

func IsClientError(code int) bool

IsClientError checks if the status code is a 4xx client error.

func IsError added in v0.0.5

func IsError(code int) bool

IsError checks if the status code represents an error (4xx or 5xx).

func IsServerError added in v0.0.5

func IsServerError(code int) bool

IsServerError checks if the status code is a 5xx server error.

func LoadTLSConfig added in v0.0.3

func LoadTLSConfig(certFile, keyFile, caFile string, clientAuth bool) (*tls.Config, error)

LoadTLSConfig creates a TLS configuration from certificate and key files Parameters:

  • certFile: Path to the certificate file (PEM format)
  • keyFile: Path to the private key file (PEM format)
  • caFile: Optional path to CA certificate file for client verification (set to "" to disable)
  • clientAuth: Whether to require client certificate verification

Returns:

  • *tls.Config configured with the certificate and settings
  • error if any occurred during loading

func RegisterRoutes added in v0.0.13

func RegisterRoutes(o *Okapi, routes []RouteDefinition)

RegisterRoutes registers a slice of RouteDefinition with the given Okapi instance.

For each route definition, this function determines whether to register the route on the root Okapi instance or within a specific route group (if provided).

It supports all standard HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) and applies any associated RouteOptions, such as documentation annotations or middleware settings.

If the Group field in the RouteDefinition is nil, the route is registered on the root Okapi instance. Otherwise, it is registered within the specified group. If the group's Okapi reference is unset, it is automatically assigned from the root instance.

The function panics if an unsupported HTTP method is encountered.

Note: Use the `Use()` method on either the Okapi instance or a Group to apply middleware.

Example:

routes := []okapi.RouteDefinition{
	{
		Method:  "GET",
		Path:    "/example",
		Handler: exampleHandler,
		OperationId: "get-example",
		Summary: "Example GET request",
		Request: nil,
		Response: &ExampleResponse{},
		Group:   &okapi.Group{Prefix: "/api/v1", Tags: []string{"Example"}},
	},
	{
		Method:  "POST",
		Path:    "/example",
		Handler: exampleHandler,
		Middlewares: []okapi.Middleware{customMiddleware}
		Options: []okapi.RouteOption{
		okapi.DocSummary("Example POST request"),
		okapi.Request(&ExampleRequest{}),
		okapi.Response(&ExampleResponse{}),
	},
	Security: Security: []map[string][]string{
		{
		"bearerAuth": {},
		},
	},
	},
}

// Create a new Okapi instance
app := okapi.New()
okapi.RegisterRoutes(app, routes)

func ValidateAddr

func ValidateAddr(addr string) bool

ValidateAddr checks if the entrypoint address is valid. A valid entrypoint address should be in the format ":<port>" or "<IP>:<port>", where <IP> is a valid IP address and <port> is a valid port number (1-65535).

Types

type AndExpr added in v0.0.12

type AndExpr struct {
	Left  Expression
	Right Expression
}

func And added in v0.0.12

func And(left, right Expression) *AndExpr

func (*AndExpr) Evaluate added in v0.0.12

func (a *AndExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type Base64Serializer added in v0.2.1

type Base64Serializer struct{}

Base64Serializer for binary data

func (Base64Serializer) Serialize added in v0.2.1

func (b Base64Serializer) Serialize(data any) (string, error)

type BasicAuth added in v0.0.9

type BasicAuth struct {
	Username   string
	Password   string
	Realm      string
	ContextKey string // where to store the username e.g. "user", default(username)

}

BasicAuth provides basic authentication for routes.

func (*BasicAuth) Middleware added in v0.0.9

func (b *BasicAuth) Middleware(next HandlerFunc) HandlerFunc

Middleware is a basic authentication middleware that checks Basic Auth credentials. It returns 401 Unauthorized and sets the WWW-Authenticate header on failure.

type BasicAuthMiddleware

type BasicAuthMiddleware BasicAuth

BasicAuthMiddleware provides basic authentication for routes

deprecated, use BasicAuth

func (*BasicAuthMiddleware) Middleware

func (b *BasicAuthMiddleware) Middleware(next HandlerFunc) HandlerFunc

Middleware

deprecate, use BasicAuth.Middleware

type BodyLimit

type BodyLimit struct {
	MaxBytes int64
}

BodyLimit is a middleware that limits the size of the request body.

func (BodyLimit) Middleware

func (b BodyLimit) Middleware(next HandlerFunc) HandlerFunc

Middleware is a middleware that limits the size of the request body to prevent excessive memory usage.

type C added in v0.1.3

type C = *Context

C is a shortcut of *Context

type Contact added in v0.0.5

type Contact struct {
	Extensions map[string]any `json:"-" yaml:"-"`                             // Custom extensions not part of OpenAPI spec
	Name       string         `json:"name,omitempty" yaml:"name,omitempty"`   // Optional contact name
	URL        string         `json:"url,omitempty" yaml:"url,omitempty"`     // Optional contact URL
	Email      string         `json:"email,omitempty" yaml:"email,omitempty"` // Optional contact email
}

Contact contains contact information for the API maintainers

func (Contact) ToOpenAPI added in v0.0.5

func (c Contact) ToOpenAPI() *openapi3.Contact

ToOpenAPI converts Contact to openapi3.Contact. It transforms the custom Contact type to the format expected by the openapi3 package.

type ContainsExpr added in v0.0.12

type ContainsExpr struct {
	ClaimKey string
	Values   []string
	IsArray  bool
}

ContainsExpr checks if claim contains substring or array contains value

func Contains added in v0.0.12

func Contains(claimKey string, values ...string) *ContainsExpr

func (*ContainsExpr) Evaluate added in v0.0.12

func (c *ContainsExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type Context

type Context struct {
	// contains filtered or unexported fields
}

func NewContext added in v0.1.2

func NewContext(o *Okapi, w http.ResponseWriter, r *http.Request) *Context

NewContext creates a new Okapi Context

func NewTestContext added in v0.1.2

func NewTestContext(method, url string, body io.Reader) (*Context, *httptest.ResponseRecorder)

NewTestContext creates a Context with its own in-memory request and recorder. Unlike NewContext, it does not initialize a default Okapi engine.

func (*Context) Abort added in v0.0.2

func (c *Context) Abort(err error) error

Abort writes a standardized 500 Internal Server Error response.

func (*Context) AbortBadGateway added in v0.0.5

func (c *Context) AbortBadGateway(msg string, err ...error) error

AbortBadGateway writes a standardized 502 Bad Gateway response.

func (*Context) AbortBadRequest added in v0.0.2

func (c *Context) AbortBadRequest(msg string, err ...error) error

AbortBadRequest writes a standardized 400 Bad request response.

func (*Context) AbortConflict added in v0.0.2

func (c *Context) AbortConflict(msg string, err ...error) error

AbortConflict writes a standardized 409 Conflict response.

func (*Context) AbortExpectationFailed added in v0.0.5

func (c *Context) AbortExpectationFailed(msg string, err ...error) error

AbortExpectationFailed writes a standardized 417 Expectation Failed response.

func (*Context) AbortFailedDependency added in v0.0.5

func (c *Context) AbortFailedDependency(msg string, err ...error) error

AbortFailedDependency writes a standardized 424 Failed Dependency response.

func (*Context) AbortForbidden added in v0.0.2

func (c *Context) AbortForbidden(msg string, err ...error) error

AbortForbidden writes a standardized 403 Forbidden response.

func (*Context) AbortGatewayTimeout added in v0.0.5

func (c *Context) AbortGatewayTimeout(msg string, err ...error) error

AbortGatewayTimeout writes a standardized 504 Gateway Timeout response.

func (*Context) AbortGone added in v0.0.5

func (c *Context) AbortGone(msg string, err ...error) error

AbortGone writes a standardized 410 Gone response.

func (*Context) AbortHTTPVersionNotSupported added in v0.0.5

func (c *Context) AbortHTTPVersionNotSupported(msg string, err ...error) error

AbortHTTPVersionNotSupported writes a standardized 505 HTTP version Not Supported response.

func (*Context) AbortInsufficientStorage added in v0.0.5

func (c *Context) AbortInsufficientStorage(msg string, err ...error) error

AbortInsufficientStorage writes a standardized 507 Insufficient Storage response.

func (*Context) AbortInternalServerError added in v0.0.5

func (c *Context) AbortInternalServerError(msg string, err ...error) error

AbortInternalServerError writes a standardized 500 Internal Server Error response.

func (*Context) AbortLengthRequired added in v0.0.5

func (c *Context) AbortLengthRequired(msg string, err ...error) error

AbortLengthRequired writes a standardized 411 Length Required response.

func (*Context) AbortLocked added in v0.0.5

func (c *Context) AbortLocked(msg string, err ...error) error

AbortLocked writes a standardized 423 Locked response.

func (*Context) AbortLoopDetected added in v0.0.5

func (c *Context) AbortLoopDetected(msg string, err ...error) error

AbortLoopDetected writes a standardized 508 Loop Detected response.

func (*Context) AbortMethodNotAllowed added in v0.0.5

func (c *Context) AbortMethodNotAllowed(msg string, err ...error) error

AbortMethodNotAllowed writes a standardized 405 Method Not Allowed response.

func (*Context) AbortMisdirectedRequest added in v0.0.5

func (c *Context) AbortMisdirectedRequest(msg string, err ...error) error

AbortMisdirectedRequest writes a standardized 421 Misdirected request response.

func (*Context) AbortNetworkAuthenticationRequired added in v0.0.5

func (c *Context) AbortNetworkAuthenticationRequired(msg string, err ...error) error

AbortNetworkAuthenticationRequired writes a standardized 511 Network Authentication Required response.

func (*Context) AbortNotAcceptable added in v0.0.5

func (c *Context) AbortNotAcceptable(msg string, err ...error) error

AbortNotAcceptable writes a standardized 406 Not Acceptable response.

func (*Context) AbortNotExtended added in v0.0.5

func (c *Context) AbortNotExtended(msg string, err ...error) error

AbortNotExtended writes a standardized 510 Not Extended response.

func (*Context) AbortNotFound added in v0.0.2

func (c *Context) AbortNotFound(msg string, err ...error) error

AbortNotFound writes a standardized 404 Not Found response.

func (*Context) AbortNotImplemented added in v0.0.5

func (c *Context) AbortNotImplemented(msg string, err ...error) error

AbortNotImplemented writes a standardized 501 Not Implemented response.

func (*Context) AbortPaymentRequired added in v0.0.5

func (c *Context) AbortPaymentRequired(msg string, err ...error) error

AbortPaymentRequired writes a standardized 402 Payment Required response.

func (*Context) AbortPreconditionFailed added in v0.0.5

func (c *Context) AbortPreconditionFailed(msg string, err ...error) error

AbortPreconditionFailed writes a standardized 412 Precondition Failed response.

func (*Context) AbortPreconditionRequired added in v0.0.5

func (c *Context) AbortPreconditionRequired(msg string, err ...error) error

AbortPreconditionRequired writes a standardized 428 Precondition Required response.

func (*Context) AbortProxyAuthRequired added in v0.0.5

func (c *Context) AbortProxyAuthRequired(msg string, err ...error) error

AbortProxyAuthRequired writes a standardized 407 Proxy Authentication Required response.

func (*Context) AbortRequestEntityTooLarge added in v0.0.5

func (c *Context) AbortRequestEntityTooLarge(msg string, err ...error) error

AbortRequestEntityTooLarge writes a standardized 413 request Entity Too Large response.

func (*Context) AbortRequestHeaderFieldsTooLarge added in v0.0.5

func (c *Context) AbortRequestHeaderFieldsTooLarge(msg string, err ...error) error

AbortRequestHeaderFieldsTooLarge writes a standardized 431 request Header Fields Too Large response.

func (*Context) AbortRequestTimeout added in v0.0.5

func (c *Context) AbortRequestTimeout(msg string, err ...error) error

AbortRequestTimeout writes a standardized 408 request Timeout response.

func (*Context) AbortRequestURITooLong added in v0.0.5

func (c *Context) AbortRequestURITooLong(msg string, err ...error) error

AbortRequestURITooLong writes a standardized 414 request-URI Too Long response.

func (*Context) AbortRequestedRangeNotSatisfiable added in v0.0.5

func (c *Context) AbortRequestedRangeNotSatisfiable(msg string, err ...error) error

AbortRequestedRangeNotSatisfiable writes a standardized 416 Requested Range Not Satisfiable response.

func (*Context) AbortServiceUnavailable added in v0.0.5

func (c *Context) AbortServiceUnavailable(msg string, err ...error) error

AbortServiceUnavailable writes a standardized 503 Service Unavailable response.

func (*Context) AbortTeapot added in v0.0.5

func (c *Context) AbortTeapot(msg string, err ...error) error

AbortTeapot writes a standardized 418 I'm a teapot response.

func (*Context) AbortTooEarly added in v0.0.5

func (c *Context) AbortTooEarly(msg string, err ...error) error

AbortTooEarly writes a standardized 425 Too Early response.

func (*Context) AbortTooManyRequests added in v0.0.2

func (c *Context) AbortTooManyRequests(msg string, err ...error) error

AbortTooManyRequests writes a standardized 429 Too Many Requests response.

func (*Context) AbortUnauthorized added in v0.0.2

func (c *Context) AbortUnauthorized(msg string, err ...error) error

AbortUnauthorized writes a standardized 401 Unauthorized response.

func (*Context) AbortUnavailableForLegalReasons added in v0.0.5

func (c *Context) AbortUnavailableForLegalReasons(msg string, err ...error) error

AbortUnavailableForLegalReasons writes a standardized 451 Unavailable For Legal Reasons response.

func (*Context) AbortUnsupportedMediaType added in v0.0.5

func (c *Context) AbortUnsupportedMediaType(msg string, err ...error) error

AbortUnsupportedMediaType writes a standardized 415 Unsupported Media Type response.

func (*Context) AbortUpgradeRequired added in v0.0.5

func (c *Context) AbortUpgradeRequired(msg string, err ...error) error

AbortUpgradeRequired writes a standardized 426 Upgrade Required response.

func (*Context) AbortValidationError added in v0.0.2

func (c *Context) AbortValidationError(msg string, err ...error) error

AbortValidationError writes a standardized 422 Unprocessable Entity response.

func (*Context) AbortValidationErrors added in v0.0.5

func (c *Context) AbortValidationErrors(errors []ValidationError, msg ...string) error

AbortValidationErrors writes a detailed validation error response.

func (*Context) AbortVariantAlsoNegotiates added in v0.0.5

func (c *Context) AbortVariantAlsoNegotiates(msg string, err ...error) error

AbortVariantAlsoNegotiates writes a standardized 506 Variant Also Negotiates response.

func (*Context) AbortWithError

func (c *Context) AbortWithError(code int, err error) error

AbortWithError writes a standardized error response and stops execution.

func (*Context) AbortWithJSON added in v0.0.2

func (c *Context) AbortWithJSON(code int, jsonObj interface{}) error

AbortWithJSON writes a custom JSON error response.

func (*Context) AbortWithStatus added in v0.0.2

func (c *Context) AbortWithStatus(code int, message string) error

AbortWithStatus writes an error response with status code and custom message.

func (*Context) Accept

func (c *Context) Accept() []string

Accept returns the Accept header values as a slice.

func (*Context) AcceptLanguage

func (c *Context) AcceptLanguage() []string

AcceptLanguage returns the Accept-Language header values as a slice. Trims whitespace from each language tag.

func (*Context) B

func (c *Context) B(v any) error

B is a shortcut for Bind, allowing you to bind request data to a struct.

func (*Context) Bind

func (c *Context) Bind(out any) error

Bind populates the given struct with request data by inspecting tags and content type. It supports two binding styles:

  1. **Flat binding (legacy style)** Request body fields (JSON, XML, YAML, Protobuf, Form) can be mixed directly with query parameters, headers, cookies, and path params in a single struct.

  2. **Body field binding (recommended style)** A struct may contain a dedicated `Body` field (or tagged as `body`) that represents the request payload, while sibling fields represent query params, headers, cookies, and path params. This style enforces a clear separation between metadata and body.

Validation tags such as `required`, `min`, `max`, `minLength`, and `maxLength` are supported, along with descriptive metadata (`description`) that can be used for documentation.

Example (Body field binding):

type BookInput struct {
  // Query parameter
  Tags []string `query:"tags" description:"List of book tags"`

  // Header parameter
  Accept string `header:"Accept" required:"true" description:"Accept header"`

  // Cookie parameter
  SessionID string `cookie:"SessionID" required:"true" description:"Session ID cookie"`
  // Path parameter
  BookID string `path:"bookId" required:"true" description:"Book ID"`

  // Request body
  Body struct {
    Name  string `json:"name" required:"true" minLength:"2" maxLength:"100" description:"Book name"`
    Price int    `json:"price" required:"true" min:"5" max:"100" yaml:"price" description:"Book price"`
  }
}

okapi.Put("/books/:bookId", func(c okapi.Context) error {
  book := &BookInput{}
  if err := c.Bind(book); err != nil {
    return c.AbortBadRequest("Invalid input", err)
  }
  return c.Respond(book)
})

func (*Context) BindForm

func (c *Context) BindForm(v any) error

func (*Context) BindJSON

func (c *Context) BindJSON(v any) error

func (*Context) BindMultipart

func (c *Context) BindMultipart(out any) error

BindMultipart binds multipart form data to the provided struct.

func (*Context) BindProtoBuf

func (c *Context) BindProtoBuf(v proto.Message) error

func (*Context) BindQuery

func (c *Context) BindQuery(v any) error

func (*Context) BindXML

func (c *Context) BindXML(v any) error

func (*Context) BindYAML

func (c *Context) BindYAML(v any) error

func (*Context) ContentType

func (c *Context) ContentType() string

ContentType returns the Content-Type header value.

func (*Context) Cookie

func (c *Context) Cookie(name string) (string, error)

Cookie retrieves a cookie value by name. Returns empty string and error if cookie not found.

func (*Context) Copy

func (c *Context) Copy() *Context

Copy creates a shallow copy of the context with a new data map.

func (*Context) Created added in v0.0.8

func (c *Context) Created(v any) error

Created writes a JSON response with 201 status code.

func (*Context) Data

func (c *Context) Data(code int, contentType string, data []byte) error

Data writes a raw byte response with the given content type and status code.

func (*Context) Error

func (c *Context) Error(code int, message string) error

Error writes a basic error response with the given status code and message.

func (*Context) ErrorBadGateway added in v0.0.5

func (c *Context) ErrorBadGateway(message any) error

ErrorBadGateway writes a 502 Bad Gateway response.

func (*Context) ErrorBadRequest added in v0.0.2

func (c *Context) ErrorBadRequest(message any) error

ErrorBadRequest writes a 400 Bad request response.

func (*Context) ErrorConflict added in v0.0.2

func (c *Context) ErrorConflict(message any) error

ErrorConflict writes a 409 Conflict response.

func (*Context) ErrorExpectationFailed added in v0.0.5

func (c *Context) ErrorExpectationFailed(message any) error

ErrorExpectationFailed writes a 417 Expectation Failed response.

func (*Context) ErrorFailedDependency added in v0.0.5

func (c *Context) ErrorFailedDependency(message any) error

ErrorFailedDependency writes a 424 Failed Dependency response.

func (*Context) ErrorForbidden added in v0.0.2

func (c *Context) ErrorForbidden(message any) error

ErrorForbidden writes a 403 Forbidden response.

func (*Context) ErrorGatewayTimeout added in v0.0.5

func (c *Context) ErrorGatewayTimeout(message any) error

ErrorGatewayTimeout writes a 504 Gateway Timeout response.

func (*Context) ErrorGone added in v0.0.5

func (c *Context) ErrorGone(message any) error

ErrorGone writes a 410 Gone response.

func (*Context) ErrorHTTPVersionNotSupported added in v0.0.5

func (c *Context) ErrorHTTPVersionNotSupported(message any) error

ErrorHTTPVersionNotSupported writes a 505 HTTP version Not Supported response.

func (*Context) ErrorInsufficientStorage added in v0.0.5

func (c *Context) ErrorInsufficientStorage(message any) error

ErrorInsufficientStorage writes a 507 Insufficient Storage response.

func (*Context) ErrorInternalServerError added in v0.0.2

func (c *Context) ErrorInternalServerError(message any) error

ErrorInternalServerError writes a 500 Internal Server Error response.

func (*Context) ErrorLengthRequired added in v0.0.5

func (c *Context) ErrorLengthRequired(message any) error

ErrorLengthRequired writes a 411 Length Required response.

func (*Context) ErrorLocked added in v0.0.5

func (c *Context) ErrorLocked(message any) error

ErrorLocked writes a 423 Locked response.

func (*Context) ErrorLoopDetected added in v0.0.5

func (c *Context) ErrorLoopDetected(message any) error

ErrorLoopDetected writes a 508 Loop Detected response.

func (*Context) ErrorMethodNotAllowed added in v0.0.5

func (c *Context) ErrorMethodNotAllowed(message any) error

ErrorMethodNotAllowed writes a 405 Method Not Allowed response.

func (*Context) ErrorMisdirectedRequest added in v0.0.5

func (c *Context) ErrorMisdirectedRequest(message any) error

ErrorMisdirectedRequest writes a 421 Misdirected request response.

func (*Context) ErrorNetworkAuthenticationRequired added in v0.0.5

func (c *Context) ErrorNetworkAuthenticationRequired(message any) error

ErrorNetworkAuthenticationRequired writes a 511 Network Authentication Required response.

func (*Context) ErrorNotAcceptable added in v0.0.5

func (c *Context) ErrorNotAcceptable(message any) error

ErrorNotAcceptable writes a 406 Not Acceptable response.

func (*Context) ErrorNotExtended added in v0.0.5

func (c *Context) ErrorNotExtended(message any) error

ErrorNotExtended writes a 510 Not Extended response.

func (*Context) ErrorNotFound added in v0.0.2

func (c *Context) ErrorNotFound(message any) error

ErrorNotFound writes a 404 Not Found response.

func (*Context) ErrorNotImplemented added in v0.0.5

func (c *Context) ErrorNotImplemented(message any) error

ErrorNotImplemented writes a 501 Not Implemented response.

func (*Context) ErrorPaymentRequired added in v0.0.5

func (c *Context) ErrorPaymentRequired(message any) error

ErrorPaymentRequired writes a 402 Payment Required response.

func (*Context) ErrorPreconditionFailed added in v0.0.5

func (c *Context) ErrorPreconditionFailed(message any) error

ErrorPreconditionFailed writes a 412 Precondition Failed response.

func (*Context) ErrorPreconditionRequired added in v0.0.5

func (c *Context) ErrorPreconditionRequired(message any) error

ErrorPreconditionRequired writes a 428 Precondition Required response.

func (*Context) ErrorProxyAuthRequired added in v0.0.5

func (c *Context) ErrorProxyAuthRequired(message any) error

ErrorProxyAuthRequired writes a 407 Proxy Authentication Required response.

func (*Context) ErrorRequestEntityTooLarge added in v0.0.5

func (c *Context) ErrorRequestEntityTooLarge(message any) error

ErrorRequestEntityTooLarge writes a 413 request Entity Too Large response.

func (*Context) ErrorRequestHeaderFieldsTooLarge added in v0.0.5

func (c *Context) ErrorRequestHeaderFieldsTooLarge(message any) error

ErrorRequestHeaderFieldsTooLarge writes a 431 request Header Fields Too Large response.

func (*Context) ErrorRequestTimeout added in v0.0.5

func (c *Context) ErrorRequestTimeout(message any) error

ErrorRequestTimeout writes a 408 request Timeout response.

func (*Context) ErrorRequestURITooLong added in v0.0.5

func (c *Context) ErrorRequestURITooLong(message any) error

ErrorRequestURITooLong writes a 414 request-URI Too Long response.

func (*Context) ErrorRequestedRangeNotSatisfiable added in v0.0.5

func (c *Context) ErrorRequestedRangeNotSatisfiable(message any) error

ErrorRequestedRangeNotSatisfiable writes a 416 Requested Range Not Satisfiable response.

func (*Context) ErrorServiceUnavailable added in v0.0.2

func (c *Context) ErrorServiceUnavailable(message any) error

ErrorServiceUnavailable writes a 503 Service Unavailable response.

func (*Context) ErrorTeapot added in v0.0.5

func (c *Context) ErrorTeapot(message any) error

ErrorTeapot writes a 418 I'm a teapot response (RFC 2324).

func (*Context) ErrorTooEarly added in v0.0.5

func (c *Context) ErrorTooEarly(message any) error

ErrorTooEarly writes a 425 Too Early response.

func (*Context) ErrorTooManyRequests added in v0.0.2

func (c *Context) ErrorTooManyRequests(message any) error

ErrorTooManyRequests writes a 429 Too Many Requests response.

func (*Context) ErrorUnauthorized added in v0.0.2

func (c *Context) ErrorUnauthorized(message any) error

ErrorUnauthorized writes a 401 Unauthorized response.

func (*Context) ErrorUnavailableForLegalReasons added in v0.0.5

func (c *Context) ErrorUnavailableForLegalReasons(message any) error

ErrorUnavailableForLegalReasons writes a 451 Unavailable For Legal Reasons response.

func (*Context) ErrorUnprocessableEntity added in v0.0.2

func (c *Context) ErrorUnprocessableEntity(message any) error

ErrorUnprocessableEntity writes a 422 Unprocessable Entity response.

func (*Context) ErrorUnsupportedMediaType added in v0.0.5

func (c *Context) ErrorUnsupportedMediaType(message any) error

ErrorUnsupportedMediaType writes a 415 Unsupported Media Type response.

func (*Context) ErrorUpgradeRequired added in v0.0.5

func (c *Context) ErrorUpgradeRequired(message any) error

ErrorUpgradeRequired writes a 426 Upgrade Required response.

func (*Context) ErrorVariantAlsoNegotiates added in v0.0.5

func (c *Context) ErrorVariantAlsoNegotiates(message any) error

ErrorVariantAlsoNegotiates writes a 506 Variant Also Negotiates response.

func (*Context) Form

func (c *Context) Form(key string) string

Form retrieves a form value after parsing the form data.

func (*Context) FormFile

func (c *Context) FormFile(key string) (*multipart.FileHeader, error)

FormFile retrieves a file from multipart form data. Returns the file and any error encountered.

func (*Context) FormValue

func (c *Context) FormValue(key string) string

FormValue retrieves a form value, including multipart form data.

func (*Context) Get

func (c *Context) Get(key string) (any, bool)

Get retrieves a value from the context's data store with thread-safe access. Returns the value and a boolean indicating if the key exists.

func (*Context) GetBool

func (c *Context) GetBool(key string) bool

GetBool retrieves a boolean value from the context. Returns false if key doesn't exist or value isn't a bool.

func (*Context) GetInt

func (c *Context) GetInt(key string) int

GetInt retrieves an integer value from the context. Returns 0 if key doesn't exist or value isn't an int.

func (*Context) GetInt64

func (c *Context) GetInt64(key string) int64

GetInt64 retrieves an int64 value from the context. Returns 0 if key doesn't exist or value isn't an int64.

func (*Context) GetString

func (c *Context) GetString(key string) string

GetString retrieves a string value from the context. Returns empty string if key doesn't exist or value isn't a string.

func (*Context) GetTime

func (c *Context) GetTime(key string) (time.Time, bool)

GetTime retrieves a time.Time value from the context's data store.

func (*Context) HTML

func (c *Context) HTML(code int, file string, data any) error

HTML renders an HTML template from a file with the given status code.

func (*Context) HTMLView

func (c *Context) HTMLView(code int, templateStr string, data any) error

HTMLView renders an HTML template from a string with the given status code.

func (*Context) Header

func (c *Context) Header(key string) string

Header gets a request header by key.

func (*Context) Headers

func (c *Context) Headers() map[string][]string

Headers returns all request headers as a map.

func (*Context) IsSSE

func (c *Context) IsSSE() bool

IsSSE checks if the request is for Server-Sent Events (SSE).

func (*Context) IsWebSocketUpgrade

func (c *Context) IsWebSocketUpgrade() bool

IsWebSocketUpgrade checks if the request is a WebSocket upgrade request.

func (*Context) JSON

func (c *Context) JSON(code int, v any) error

JSON writes a JSON response with the given status code.

func (*Context) Logger added in v0.0.15

func (c *Context) Logger() *slog.Logger

Logger returns the logger instance associated with the Okapi context.

func (*Context) MaxMultipartMemory

func (c *Context) MaxMultipartMemory() int64

MaxMultipartMemory returns the maximum memory for multipart form

func (*Context) OK added in v0.0.5

func (c *Context) OK(v any) error

OK writes a JSON response with 200 status code.

func (*Context) Param

func (c *Context) Param(key string) string

Param retrieves a URL path parameter value.

func (*Context) Params added in v0.2.1

func (c *Context) Params() map[string]string

Params returns all URL path parameters as a map.

func (*Context) Query

func (c *Context) Query(key string) string

Query retrieves a URL query parameter value. Returns empty string if parameter doesn't exist.

func (*Context) QueryArray added in v0.1.0

func (c *Context) QueryArray(key string) []string

QueryArray retrieves all values for a query parameter. Supports both repeated params (?tags=a&tags=b) and comma-separated (?tags=a,b).

func (*Context) QueryMap

func (c *Context) QueryMap() map[string]string

QueryMap returns all query parameters as a map. Only includes the first value for each parameter.

func (*Context) RealIP

func (c *Context) RealIP() string

RealIP returns the client's real IP address, handling proxies.

func (*Context) Redirect

func (c *Context) Redirect(code int, location string)

Redirect sends a redirect response to the specified location.

func (*Context) Referer

func (c *Context) Referer() string

Referer retrieves the Referer header value from the request.

func (*Context) Render

func (c *Context) Render(code int, name string, data interface{}) error

Render renders a template using the configured Renderer.

func (*Context) Request

func (c *Context) Request() *http.Request

Request a new Context instance with the given request

func (*Context) Respond added in v0.1.0

func (c *Context) Respond(output any) error

Respond serializes the output struct into the HTTP response. It inspects struct tags to automatically set headers, cookies, and status code, and encodes the response body in the format requested by the `Accept` header.

Supported formats: JSON, XML, YAML, plain text, HTML.

Example:

type BookResponse struct {
  Status  int                           // HTTP status code
  version string `header:"version"`     // Response header
  Session string `cookie:"SessionID"`   // Response cookie
  Body    struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Price int    `json:"price"`
  }
}

okapi.Get("/books/:id", func(c okapi.Context) error {
  return c.Respond(BookResponse{
    version: "v1",
    Session: "abc123",
    Status:  200,
    Body: struct {
      ID    int    `json:"id"`
      Name  string `json:"name"`
      Price int    `json:"price"`
    }{
      ID: 1, Name: "Okapi Guide", Price: 50,
    },
  })
})

func (*Context) Response

func (c *Context) Response() ResponseWriter

Response returns the http.ResponseWriter for writing responses. This is an alias for ResponseWriter for convenience.

func (*Context) ResponseWriter added in v0.0.14

func (c *Context) ResponseWriter() http.ResponseWriter

ResponseWriter returns the http.ResponseWriter for writing responses.

func (*Context) Return added in v0.1.0

func (c *Context) Return(output any) error

Return is an alias for Respond to improve readability when sending output.

func (*Context) SSESendBinary added in v0.2.1

func (c *Context) SSESendBinary(data []byte) error

SSESendBinary sends binary data as base64

func (*Context) SSESendData added in v0.2.1

func (c *Context) SSESendData(data any) error

SSESendData sends structured data as JSON

func (*Context) SSESendEvent added in v0.2.1

func (c *Context) SSESendEvent(id, eventType string, data any) error

SSESendEvent writes SSE response with an ID.

func (*Context) SSESendJSON added in v0.2.1

func (c *Context) SSESendJSON(data any) error

SSESendJSON sends JSON data with explicit JSON serialization

func (*Context) SSESendText added in v0.2.1

func (c *Context) SSESendText(text string) error

SSESendText sends plain text data

func (*Context) SSEStream added in v0.1.2

func (c *Context) SSEStream(ctx context.Context, messageChan <-chan Message) error

SSEStream keeps connection open for multiple messages

func (*Context) SSEStreamWithOptions added in v0.2.1

func (c *Context) SSEStreamWithOptions(ctx context.Context, messageChan <-chan Message, opts *StreamOptions) error

SSEStreamWithOptions provides advanced streaming control

func (*Context) SSEvent added in v0.0.10

func (c *Context) SSEvent(eventType string, data any) error

SSEvent writes SSE response with optional ID.

func (*Context) SendSSECustom added in v0.2.1

func (c *Context) SendSSECustom(data any, serializer Serializer) error

SendSSECustom sends data with custom serializer

func (*Context) SendSSEvent added in v0.0.18

func (c *Context) SendSSEvent(id, eventType string, data any) error

SendSSEvent writes SSE response with an ID. Deprecated: use SSESendEvent instead.

func (*Context) ServeFile

func (c *Context) ServeFile(path string)

ServeFile serves a file from the filesystem.

func (*Context) ServeFileAttachment

func (c *Context) ServeFileAttachment(path, filename string)

ServeFileAttachment serves a file as an attachment (download).

func (*Context) ServeFileFromFS

func (c *Context) ServeFileFromFS(filepath string, fs http.FileSystem)

ServeFileFromFS serves a file from a custom http.FileSystem.

func (*Context) ServeFileInline

func (c *Context) ServeFileInline(path, filename string)

ServeFileInline serves a file to be displayed inline in the browser.

func (*Context) Set

func (c *Context) Set(key string, value any)

Set stores a value in the context's data store with thread-safe access. Initializes the data map if it doesn't exist.

func (*Context) SetCookie

func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)

SetCookie sets a cookie with various configurable options. Defaults path to "/" if empty.

func (*Context) SetHeader

func (c *Context) SetHeader(key, value string)

SetHeader sets a response header.

func (*Context) SetMaxMultipartMemory added in v0.0.7

func (c *Context) SetMaxMultipartMemory(max int64)

SetMaxMultipartMemory sets the maximum memory for multipart form (default: 32 MB)

func (*Context) ShouldBind

func (c *Context) ShouldBind(v any) (bool, error)

ShouldBind is a convenience method that binds request data to a struct and returns a boolean indicating success.

func (*Context) String

func (c *Context) String(code int, data any) error

String is an alias for Text for convenience.

func (*Context) Text

func (c *Context) Text(code int, v any) error

Text writes a plain text response with the given status code.

func (*Context) WriteStatus

func (c *Context) WriteStatus(code int)

WriteStatus writes the HTTP status code to the response.

func (*Context) XML

func (c *Context) XML(code int, v any) error

XML writes an XML response with the given status code.

func (*Context) YAML

func (c *Context) YAML(code int, data any) error

YAML writes a YAML response with the given status code.

type Cors added in v0.0.2

type Cors struct {
	// AllowedOrigins specifies which origins are allowed.
	AllowedOrigins []string

	// AllowedHeaders defines which request headers are permitted.
	AllowedHeaders []string

	// ExposeHeaders indicates which response headers are exposed to the client.
	ExposeHeaders []string
	//
	Headers map[string]string

	// MaxAge defines how long the results of a preflight request can be cached (in seconds).
	MaxAge int

	// AllowMethods lists the HTTP methods permitted for cross-origin requests.
	AllowMethods     []string
	AllowCredentials bool
}

func (Cors) CORSHandler added in v0.0.2

func (cors Cors) CORSHandler(next HandlerFunc) HandlerFunc

CORSHandler applies CORS headers and handles preflight (OPTIONS) requests.

type DocBuilder added in v0.0.6

type DocBuilder struct {
	// contains filtered or unexported fields
}

DocBuilder helps construct a list of RouteOption functions in a fluent, chainable way.

func Doc added in v0.0.6

func Doc() *DocBuilder

Doc creates and returns a new DocBuilder instance for chaining documentation options.

func (*DocBuilder) AsOption added in v0.0.6

func (b *DocBuilder) AsOption() RouteOption

AsOption returns a single RouteOption by merging all accumulated documentation options. This is functionally equivalent to Build(), and exists for naming flexibility and readability.

You can use either Build() or AsOption(), depending on what best fits your code style.

Example:

okapi.Get("/books", handler, okapi.Doc().response(Book{}).AsOption())

func (*DocBuilder) BearerAuth added in v0.0.6

func (b *DocBuilder) BearerAuth() *DocBuilder

BearerAuth marks the route as requiring Bearer token authentication.

func (*DocBuilder) Build added in v0.0.6

func (b *DocBuilder) Build() RouteOption

Build returns a single RouteOption composed of all accumulated documentation options. This method is intended to be passed directly to route registration functions.

Example:

okapi.Get("/books", handler, okapi.Doc().response(Book{}).Summary("List books").Build())

func (*DocBuilder) Deprecated added in v0.0.8

func (b *DocBuilder) Deprecated() *DocBuilder

Deprecated marks the route as deprecated

func (*DocBuilder) Description added in v0.0.13

func (b *DocBuilder) Description(description string) *DocBuilder

Description adds a description to the route documentation.

func (*DocBuilder) ErrorResponse added in v0.0.7

func (b *DocBuilder) ErrorResponse(status int, v any) *DocBuilder

ErrorResponse defines an error response schema for a specific HTTP status code in the route's OpenAPI documentation. Deprecated: This function is deprecated in favor of Response(status, v).

Parameters:

  • status: the HTTP status code (e.g., 400, 404, 500).
  • v: a Go value (e.g., a struct instance) whose type will be used to generate the OpenAPI schema for the error response.

func (*DocBuilder) Header added in v0.0.6

func (b *DocBuilder) Header(name, typ, desc string, required bool) *DocBuilder

Header adds a documented header to the route. name: header name typ: header value type (e.g., "string", "int") desc: header description required: whether the header is required

func (*DocBuilder) HeaderWithDefault added in v0.1.0

func (b *DocBuilder) HeaderWithDefault(name, typ, desc string, required bool, defvalue any) *DocBuilder

HeaderWithDefault adds a documented header to the route with default. name: header name typ: header value type (e.g., "string", "int") desc: header description required: whether the header is required defvalue: default value to use

func (*DocBuilder) Hide added in v0.0.19

func (b *DocBuilder) Hide() *DocBuilder

Hide marks the route to be excluded from OpenAPI documentation.

func (*DocBuilder) OperationId added in v0.0.19

func (b *DocBuilder) OperationId(operationId string) *DocBuilder

OperationId sets a unique identifier for the operation in the OpenAPI documentation.

func (*DocBuilder) PathParam added in v0.0.6

func (b *DocBuilder) PathParam(name, typ, desc string) *DocBuilder

PathParam adds a documented path parameter to the route. name: parameter name typ: parameter type (e.g., "string", "int") desc: parameter description

func (*DocBuilder) PathParamWithDefault added in v0.1.1

func (b *DocBuilder) PathParamWithDefault(name, typ, desc string, defvalue any) *DocBuilder

PathParamWithDefault adds a documented path parameter to the route. name: parameter name typ: parameter type (e.g., "string", "int") desc: parameter description defvalue: default value to use

func (*DocBuilder) QueryParam added in v0.0.6

func (b *DocBuilder) QueryParam(name, typ, desc string, required bool) *DocBuilder

QueryParam adds a documented query parameter to the route. name: parameter name typ: parameter type (e.g., "string", "int") desc: parameter description required: whether the parameter is required

func (*DocBuilder) QueryParamWithDefault added in v0.1.0

func (b *DocBuilder) QueryParamWithDefault(name, typ, desc string, required bool, defvalue any) *DocBuilder

QueryParamWithDefault adds a documented query parameter to the route with default. name: parameter name typ: parameter type (e.g., "string", "int") desc: parameter description required: whether the parameter is required defvalue: default value to use

func (*DocBuilder) RequestBody added in v0.0.6

func (b *DocBuilder) RequestBody(v any) *DocBuilder

RequestBody adds a request body schema to the route documentation using the provided value.

func (*DocBuilder) Response added in v0.0.6

func (b *DocBuilder) Response(statusOrValue any, vOptional ...any) *DocBuilder

Response registers a response schema for the route's OpenAPI documentation. It can be used in two ways:

  1. DocResponse(status int, value any) - Defines a response schema for the specified HTTP status code (e.g., 200, 201, 400).
  2. DocResponse(value any) - Shorthand for DocResponse(200, value).

Examples:

DocResponse(201, CreatedResponse{})   // Response for 201 Created
DocResponse(400, ErrorResponse{})     // Response for 400 Bad Request
DocResponse(Response{})               // Response: assumes status 200

func (*DocBuilder) ResponseHeader added in v0.0.13

func (b *DocBuilder) ResponseHeader(name, typ string, desc ...string) *DocBuilder

ResponseHeader adds a response header to the route documentation name: header name typ: header value type (e.g., "string", "int") desc: header description, optional

func (*DocBuilder) Summary added in v0.0.6

func (b *DocBuilder) Summary(summary string) *DocBuilder

Summary adds a short summary description to the route documentation.

func (*DocBuilder) Tags added in v0.0.6

func (b *DocBuilder) Tags(tags ...string) *DocBuilder

Tags adds one or more tags to the route documentation for categorization.

type EqualsExpr added in v0.0.12

type EqualsExpr struct {
	ClaimKey string
	Expected string
}

EqualsExpr checks if claim equals expected value

func Equals added in v0.0.12

func Equals(claimKey, expected string) *EqualsExpr

func (*EqualsExpr) Evaluate added in v0.0.12

func (e *EqualsExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type ErrorResponse added in v0.0.2

type ErrorResponse struct {
	Code      int       `json:"code"`
	Message   string    `json:"message"`
	Details   string    `json:"details,omitempty"`
	Timestamp time.Time `json:"timestamp"`
}

ErrorResponse represents a standardized error response structure

type Expression added in v0.0.12

type Expression interface {
	Evaluate(claims jwt.MapClaims) (bool, error)
}

Expression types for claims validation

func ParseExpression added in v0.0.12

func ParseExpression(input string) (Expression, error)

type ExpressionParser added in v0.0.12

type ExpressionParser struct {
	// contains filtered or unexported fields
}

type ExternalDocs added in v0.0.19

type ExternalDocs struct {
	Extensions map[string]any `json:"-" yaml:"-"`
	Origin     *Origin        `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`

	Description string `json:"description,omitempty" yaml:"description,omitempty"`
	URL         string `json:"url,omitempty" yaml:"url,omitempty"`
}

func (*ExternalDocs) ToOpenAPI added in v0.0.19

func (e *ExternalDocs) ToOpenAPI() *openapi3.ExternalDocs

type Group

type Group struct {
	// Prefix is the base path for all routes in this group.
	Prefix string
	// Tags is an optional tag for the group, used for documentation purposes.
	Tags []string
	// contains filtered or unexported fields
}

func NewGroup added in v0.0.13

func NewGroup(basePath string, okapi *Okapi, middlewares ...Middleware) *Group

func (*Group) Delete

func (g *Group) Delete(path string, h HandlerFunc, opts ...RouteOption) *Route

Delete registers a DELETE route within the group with the given path and handler.

func (*Group) Deprecated added in v0.0.12

func (g *Group) Deprecated() *Group

Deprecated marks the Group as deprecated for its routes. Returns the Group to allow method chaining.

func (*Group) Disable added in v0.0.6

func (g *Group) Disable() *Group

Disable marks the Group as disabled, causing all routes within it to return 404 Not Found. Returns the Group to allow method chaining.

func (*Group) Enable added in v0.0.6

func (g *Group) Enable() *Group

Enable marks the Group as enabled, allowing all routes within it to handle requests normally. Returns the Group to allow method chaining.

func (*Group) Get

func (g *Group) Get(path string, h HandlerFunc, opts ...RouteOption) *Route

Get registers a GET route within the group with the given path and handler.

func (*Group) Group

func (g *Group) Group(path string, middlewares ...Middleware) *Group

Group creates a nested subgroup with an additional path segment and optional middlewares. The new group inherits all middlewares from its parent group.

func (*Group) HandleHTTP added in v0.0.9

func (g *Group) HandleHTTP(method, path string, h http.Handler, opts ...RouteOption)

HandleHTTP registers a standard http.Handler and wraps it with the group's middleware chain.

func (*Group) HandleStd added in v0.0.9

func (g *Group) HandleStd(method, path string, h func(http.ResponseWriter, *http.Request), opts ...RouteOption)

HandleStd registers a standard http.HandlerFunc and wraps it with the group's middleware chain.

func (*Group) Head

func (g *Group) Head(path string, h HandlerFunc, opts ...RouteOption) *Route

Head registers a HEAD route within the group with the given path and handler.

func (*Group) Okapi

func (g *Group) Okapi() *Okapi

Okapi returns the parent Okapi instance associated with this group.

func (*Group) Options

func (g *Group) Options(path string, h HandlerFunc, opts ...RouteOption) *Route

Options registers an OPTIONS route within the group with the given path and handler.

func (*Group) Patch

func (g *Group) Patch(path string, h HandlerFunc, opts ...RouteOption) *Route

Patch registers a PATCH route within the group with the given path and handler.

func (*Group) Post

func (g *Group) Post(path string, h HandlerFunc, opts ...RouteOption) *Route

Post registers a POST route within the group with the given path and handler.

func (*Group) Put

func (g *Group) Put(path string, h HandlerFunc, opts ...RouteOption) *Route

Put registers a PUT route within the group with the given path and handler.

func (*Group) Register added in v0.0.13

func (g *Group) Register(routes ...RouteDefinition)

Register registers a slice of RouteDefinition with the group. It ensures that each route is associated with the group and its Okapi instance. If a route's Group field is nil, it assigns the current group to it. If the route's Group's Okapi reference is nil, it assigns the group's Okapi instance to it. This method is useful for bulk registering routes defined in a controller or similar structure.

Example:

routes := []okapi.RouteDefinition{
    {
        Method:  "GET",
        Path:    "/example",
        Handler: exampleHandler,
        Options: []okapi.RouteOption{
            okapi.DocSummary("Example GET request"),
        },
    },
    {
        Method:  "POST",
        Path:    "/example",
        Handler: exampleHandler,
        Options: []okapi.RouteOption{
            okapi.DocSummary("Example POST request"),
        },
    },
}
// Create a new Okapi instance
app := okapi.New()

api:= app.Group("/api")

api.Register(routes...)

func (*Group) Use

func (g *Group) Use(m ...Middleware)

Use adds one or more middlewares to the group's middleware chain. These middlewares will be executed in the order they are added, before the route handler for all routes within this group. Middlewares are inherited by any subgroups created from this group.

func (*Group) UseMiddleware added in v0.0.9

func (g *Group) UseMiddleware(mw func(http.Handler) http.Handler)

UseMiddleware registers a standard HTTP middleware function and integrates it into Okapi's middleware chain.

This enables compatibility with existing middleware libraries that use the func(http.Handler) http.Handler pattern.

func (*Group) WithBasicAuth added in v0.0.18

func (g *Group) WithBasicAuth() *Group

func (*Group) WithBearerAuth added in v0.0.10

func (g *Group) WithBearerAuth() *Group

WithBearerAuth marks the Group as requiring Bearer authentication for its routes. Returns the Group to allow method chaining.

func (*Group) WithSecurity added in v0.0.18

func (g *Group) WithSecurity(security []map[string][]string) *Group

WithSecurity sets the security requirements for the Group's routes.

func (*Group) WithTags added in v0.0.13

func (g *Group) WithTags(tags []string) *Group

WithTags sets the tags for the Group, which can be used for documentation purposes.

type HandlerFunc added in v0.1.3

type HandlerFunc func(*Context) error

HandlerFunc is a function type that takes a Context and returns an error.

func LoggerMiddleware

func LoggerMiddleware(next HandlerFunc) HandlerFunc

LoggerMiddleware is a middleware that logs request details like method, URL, client IP, status, duration, referer, and user agent.

type JSONSerializer added in v0.2.1

type JSONSerializer struct{}

JSONSerializer is the default JSON serializer

func (JSONSerializer) Serialize added in v0.2.1

func (j JSONSerializer) Serialize(data any) (string, error)

type JWTAuth

type JWTAuth struct {
	// SecretKey is a legacy secret key used for HMAC algorithms (e.g., HS256).
	// Deprecated: Use SigningSecret instead.
	SecretKey []byte

	// SigningSecret is the key used for signing/validating tokens when using symmetric algorithms like HS256.
	SigningSecret []byte

	// JwksFile provides a static JWKS (JSON Web Key Set), either from a file or base64-encoded string.
	// Use okapi.LoadJWKSFromFile() to load the JWKS from a file.
	// Optional.
	JwksFile *Jwks

	// JwksUrl specifies a remote JWKS endpoint URL for key discovery.
	// Optional.
	JwksUrl string

	// Audience is the expected "aud" (audience) claim in the token.
	// Optional.
	Audience string

	// Issuer is the expected "iss" (issuer) claim in the token.
	// Optional.
	Issuer string

	// RsaKey is a public RSA key used to verify tokens signed with RS256.
	// Optional.
	RsaKey *rsa.PublicKey

	// Algo specifies the expected signing algorithm (e.g., "RS256", "HS256").
	// Optional.
	Algo string

	// TokenLookup defines how and where to extract the token from the request.
	// Supported formats include:
	//   - "header:Authorization" (default)
	//   - "query:token"
	//   - "cookie:jwt"
	TokenLookup string
	// ContextKey is the key used to store the full validated JWT claims in the request context.
	//
	// Use this when you need access to the entire set of claims for advanced processing or custom logic
	// within your handler or middleware.
	//
	// If you only need specific claim values (e.g., "user.email", "user.id"), consider using ForwardClaims instead.
	//
	// Example:
	//   ContextKey: "user"
	ContextKey string
	// ForwardClaims maps context keys to JWT claim paths (supports dot notation for nested fields).
	// This extracts selected claims and stores them in the request context under the specified keys.
	//
	// Use this when you want to expose only specific claims to handlers or middleware, without
	// needing access to the entire token.
	//
	// Example:
	//   ForwardClaims: map[string]string{
	//     "email": "user.email",
	//     "uid":   "user.id",
	//   }
	ForwardClaims map[string]string
	// ClaimsExpression defines a custom expression to validate JWT claims.
	// Useful for enforcing advanced conditions on claims such as role, scope, or custom fields.
	//
	// Supported functions:
	//   - Equals(field, value)
	//   - Prefix(field, prefix)
	//   - Contains(field, val1, val2, ...)
	//   - OneOf(field, val1, val2, ...)
	//
	// Logical Operators:
	//   - !   — NOT
	//   - &&  — AND (evaluated before OR)
	//   - ||  — OR  (evaluated after AND)
	//
	// These operators allow you to combine multiple expressions to create complex validation logic.
	// Example:
	//   jwtAuth.ClaimsExpression = "Equals(`email_verified`, `true`) && OneOf(`user.role`, `admin`, `owner`) && Contains(`tags`, `vip`, `premium`)"
	//
	// In the above:
	//   - The expression ensures the user is verified AND either has an admin/owner role,
	//     OR belongs to a premium tag group.
	ClaimsExpression string

	// ValidateClaims is an optional custom validation function for processing JWT claims.
	// This provides full control over claim validation logic and can be used alongside or
	// instead of ClaimsExpression.
	//
	// Return an error to reject the request.
	//
	// Example:
	//   ValidateClaims: func(c *okapi.Context,claims jwt.Claims) error {
	//     mapClaims, ok := claims.(jwt.MapClaims)
	//     if !ok {
	//       return errors.New("invalid claims type")
	//     }
	//     if emailVerified, _ := mapClaims["email_verified"].(bool); !emailVerified {
	//       return errors.New("email not verified")
	//     }
	//     if role, _ := mapClaims["role"].(string); role != "admin" {
	//       return errors.New("unauthorized role")
	//     }
	//     return nil
	//   }
	ValidateClaims func(c *Context, claims jwt.Claims) error
	// OnUnauthorized defines a custom handler function that is called when JWT validation fails.
	// This includes scenarios such as missing, expired, malformed, or invalid tokens,
	// or when claims validation (via ClaimsExpression or ValidateClaims) is unsuccessful.
	//
	// Use this to customize the error response sent to unauthorized clients.
	OnUnauthorized HandlerFunc

	// Deprecated: Use ValidateClaims instead.
	//
	// ValidateRole was previously used for role-based access control, but has been
	// replaced by the more general ValidateClaims function which allows for flexible
	// validation of any JWT claims.
	ValidateRole func(claims jwt.Claims) error
	// contains filtered or unexported fields
}

JWTAuth is a configuration struct for JWT-based authentication middleware.

You must configure at least one token verification mechanism: - SigningSecret: for HMAC algorithms - RsaKey: for RSA algorithms (e.g. RS256) - JwksUrl: to fetch public keys dynamically from a JWKS endpoint - JwksFile: to load static JWKS from a file or base64 string, use okapi.LoadJWKSFromFile()

Fields: JWTAuth holds configuration for JWT-based authentication.

func (*JWTAuth) Middleware

func (jwtAuth *JWTAuth) Middleware(next HandlerFunc) HandlerFunc

Middleware validates JWT tokens from the configured source

func (*JWTAuth) ValidateToken

func (jwtAuth *JWTAuth) ValidateToken(c *Context) (jwt.MapClaims, error)

ValidateToken checks the JWT token and returns the claims if valid

type Jwk added in v0.0.9

type Jwk struct {
	Kid string `json:"kid"`
	Kty string `json:"kty"`
	N   string `json:"n"`   // RSA modulus
	E   string `json:"e"`   // RSA exponent
	Crv string `json:"crv"` // for EC
	X   string `json:"x"`   // for EC
	Y   string `json:"y"`   // for EC
}

type Jwks added in v0.0.9

type Jwks struct {
	Keys []Jwk `json:"keys"`
}

func LoadJWKSFromFile added in v0.0.9

func LoadJWKSFromFile(jwksInput string) (*Jwks, error)

LoadJWKSFromFile loads a JWKS (JSON Web Key Set) from a file path or a base64-encoded string.

If the input is a base64-encoded string, it decodes it. Otherwise, it treats the input as a file path and attempts to open and read it. The function returns a parsed *Jwks struct or an error if any step fails.

type License added in v0.0.5

type License struct {
	Extensions map[string]any `json:"-" yaml:"-"`                         // Custom extensions not part of OpenAPI spec
	Name       string         `json:"name" yaml:"name"`                   // Required license name (e.g., "MIT")
	URL        string         `json:"url,omitempty" yaml:"url,omitempty"` // Optional URL to the license
}

License contains license information for the API. It follows the OpenAPI specification format.

func (License) ToOpenAPI added in v0.0.5

func (l License) ToOpenAPI() *openapi3.License

ToOpenAPI converts License to openapi3.License. It transforms the custom License type to the format expected by the openapi3 package.

type Location added in v0.0.19

type Location struct {
	Line   int `json:"line,omitempty" yaml:"line,omitempty"`
	Column int `json:"column,omitempty" yaml:"column,omitempty"`
}

func (*Location) ToOpenAPI added in v0.2.2

func (l *Location) ToOpenAPI() openapi3.Location

type Logger

type Logger struct {
}

Logger is a middleware that logs request details such as method, URL, client IP, status, duration, referer, and user agent.

type M

type M map[string]any

M is shortcut of map[string]any

type Message

type Message struct {
	// ID unique identifier for the message
	ID string `json:"id"`
	// Event type
	Event string `json:"event"`
	//  Data payload
	Data any `json:"message"`
	// Retry interval
	Retry uint `json:"retry,omitempty"`
	// Serializer to use for the message
	Serializer Serializer `json:"-"`
}

Message represents a Server-Sent Events (SSE) message.

func (*Message) Close

func (m *Message) Close(w http.ResponseWriter) error

Close flushes the response writer to ensure data is sent to the client.

func (*Message) Send

func (m *Message) Send(w http.ResponseWriter) (string, error)

Send writes an SSE message to the response writer.

type Middleware

type Middleware func(next HandlerFunc) HandlerFunc

type NotExpr added in v0.0.12

type NotExpr struct {
	Expr Expression
}

func Not added in v0.0.12

func Not(expr Expression) *NotExpr

func (*NotExpr) Evaluate added in v0.0.12

func (n *NotExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type OAuthFlow added in v0.0.18

type OAuthFlow struct {
	AuthorizationURL string
	TokenURL         string
	RefreshURL       string
	Scopes           map[string]string
}

func (*OAuthFlow) ToOpenAPI added in v0.0.18

func (f *OAuthFlow) ToOpenAPI() *openapi3.OAuthFlow

type OAuthFlows added in v0.0.18

type OAuthFlows struct {
	Implicit          *OAuthFlow
	Password          *OAuthFlow
	ClientCredentials *OAuthFlow
	AuthorizationCode *OAuthFlow
}

func (*OAuthFlows) ToOpenAPI added in v0.0.18

func (flows *OAuthFlows) ToOpenAPI() *openapi3.OAuthFlows

type Okapi

type Okapi struct {
	// contains filtered or unexported fields
}

Okapi represents the core application structure of the framework, holding configuration, routers, middleware, server settings, and documentation components.

func Default

func Default() *Okapi

Default creates a new Okapi instance with default settings.

func New

func New(options ...OptionFunc) *Okapi

New creates a new Okapi instance with the provided options.

func (*Okapi) Any

func (o *Okapi) Any(path string, h HandlerFunc, opts ...RouteOption) *Route

Any registers a route that matches any HTTP method with the given path and handler function. Returns the created *Route for possible chaining or modification.

Useful for handlers that need to respond to multiple HTTP methods uniformly.

Example:

o.Any("/health", func(c okapi.Context) error {
    return c.String(200, "OK")
})

func (*Okapi) Delete

func (o *Okapi) Delete(path string, h HandlerFunc, opts ...RouteOption) *Route

Delete registers a new DELETE route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Commonly used for removing resources.

Example:

o.Delete("/users/{id}", func(c okapi.Context) error {
    id := c.Param("id")
    // Delete user logic...
    return c.NoContent(204)
})

func (*Okapi) DisableAccessLog added in v0.0.4

func (o *Okapi) DisableAccessLog() *Okapi

func (*Okapi) Get

func (o *Okapi) Get(path string, h HandlerFunc, opts ...RouteOption) *Route

Get registers a new GET route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Path parameters support type hints for OpenAPI documentation generation:

  • /users/{id} or /users/:id -> "id" documented as UUID in OpenAPI
  • /users/{user_id} -> "user_id" documented as UUID in OpenAPI
  • /users/{id:int} or /users/:id:int -> "id" documented as integer in OpenAPI
  • /users/{user_id:uuid} -> "user_id" documented as UUID in OpenAPI

Note: Type hints affect OpenAPI schema generation only. All parameters are accessed as strings via Context.Param() at runtime.

Example:

o.Get("/users/{id:int}", func(c okapi.Context) error {
    userID := c.Param("id") // Returns string "123"
    return c.JSON(200, okapi.M{"user_id": userID})
})

func (*Okapi) GetContext

func (o *Okapi) GetContext() *Context

GetContext returns the current context

func (*Okapi) Group

func (o *Okapi) Group(prefix string, middlewares ...Middleware) *Group

Group creates a new route group with the specified base path and optional middlewares. The group inherits all existing middlewares from the parent Okapi instance. Routes registered within the group will have their paths prefixed with the group's path, and the group's middlewares will be executed before the route-specific handlers.

Panics if the path is empty, as this would lead to ambiguous routing.

Example:

api := okapi.Group("/api", AuthMiddleware) // All /api routes require auth
api.Get("/users", getUserHandler)          // Handles /api/users
api.Post("/users", createUserHandler)      // Handles /api/users

func (*Okapi) Handle added in v0.0.4

func (o *Okapi) Handle(method, path string, h HandlerFunc, opts ...RouteOption)

Handle registers a new route with the given HTTP method, path, and Okapi-style handler function.

It performs the following steps:

  1. Normalizes the route path
  2. Creates and configures a new Route instance
  3. Applies all registered middleware to the handler
  4. Registers the route with the underlying router (with method filtering)
  5. Adds centralized error handling for the route

Parameters:

  • method: HTTP method (e.g., "GET", "POST", "PUT")
  • path: URL path pattern (supports path parameters, e.g., /users/:id)
  • h: A handler function using Okapi's Context abstraction
  • opts: Optional route metadata (e.g., OpenAPI summary, description, tags)

Middleware:

All middleware registered via Use() or UseMiddleware() will be applied in order,
wrapping around the handler.

Error Handling:

Any non-nil error returned by the handler will automatically result in a
500 Internal Server Error response.

Example:

okapi.Handle("GET", "/users/:id", func(c *okapi.Context) error {
    id := c.Param("id")
    // process request...
    return nil
})

func (*Okapi) HandleHTTP added in v0.0.8

func (o *Okapi) HandleHTTP(method, path string, h http.Handler, opts ...RouteOption)

HandleHTTP registers a new route using a standard http.Handler.

It wraps the provided http.Handler into Okapi's internal HandlerFunc signature and processes it as if it were registered via Handle.

Parameters:

  • method: HTTP method (e.g., "GET", "POST", "DELETE")
  • path: URL path pattern (supports dynamic segments)
  • h: A standard http.Handler (or http.HandlerFunc)
  • opts: Optional route metadata (e.g., OpenAPI summary, description, tags)

Differences from Handle:

  • Uses the standard http.Handler interface
  • Middleware is still applied
  • Errors must be handled inside the handler itself (Okapi will not capture them)

Example:

okapi.HandleHTTP("GET", "/static", http.FileServer(http.Dir("./public")))

func (*Okapi) HandleStd added in v0.0.8

func (o *Okapi) HandleStd(method, path string, h func(http.ResponseWriter, *http.Request), opts ...RouteOption)

HandleStd is a convenience method for registering handlers using the standard http.HandlerFunc signature (func(http.ResponseWriter, *http.Request)).

Internally, it wraps the handler into http.Handler and delegates to HandleHTTP.

Example:

okapi.HandleStd("GET", "/greet", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello from Okapi!"))
})

This handler will still benefit from:

  • All registered middleware
  • Automatic route and CORS registration

func (*Okapi) Head

func (o *Okapi) Head(path string, h HandlerFunc, opts ...RouteOption) *Route

Head registers a new HEAD route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Identical to GET but without the response body, useful for checking resource existence or metadata.

func (*Okapi) NoMethod added in v0.0.10

func (o *Okapi) NoMethod(h HandlerFunc)

NoMethod sets a custom handler to be executed when the HTTP method is not allowed.

This function is triggered when the request path exists but the method (e.g., POST, GET) is not allowed. It enables you to define a consistent response for unsupported HTTP methods (405).

Example:

o.NoMethod(func(c okapi.Context) error {
 return c.AbortMethodNotAllowed("Custom 405 - Method Not Allowed")
})

func (*Okapi) NoRoute added in v0.0.10

func (o *Okapi) NoRoute(h HandlerFunc)

NoRoute sets a custom handler to be executed when no matching route is found.

This function allows you to define a fallback handler for unmatched routes (404). It is useful for returning custom error pages or JSON responses when a route doesn't exist.

Example:

o.NoRoute(func(c okapi.Context) error {
	return c.AbortNotFound("Custom 404 - Not found")
})

func (*Okapi) Options

func (o *Okapi) Options(path string, h HandlerFunc, opts ...RouteOption) *Route

Options registers a new OPTIONS route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Commonly used for CORS preflight requests to describe communication options.

func (*Okapi) Patch

func (o *Okapi) Patch(path string, h HandlerFunc, opts ...RouteOption) *Route

Patch registers a new PATCH route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Commonly used for partial updates to resources.

Example:

o.Patch("/users/{id}", func(c okapi.Context) error {
    id := c.Param("id")
    var updates map[string]any
    if err := c.Bind(&updates); err != nil {
        return err
    }
    // Partial update logic...
    return c.JSON(200, updates)
})

func (*Okapi) Post

func (o *Okapi) Post(path string, h HandlerFunc, opts ...RouteOption) *Route

Post registers a new POST route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Commonly used for creating resources. The handler can access request body via Context.Bind() or Context.Body().

Example:

o.Post("/users", func(c okapi.Context) error {
    var user User
    if err := c.Bind(&user); err != nil {
        return err
    }
    // Create user logic...
    return c.Created(user)
})

func (*Okapi) PrintServerInfo added in v0.2.2

func (o *Okapi) PrintServerInfo()

func (*Okapi) Put

func (o *Okapi) Put(path string, h HandlerFunc, opts ...RouteOption) *Route

Put registers a new PUT route with the given path and handler function. Returns the created *Route for possible chaining or modification.

Commonly used for replacing/updating entire resources.

Example:

o.Put("/users/{id}", func(c okapi.Context) error {
    id := c.Param("id")
    var user User
    if err := c.Bind(&user); err != nil {
        return err
    }
    // Update user logic...
    return c.JSON(200, user)
})

func (*Okapi) Register added in v0.0.13

func (o *Okapi) Register(routes ...RouteDefinition)

Register registers a list of RouteDefinition to the Okapi instance. This method allows you to define multiple routes in a single call, which can be useful for organizing your routes in a more structured way. Example:

routes := []okapi.RouteDefinition{
    {
        Method:  "POST",
        Path:    "/example",
        Handler: exampleHandler,
		Middlewares: []okapi.Middleware{customMiddleware}
		OperationId: "PostExample",
		Summary: "Example POST request",
		Description: "This endpoint handles example POST request.",
		Request: &RequestExample{},
		Response: &ResponseExample{}
    },
    {
        Method:  "GET",
        Path:    "/example",
        Handler: exampleHandler,
        Options: []okapi.RouteOption{
            okapi.DocSummary("Example GET request"),
        },
    	Security: Security: []map[string][]string{
			{
				"bearerAuth": {},
			},
		},
    },
}
// Create a new Okapi instance
app := okapi.New()
app.Register(routes...)

func (*Okapi) RegisterSchemas added in v0.1.1

func (o *Okapi) RegisterSchemas(schemas map[string]*SchemaInfo) error

RegisterSchemas registers component schemas that are re-used as references.

func (*Okapi) Routes

func (o *Okapi) Routes() []Route

func (*Okapi) ServeHTTP

func (o *Okapi) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface

func (*Okapi) SetContext

func (o *Okapi) SetContext(ctx *Context)

func (*Okapi) Shutdown

func (o *Okapi) Shutdown(server *http.Server) error

Shutdown performs graceful shutdown of the provided server using a background context

func (*Okapi) Start

func (o *Okapi) Start() error

Start starts the Okapi server

func (*Okapi) StartForTest added in v0.1.3

func (o *Okapi) StartForTest(t TestingT) string

StartForTest starts the Okapi server for testing and returns the base URL.

func (*Okapi) StartOn added in v0.0.19

func (o *Okapi) StartOn(port int) error

StartOn starts the Okapi server with custom port

func (*Okapi) StartServer

func (o *Okapi) StartServer(server *http.Server) error

StartServer starts the Okapi server with the specified HTTP server

func (*Okapi) Static

func (o *Okapi) Static(prefix string, dir string)

Static serves static files under a path prefix, without directory listing

func (*Okapi) StaticFS

func (o *Okapi) StaticFS(prefix string, fs http.FileSystem)

StaticFS serves static files from a custom http.FileSystem (e.g., embed.FS).

func (*Okapi) StaticFile

func (o *Okapi) StaticFile(path string, filepath string)

StaticFile serves a single file at the specified path.

func (*Okapi) Stop

func (o *Okapi) Stop() error

Stop gracefully shuts down the Okapi HTTP and HTTPS server(s)

func (*Okapi) Use

func (o *Okapi) Use(middlewares ...Middleware)

Use registers one or more middleware functions to the Okapi instance. These middleware will be executed in the order they are added for every request before reaching the route handler. Middleware added here will apply to all routes registered on this Okapi instance and any groups created from it.

Middleware functions have the signature:

func(next HandlerFunc) HandlerFunc

Example:

// Add logging and authentication middleware
okapi.Use(LoggingMiddleware, AuthMiddleware)

Note: For group-specific middleware, use Group.Use() instead.

func (*Okapi) UseMiddleware added in v0.0.8

func (o *Okapi) UseMiddleware(mw func(http.Handler) http.Handler)

UseMiddleware registers a standard HTTP middleware function and integrates it into Okapi's middleware chain.

This enables compatibility with existing middleware libraries that use the func(http.Handler) http.Handler pattern.

Example:

okapi.UseMiddleware(func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.request) {
        w.Header().Set("X-Powered-By", "Okapi")
        next.ServeHTTP(w, r)
    })
})

Internally, Okapi converts between http.Handler and HandlerFunc to allow smooth interop.

func (*Okapi) WaitForServer added in v0.1.3

func (o *Okapi) WaitForServer(timeout time.Duration) string

WaitForServer waits until the server is ready and returns the address

func (*Okapi) With

func (o *Okapi) With(options ...OptionFunc) *Okapi

With applies the provided options to the Okapi instance

func (*Okapi) WithAddr added in v0.0.4

func (o *Okapi) WithAddr(addr string) *Okapi

func (*Okapi) WithCORS added in v0.0.4

func (o *Okapi) WithCORS(cors Cors) *Okapi

func (*Okapi) WithDebug added in v0.0.4

func (o *Okapi) WithDebug() *Okapi

func (*Okapi) WithIdleTimeout added in v0.0.4

func (o *Okapi) WithIdleTimeout(seconds int) *Okapi

func (*Okapi) WithLogger added in v0.0.4

func (o *Okapi) WithLogger(logger *slog.Logger) *Okapi

func (*Okapi) WithMaxMultipartMemory added in v0.0.7

func (o *Okapi) WithMaxMultipartMemory(max int64) *Okapi

func (*Okapi) WithOpenAPIDisabled added in v0.0.10

func (o *Okapi) WithOpenAPIDisabled() *Okapi

WithOpenAPIDisabled disabled OpenAPI Docs

func (*Okapi) WithOpenAPIDocs added in v0.0.4

func (o *Okapi) WithOpenAPIDocs(cfg ...OpenAPI) *Okapi

WithOpenAPIDocs registers the OpenAPI JSON and Swagger UI handlers at the configured PathPrefix (default: /docs).

UI Path: /docs JSON Path: /openapi.json

func (*Okapi) WithPort added in v0.0.4

func (o *Okapi) WithPort(port int) *Okapi

func (*Okapi) WithReadTimeout added in v0.0.4

func (o *Okapi) WithReadTimeout(seconds int) *Okapi

func (*Okapi) WithRenderer added in v0.0.10

func (o *Okapi) WithRenderer(renderer Renderer) *Okapi

WithRenderer sets a custom Renderer for the server.

This allows you to define how templates or views are rendered in response handlers. You can implement the Renderer interface on your own type, or use the built-in RendererFunc adapter to provide an inline function.

Example using a custom Renderer type:

type Template struct {
	templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c okapi.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

o := okapi.New().WithRenderer(&Template{templates: template.Must(template.ParseGlob("public/views/*.html"))})

Example using RendererFunc:

o := okapi.New().WithRenderer(okapi.RendererFunc(func(w io.Writer,
name string, data interface{}, c *okapi.Context) error {
	tmpl, err := template.ParseFiles("public/views/" + name + ".html")
	if err != nil {
		return err
	}
	return tmpl.ExecuteTemplate(w, name, data)
}))

func (*Okapi) WithStrictSlash added in v0.0.4

func (o *Okapi) WithStrictSlash(strict bool) *Okapi

func (*Okapi) WithWriteTimeout added in v0.0.4

func (o *Okapi) WithWriteTimeout(seconds int) *Okapi

type OneOfExpr added in v0.0.12

type OneOfExpr struct {
	ClaimKey string
	Values   []string
}

func OneOf added in v0.0.12

func OneOf(claimKey string, values ...string) *OneOfExpr

func (*OneOfExpr) Evaluate added in v0.0.12

func (o *OneOfExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type OpenAPI added in v0.0.4

type OpenAPI struct {
	Title   string  // Title of the API
	Version string  // Version of the API
	Servers Servers // List of server URLs where the API is hosted
	License License // License information for the API
	Contact Contact // Contact information for the API maintainers
	// SecuritySchemes defines security schemes for the OpenAPI specification.
	SecuritySchemes  SecuritySchemes
	ExternalDocs     *ExternalDocs
	ComponentSchemas map[string]*SchemaInfo
}

OpenAPI contains configuration for generating OpenAPI/Swagger documentation. It includes metadata about the API and its documentation.

func (OpenAPI) ToOpenAPISpec added in v0.0.5

func (o OpenAPI) ToOpenAPISpec() *openapi3.T

ToOpenAPISpec converts OpenAPI to *openapi3.T. It transforms the custom OpenAPI configuration to a complete OpenAPI specification object.

type OptionFunc

type OptionFunc func(*Okapi)

func WithAccessLogDisabled

func WithAccessLogDisabled() OptionFunc

WithAccessLogDisabled disables access logging

func WithAddr

func WithAddr(addr string) OptionFunc

WithAddr sets the server address

func WithCors added in v0.0.2

func WithCors(cors Cors) OptionFunc

WithCors returns an OptionFunc that configures CORS settings

func WithDebug

func WithDebug() OptionFunc

WithDebug enables debug mode and access logging

func WithIdleTimeout added in v0.0.3

func WithIdleTimeout(t int) OptionFunc

WithIdleTimeout returns an OptionFunc that sets the idle timeout

func WithLogger

func WithLogger(logger *slog.Logger) OptionFunc

WithLogger sets the logger for the Okapi instance

func WithMaxMultipartMemory added in v0.0.7

func WithMaxMultipartMemory(max int64) OptionFunc

WithMaxMultipartMemory Maximum memory for multipart forms

func WithMuxRouter added in v0.0.10

func WithMuxRouter(router *mux.Router) OptionFunc

WithMuxRouter sets the router for the Okapi instance

func WithOpenAPIDisabled added in v0.0.5

func WithOpenAPIDisabled() OptionFunc

WithOpenAPIDisabled disabled OpenAPI Docs

func WithPort

func WithPort(port int) OptionFunc

WithPort sets the server port

func WithReadTimeout added in v0.0.3

func WithReadTimeout(t int) OptionFunc

WithReadTimeout returns an OptionFunc that sets the read timeout

func WithRenderer added in v0.0.10

func WithRenderer(renderer Renderer) OptionFunc

WithRenderer sets a custom Renderer for the server.

This allows you to define how templates or views are rendered in response handlers. You can implement the Renderer interface on your own type, or use the built-in RendererFunc adapter to provide an inline function.

Example using a custom Renderer type:

type Template struct {
	templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c okapi.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

o := okapi.New().WithRenderer(&Template{templates: template.Must(template.ParseGlob("public/views/*.html"))})

Example using RendererFunc:

o := okapi.New().WithRenderer(okapi.RendererFunc(func(w io.Writer,
name string, data interface{}, c *okapi.Context) error {
	tmpl, err := template.ParseFiles("public/views/" + name + ".html")
	if err != nil {
		return err
	}
	return tmpl.ExecuteTemplate(w, name, data)
}))

func WithServer

func WithServer(server *http.Server) OptionFunc

WithServer sets the HTTP server for the Okapi instance

func WithStrictSlash

func WithStrictSlash(strict bool) OptionFunc

WithStrictSlash sets whether to enforce strict slash handling

func WithTLS added in v0.0.4

func WithTLS(tlsConfig *tls.Config) OptionFunc

WithTLS sets tls config to HTTP Server for the Okapi instance

Use okapi.LoadTLSConfig() to create a TLS configuration from certificate and key files

func WithTLSServer

func WithTLSServer(addr string, tlsConfig *tls.Config) OptionFunc

WithTLSServer sets the TLS server for the Okapi instance

Use okapi.LoadTLSConfig() to create a TLS configuration from certificate and key files

func WithWriteTimeout added in v0.0.3

func WithWriteTimeout(t int) OptionFunc

WithWriteTimeout returns an OptionFunc that sets the write timeout

type OrExpr added in v0.0.12

type OrExpr struct {
	Left  Expression
	Right Expression
}

func Or added in v0.0.12

func Or(left, right Expression) *OrExpr

func (*OrExpr) Evaluate added in v0.0.12

func (o *OrExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type Origin added in v0.0.19

type Origin struct {
	Key    *Location           `json:"key,omitempty" yaml:"key,omitempty"`
	Fields map[string]Location `json:"fields,omitempty" yaml:"fields,omitempty"`
}

func (*Origin) ToOpenAPI added in v0.2.2

func (o *Origin) ToOpenAPI() *openapi3.Origin

type PrefixExpr added in v0.0.12

type PrefixExpr struct {
	ClaimKey string
	Prefix   string
}

PrefixExpr checks if claim starts with prefix

func Prefix added in v0.0.12

func Prefix(claimKey, prefix string) *PrefixExpr

func (*PrefixExpr) Evaluate added in v0.0.12

func (p *PrefixExpr) Evaluate(claims jwt.MapClaims) (bool, error)

type Renderer

type Renderer interface {
	Render(io.Writer, string, interface{}, *Context) error
}

type RendererFunc

type RendererFunc func(io.Writer, string, interface{}, *Context) error

func (RendererFunc) Render

func (f RendererFunc) Render(w io.Writer, name string, data interface{}, c *Context) error

type ResponseWriter added in v0.1.0

type ResponseWriter interface {
	http.ResponseWriter

	// StatusCode returns the written status code, or 0 if not written.
	StatusCode() int

	// BytesWritten returns number of bytes written to the body.
	BytesWritten() int

	// Close closes the writer if supported. Returns error instead of hiding it.
	Close() error

	// Hijack upgrades to raw TCP if supported (WebSockets, proxy, etc).
	Hijack() (net.Conn, *bufio.ReadWriter, error)

	// Flush flushes buffered data if supported (streaming, SSE, gzip, etc).
	Flush()

	// Push initiates HTTP/2 server push if supported.
	Push(string, *http.PushOptions) error
}

ResponseWriter extends http.ResponseWriter with additional utilities.

type Route

type Route struct {
	Name   string
	Path   string
	Method string
	// contains filtered or unexported fields
}

Route defines the structure of a registered HTTP route in the framework. It includes metadata used for routing, OpenAPI documentation, and middleware handling.

func (*Route) Deprecated added in v0.0.15

func (r *Route) Deprecated() *Route

Deprecated marks the Route as deprecated. Returns the Route to allow method chaining.

func (*Route) Disable added in v0.0.6

func (r *Route) Disable() *Route

Disable marks the Route as disabled, causing it to return 404 Not Found. Returns the Route to allow method chaining.

func (*Route) Enable added in v0.0.6

func (r *Route) Enable() *Route

Enable marks the Route as enabled, allowing it to handle requests normally. Returns the Route to allow method chaining.

func (*Route) Hide added in v0.0.19

func (r *Route) Hide() *Route

Hide marks the Route as hidden, preventing it from being listed in OpenAPI documentation.

func (*Route) Use added in v0.0.15

func (r *Route) Use(m ...Middleware)

Use registers one or more middleware functions to the Route.

func (*Route) WithIO added in v0.1.0

func (r *Route) WithIO(req any, res any) *Route

WithIO sets both the input (request) and output (response) schemas for the route. This is a convenience method that combines WithInput and WithOutput in a single call. Both parameters are optional: pass nil if you only want one side.

Example:

route.WithIO(CreateBookInput{}, BookResponse{})

func (*Route) WithInput added in v0.1.0

func (r *Route) WithInput(req any) *Route

WithInput sets the input (request) schema for the route. The value should be a struct or pointer to a struct with binding tags (query, path, header, cookie, form, body). If provided, Okapi will:

  • Bind incoming request data to the struct
  • Validate based on struct tags
  • Generate OpenAPI documentation for the request schema

func (*Route) WithOutput added in v0.1.0

func (r *Route) WithOutput(res any) *Route

WithOutput sets the output (response) schema for the route. The value can be any type (struct, slice, map, etc.). If provided, Okapi will:

  • Serialize the value into the response body
  • Generate OpenAPI documentation for the response schema

func (*Route) WithSecurity added in v0.0.18

func (r *Route) WithSecurity(security ...map[string][]string) *Route

WithSecurity sets the security requirements for the Route.

type RouteDefinition added in v0.0.13

type RouteDefinition struct {
	// Method is the HTTP method for the route (e.g., GET, POST, PUT, DELETE, etc.)
	Method string
	// Path is the URL path for the route, relative to the base path of the Okapi instance or group
	Path string
	// Handler is the function that will handle requests to this route
	Handler HandlerFunc
	// OperationId is an optional unique identifier for the route, primarily
	// used in OpenAPI documentation to distinguish operations.
	OperationId string
	// Summary is an optional short description of the route,
	// used for OpenAPI documentation.
	// Example: "Create a new book"
	Summary string
	// Description is an optional detailed description of the route,
	// used for OpenAPI documentation.
	// Example:  "This endpoint allows clients to create a new book in the system by providing the necessary details."
	Description string

	// Request optionally defines the expected input schema for the route.
	// It can be a struct or pointer to a struct with binding tags (query, path, header, cookie, form, body).
	// If provided, Okapi will:
	//   - Bind incoming request data to the struct
	//   - Perform validations based on struct tags (e.g., required, minLength, maxLength, default)
	//   - Generate OpenAPI documentation for the request schema
	//
	// Note: To generate OpenAPI documentation, it is recommended to use a struct or pointer to a struct.
	//
	// Example:
	//	type CreateBookInput struct {
	// 		 Tags []string `query:"tags"`
	//		 XApiKey string `header:"X-API-KEY" required:"true" description:"API Key"`
	//		 Body struct {
	// 		 	Title string `json:"title" required:"true" minLength:"5"  maxLength:"100" description:"Book title"`
	// 		 	Price int    `json:"price" max:"5" min:"2"  yaml:"price" required:"true" description:"Book price"`
	// 		}
	//		}
	//   RouteDefinition{
	//       Method:  "POST",
	//       Path:    "/books",
	//       Request: &CreateBookInput{},
	//   }
	Request any

	// Response optionally defines the output schema for the route.
	// It can be any type (struct, slice, map, etc.). If provided, Okapi will:
	//   - Serialize the value into the response body (e.g., JSON)
	//   - Generate OpenAPI documentation for the response schema
	//
	// Note: To generate OpenAPI documentation, it is recommended to use a struct or pointer to a struct.
	//
	// Example:
	//   type BookResponse struct {
	//       ID    string `json:"id"`
	//       Title string `json:"title"`
	//   }
	//   RouteDefinition{
	//       Method:   "POST",
	//       Path:     "/books",
	//       Request:  &CreateBookInput{},
	//       Response: &BookResponse{},
	//   }
	Response any
	// Security defines the security requirements for the route, such as authentication schemes // Optional
	// It can be also applied at Group level.
	Security []map[string][]string
	// RouteOption registers one or more OpenAPI Doc and middleware functions to the Route. // Optional
	Options []RouteOption
	// Middleware registers one or more middleware functions to the Route. // Optional
	Middlewares []Middleware
	// Group attach Route to a Group // Optional
	Group *Group
}

type RouteOption added in v0.0.4

type RouteOption func(*Route)

RouteOption defines a function type that modifies a Route's documentation properties

func Deprecated added in v0.1.0

func Deprecated() RouteOption

Deprecated marks the route as deprecated

func Description added in v0.1.0

func Description(description string) RouteOption

Description adds a description to the route documentation.

func DocAutoPathParams added in v0.0.4

func DocAutoPathParams() RouteOption

DocAutoPathParams automatically extracts path parameters from the route path and adds them to the documentation. It skips parameters that are already defined.

func DocBasicAuth added in v0.0.18

func DocBasicAuth() RouteOption

DocBasicAuth marks the route as requiring Basic authentication

func DocBearerAuth added in v0.0.4

func DocBearerAuth() RouteOption

DocBearerAuth marks the route as requiring Bearer token authentication

func DocDeprecated added in v0.0.8

func DocDeprecated() RouteOption

DocDeprecated marks the route as deprecated

func DocDescription added in v0.0.13

func DocDescription(description string) RouteOption

DocDescription sets a description for the route

func DocErrorResponse added in v0.0.7

func DocErrorResponse(status int, v any) RouteOption

DocErrorResponse defines an error response schema for a specific HTTP status code in the route's OpenAPI documentation. Deprecated: This function is deprecated in favor of DocResponse(status, v).

Parameters:

  • status: the HTTP status code (e.g., 400, 404, 500).
  • v: a Go value (e.g., a struct instance) whose type will be used to generate the OpenAPI schema for the error response.

Returns:

  • A RouteOption function that adds the error schema to the route's documentation.

func DocHeader added in v0.0.4

func DocHeader(name, typ, desc string, required bool) RouteOption

DocHeader adds a header parameter to the route documentation name: header name typ: header value type (e.g., "string", "int") desc: header description required: whether the header is required

func DocHeaderWithDefault added in v0.1.0

func DocHeaderWithDefault(name, typ, desc string, required bool, defvalue any) RouteOption

DocHeaderWithDefault adds a header parameter to the route documentation with default (if provided) name: header name typ: header value type (e.g., "string", "int") desc: header description required: whether the header is required defvalue: default value to use

func DocHide added in v0.0.19

func DocHide() RouteOption

DocHide marks the route to be excluded from OpenAPI documentation.

func DocOperationId added in v0.0.19

func DocOperationId(operationId string) RouteOption

func DocPathParam added in v0.0.4

func DocPathParam(name, typ, desc string) RouteOption

DocPathParam adds a path parameter to the route documentation name: parameter name typ: parameter type (e.g., "string", "int", "uuid") desc: parameter description

func DocPathParamWithDefault added in v0.1.1

func DocPathParamWithDefault(name, typ, desc string, defvalue any) RouteOption

DocPathParamWithDefault adds a path parameter to the route documentation name: parameter name typ: parameter type (e.g., "string", "int", "uuid") desc: parameter description defvalue: default value to use.

func DocQueryParam added in v0.0.4

func DocQueryParam(name, typ, desc string, required bool) RouteOption

DocQueryParam adds a query parameter to the route documentation name: parameter name typ: parameter type (e.g., "string", "int") desc: parameter description required: whether the parameter is required

func DocQueryParamWithDefault added in v0.1.0

func DocQueryParamWithDefault(name, typ, desc string, required bool, defvalue any) RouteOption

DocQueryParamWithDefault adds a query parameter to the route documentation (with default if provided) name: parameter name typ: parameter type (e.g., "string", "int") desc: parameter description required: whether the parameter is required defvalue: default value to use

func DocRequestBody added in v0.0.5

func DocRequestBody(v any) RouteOption

DocRequestBody defines the request body schema for the route v: a Go value whose type will be used to generate the request schema

func DocResponse added in v0.0.4

func DocResponse(statusOrValue any, vOptional ...any) RouteOption

DocResponse registers a response schema for the route's OpenAPI documentation. It can be used in two ways:

  1. DocResponse(status int, value any) - Defines a response schema for the specified HTTP status code (e.g., 200, 201, 400).
  2. DocResponse(value any) - Shorthand for DocResponse(200, value).

Examples:

DocResponse(201, CreatedResponse{})   // response for 201 Created
DocResponse(400, ErrorResponse{})     // response for 400 Bad request
DocResponse(response{})               // response: assumes status 200

func DocResponseHeader added in v0.0.13

func DocResponseHeader(name, typ string, desc ...string) RouteOption

DocResponseHeader adds a response header to the route documentation name: header name typ: header value type (e.g., "string", "int") desc: header description, optional

func DocSummary added in v0.0.4

func DocSummary(summary string) RouteOption

DocSummary sets a short summary description for the route

func DocTag added in v0.0.4

func DocTag(tag string) RouteOption

DocTag adds a single tag to categorize the route

func DocTags added in v0.0.4

func DocTags(tags ...string) RouteOption

DocTags adds multiple tags to categorize the route

func Hide added in v0.1.0

func Hide() RouteOption

Hide marks the route to be excluded from OpenAPI documentation.

func OperationId added in v0.1.0

func OperationId(operationId string) RouteOption

OperationId sets a unique identifier for the operation in the OpenAPI documentation.

func Request added in v0.1.0

func Request(v any) RouteOption

Request registers the request schema for a route. The provided value must be a struct or a pointer to a struct.

This schema is used for both OpenAPI documentation and request validation.

Field mapping rules:

  • Request body: A field named `Body`, or a field tagged with `json:"body"`, is treated as the request body.
  • Path parameters: Fields tagged with `path:"name"` or `param:"name"` are treated as path parameters.
  • Query parameters: Fields tagged with `query:"name"` are treated as query parameters.
  • Headers: Fields tagged with `header:"name"` are treated as HTTP headers.
  • Cookies: Fields tagged with `cookie:"name"` are treated as HTTP cookies.
  • Any remaining fields are treated as general request metadata or ignored if not applicable.

func Response

func Response(v any) RouteOption

Response registers the response schema for a route. The provided value must be a struct or a pointer to a struct.

This schema is used for OpenAPI documentation and response representation.

Field mapping rules:

  • Status code: A field named `Status` is interpreted as the HTTP status code (default: 200 if omitted).
  • Response body: A field named `Body`, or a field tagged with `json:",inline"`, is treated as the response body.
  • Headers: Fields tagged with `header:"name"` are treated as HTTP response headers.
  • Cookies: Fields tagged with `cookie:"name"` are treated as HTTP cookies.
  • Any remaining fields are treated as general response metadata or ignored if not applicable.

Example:

type CreateUserResponse struct {
    Status int 			`json:"status"`
    Body User 			`json:"body"`
    Trace string 		`header:"X-Trace-ID"`
    SessionId string 	`cookie:"session_id"`
}

func Summary added in v0.1.0

func Summary(summary string) RouteOption

Summary sets a short summary description for the route

func Tag added in v0.1.0

func Tag(tag string) RouteOption

Tag adds a single tag to categorize the route

func Tags added in v0.1.0

func Tags(tags ...string) RouteOption

Tags adds multiple tags to categorize the route

func UseMiddleware added in v0.0.15

func UseMiddleware(m ...Middleware) RouteOption

UseMiddleware registers one or more middleware functions to the Route.

func WithIO added in v0.1.0

func WithIO(req any, res any) RouteOption

WithIO registers both request and response schemas for a route in one call. It is a convenience helper that combines Request and Response.

type Router

type Router struct {
	// contains filtered or unexported fields
}

type SchemaInfo added in v0.0.5

type SchemaInfo struct {
	Schema   *openapi3.SchemaRef
	TypeName string
	Package  string
}

SchemaInfo holds additional information about a schema for better naming. It's used when generating OpenAPI schemas from Go types.

type SecurityRequirement added in v0.0.18

type SecurityRequirement map[string][]string // SchemeName -> Scopes

type SecurityScheme added in v0.0.18

type SecurityScheme struct {
	Extensions map[string]any `json:"-" yaml:"-"`
	Origin     *Origin        `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
	Name       string
	// Type string // "http", "oauth2", "apiKey"
	Type string
	// Scheme string // "basic", "bearer", etc.
	Scheme       string
	BearerFormat string
	// In string // "header", "query", "cookie"
	In          string
	Flows       *OAuthFlows
	Description string
}

type SecuritySchemes added in v0.0.18

type SecuritySchemes []SecurityScheme

func (SecuritySchemes) ToOpenAPI added in v0.0.18

func (ss SecuritySchemes) ToOpenAPI() openapi3.SecuritySchemes

type SendFunc added in v0.0.10

type SendFunc func(data any, eventType string) (string, error)

SendFunc defines the signature for a function that sends an SSE message.

type Serializer added in v0.2.1

type Serializer interface {
	Serialize(data any) (string, error)
}

Serializer defines how to convert data to string format

Implement this interface to create custom serializers for SSE messages.

type Server added in v0.0.5

type Server struct {
	Extensions map[string]any `json:"-" yaml:"-"`
	// Server URL (e.g., "https://api.example.com/v1")
	URL string `json:"url" yaml:"url"`
	// Optional server description
	Description string `json:"description,omitempty" yaml:"description,omitempty"`
}

Server represents an API server location where the API is hosted

type Servers added in v0.0.5

type Servers []Server

Servers is a list of Server objects representing API server locations

func (Servers) ToOpenAPI added in v0.0.5

func (s Servers) ToOpenAPI() openapi3.Servers

ToOpenAPI converts Servers to openapi3.Servers. It transforms the custom Servers type to the format expected by the openapi3 package.

type Store added in v0.0.9

type Store struct {
	// contains filtered or unexported fields
}

type StreamOptions added in v0.2.1

type StreamOptions struct {
	// Serializer to use for the stream messages
	Serializer Serializer
	// PingEnabled indicates whether to send periodic ping messages to keep the connection alive.
	PingInterval time.Duration
	// OnError is a callback function to handle errors during streaming.
	OnError func(error)
}

type TestServer added in v0.1.3

type TestServer struct {
	*Okapi
	BaseURL string
	// contains filtered or unexported fields
}

func NewTestServer added in v0.1.3

func NewTestServer(t TestingT) *TestServer

NewTestServer creates and starts a new Okapi test server.

Example:

testServer := okapi.NewTestServer(t)

testServer.Get("/books", GetBooksHandler)

okapitest.GET(t, testServer.BaseURL+"/books").ExpectStatusOK().ExpectBodyContains("The Go Programming Language")

func NewTestServerOn added in v0.1.3

func NewTestServerOn(t TestingT, port int) *TestServer

NewTestServerOn creates and starts a new Okapi test server.

Example:

testServer := okapi.NewTestServerOn(t,80801)

testServer.Get("/books", GetBooksHandler)

okapitest.GET(t, testServer.BaseURL+"/books").ExpectStatusOK().ExpectBodyContains("The Go Programming Language")

type TestingT added in v0.1.3

type TestingT interface {
	Helper()
	Cleanup(func())
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
}

type TextSerializer added in v0.2.1

type TextSerializer struct{}

TextSerializer for plain text/string data

func (TextSerializer) Serialize added in v0.2.1

func (t TextSerializer) Serialize(data any) (string, error)

type ValidationError added in v0.0.5

type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
	Value   any    `json:"value,omitempty"`
}

ValidationError represents validation error details

type ValidationErrorResponse added in v0.0.5

type ValidationErrorResponse struct {
	ErrorResponse
	Errors []ValidationError `json:"errors"`
}

ValidationErrorResponse extends ErrorResponse for validation errors

Directories

Path Synopsis
examples
group command
middleware command
multipart command
sample command
sse command
template command
tests command
tls command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL