shiftapi

package module
v0.0.25 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 17 Imported by: 0

README

ShiftAPI Logo

End-to-end type safety from Go structs to TypeScript frontend.

ShiftAPI is a Go framework that generates an OpenAPI 3.1 spec from your handler types at runtime, then uses a Vite or Next.js plugin to turn that spec into a fully-typed TypeScript client — so your frontend stays in sync with your API automatically.

Go Reference GolangCI Go Report Card npm shiftapi

Go structs ──→ OpenAPI 3.1 spec ──→ TypeScript types ──→ Typed fetch client
   (compile time)     (runtime)         (build time)        (your frontend)

Getting Started

Scaffold a full-stack app (Go + React, Svelte, or Next.js):

npm create shiftapi@latest

Or add ShiftAPI to an existing Go project:

go get github.com/fcjr/shiftapi

Quick Start

package main

import (
    "log"
    "net/http"

    "github.com/fcjr/shiftapi"
)

type Person struct {
    Name string `json:"name" validate:"required"`
}

type Greeting struct {
    Hello string `json:"hello"`
}

func greet(r *http.Request, in *Person) (*Greeting, error) {
    return &Greeting{Hello: in.Name}, nil
}

func main() {
    api := shiftapi.New(shiftapi.WithInfo(shiftapi.Info{
        Title:   "Greeter API",
        Version: "1.0.0",
    }))

    shiftapi.Post(api, "/greet", greet)

    log.Println("listening on :8080")
    log.Fatal(shiftapi.ListenAndServe(":8080", api))
    // interactive docs at http://localhost:8080/docs
}

That's it. ShiftAPI reflects your Go types into an OpenAPI 3.1 spec at /openapi.json and serves interactive docs at /docs — no code generation step, no annotations.

Features

Generic type-safe handlers

Generic free functions capture your request and response types at compile time. Every method uses a single function — struct tags discriminate query params (query:"..."), body fields (json:"..."), and form fields (form:"..."). For routes without input, use _ struct{}.

// POST with body — input is decoded and passed as *CreateUser
shiftapi.Post(api, "/users", func(r *http.Request, in *CreateUser) (*User, error) {
    return db.CreateUser(r.Context(), in)
}, shiftapi.WithStatus(http.StatusCreated))

// GET without input — use _ struct{}
shiftapi.Get(api, "/users/{id}", func(r *http.Request, _ struct{}) (*User, error) {
    return db.GetUser(r.Context(), r.PathValue("id"))
})

Typed query parameters

Define a struct with query tags. Query params are parsed, validated, and documented in the OpenAPI spec automatically.

type SearchQuery struct {
    Q     string `query:"q"     validate:"required"`
    Page  int    `query:"page"  validate:"min=1"`
    Limit int    `query:"limit" validate:"min=1,max=100"`
}

shiftapi.Get(api, "/search", func(r *http.Request, in SearchQuery) (*Results, error) {
    return doSearch(in.Q, in.Page, in.Limit), nil
})

Supports string, bool, int*, uint*, float* scalars, *T pointers for optional params, and []T slices for repeated params (e.g. ?tag=a&tag=b). Parse errors return 400; validation failures return 422.

For handlers that need both query parameters and a request body, combine them in a single struct — fields with query tags become query params, fields with json tags become the body:

type CreateInput struct {
    DryRun bool   `query:"dry_run"`
    Name   string `json:"name"`
}

shiftapi.Post(api, "/items", func(r *http.Request, in CreateInput) (*Result, error) {
    return createItem(in.Name, in.DryRun), nil
})

File uploads (multipart/form-data)

Use form tags to declare file upload endpoints. The form tag drives OpenAPI spec generation — the generated TypeScript client gets the correct multipart/form-data types automatically. At runtime, the request body is parsed via ParseMultipartForm and form-tagged fields are populated.

type UploadInput struct {
    File  *multipart.FileHeader   `form:"file" validate:"required"`
    Title string                  `form:"title" validate:"required"`
    Tags  string                  `query:"tags"`
}

shiftapi.Post(api, "/upload", func(r *http.Request, in UploadInput) (*Result, error) {
    f, err := in.File.Open()
    if err != nil {
        return nil, shiftapi.Error(http.StatusBadRequest, "failed to open file")
    }
    defer f.Close()
    // read from f, save to disk/S3/etc.
    return &Result{Filename: in.File.Filename, Title: in.Title}, nil
})
  • *multipart.FileHeader — single file (type: string, format: binary in OpenAPI, File | Blob | Uint8Array in TypeScript)
  • []*multipart.FileHeader — multiple files (type: array, items: {type: string, format: binary})
  • Scalar types with form tag — text form fields
  • query tags work alongside form tags
  • Mixing json and form tags on the same struct panics at registration time

Restrict accepted file types with the accept tag. This validates the Content-Type at runtime (returns 400 if rejected) and documents the constraint in the OpenAPI spec via the encoding map:

type ImageUpload struct {
    Avatar *multipart.FileHeader `form:"avatar" accept:"image/png,image/jpeg" validate:"required"`
}

The default max upload size is 32 MB. Configure it with WithMaxUploadSize:

api := shiftapi.New(shiftapi.WithMaxUploadSize(64 << 20)) // 64 MB

Validation

Built-in validation via go-playground/validator. Struct tags are enforced at runtime and reflected into the OpenAPI schema.

type CreateUser struct {
    Name  string `json:"name"  validate:"required,min=2,max=50"`
    Email string `json:"email" validate:"required,email"`
    Age   int    `json:"age"   validate:"gte=0,lte=150"`
    Role  string `json:"role"  validate:"oneof=admin user guest"`
}

Invalid requests return 422 with per-field errors:

{
    "message": "validation failed",
    "errors": [
        { "field": "Name",  "message": "this field is required" },
        { "field": "Email", "message": "must be a valid email address" }
    ]
}

Supported tags: required, email, url/uri, uuid, datetime, min, max, gte, lte, gt, lt, len, oneof — all mapped to their OpenAPI equivalents (format, minimum, maxLength, enum, etc.). Use WithValidator() to supply a custom validator instance.

Error handling

Return shiftapi.Error to control the status code:

return nil, shiftapi.Error(http.StatusNotFound, "user not found")

Any non-APIError returns 500 Internal Server Error.

Route metadata

Add OpenAPI summaries, descriptions, and tags per route:

shiftapi.Post(api, "/greet", greet,
    shiftapi.WithRouteInfo(shiftapi.RouteInfo{
        Summary:     "Greet a person",
        Description: "Returns a personalized greeting.",
        Tags:        []string{"greetings"},
    }),
)

Standard http.Handler

API implements http.Handler, so it works with any middleware, httptest, and ServeMux mounting:

// middleware
wrapped := loggingMiddleware(corsMiddleware(api))
http.ListenAndServe(":8080", wrapped)

// mount under a prefix
mux := http.NewServeMux()
mux.Handle("/api/v1/", http.StripPrefix("/api/v1", api))

TypeScript Integration

ShiftAPI ships npm packages for the frontend:

  • shiftapi — CLI and codegen core. Extracts the OpenAPI spec from your Go server, generates TypeScript types via openapi-typescript, and writes a pre-configured openapi-fetch client.
  • @shiftapi/vite-plugin — Vite plugin for dev-time HMR, proxy, and Go server management.
  • @shiftapi/next — Next.js integration with the same DX (webpack/Turbopack aliases, rewrites proxy, Go server management).

shiftapi.config.ts (project root):

import { defineConfig } from "shiftapi";

export default defineConfig({
    server: "./cmd/server", // Go entry point
});

Vite

npm install shiftapi @shiftapi/vite-plugin
// vite.config.ts
import shiftapi from "@shiftapi/vite-plugin";
import { defineConfig } from "vite";

export default defineConfig({
    plugins: [shiftapi()],
});

Next.js

npm install shiftapi @shiftapi/next
// next.config.ts
import type { NextConfig } from "next";
import { withShiftAPI } from "@shiftapi/next";

const nextConfig: NextConfig = {};

export default withShiftAPI(nextConfig);

Use the typed client

import { client } from "@shiftapi/client";

const { data } = await client.GET("/health");
// data: { ok?: boolean }

const { data: greeting } = await client.POST("/greet", {
    body: { name: "frank" },
});
// body and response are fully typed from your Go structs

const { data: results } = await client.GET("/search", {
    params: { query: { q: "hello", page: 1, limit: 10 } },
});
// query params are fully typed too — { q: string, page?: number, limit?: number }

const { data: upload } = await client.POST("/upload", {
    body: { file: new File(["content"], "doc.txt"), title: "My Doc" },
    params: { query: { tags: "important" } },
});
// file uploads are typed as File | Blob | Uint8Array — generated from format: binary in the spec

In dev mode the plugins start the Go server, proxy API requests, watch .go files, and regenerate types on changes.

CLI usage (without Vite/Next.js):

shiftapi prepare

This extracts the spec and generates .shiftapi/client.d.ts and .shiftapi/client.js. Useful in postinstall scripts or CI.

Config options:

Option Default Description
server (required) Go entry point (e.g. "./cmd/server")
baseUrl "/" Fallback base URL for the API client
url "http://localhost:8080" Go server address for dev proxy

For production, set VITE_SHIFTAPI_BASE_URL (Vite) or NEXT_PUBLIC_SHIFTAPI_BASE_URL (Next.js) to point at your API host. The plugins automatically update tsconfig.json with the required path mapping for IDE autocomplete.

Development

This is a pnpm + Turborepo monorepo.

pnpm install    # install dependencies
pnpm build      # build all packages
pnpm dev        # start example Vite + Go app
pnpm test       # run all tests

Go tests can also be run directly:

go test -count=1 -tags shiftapidev ./...

Documentation

Overview

Package shiftapi provides end-to-end type safety from Go to TypeScript.

Define your API with typed Go handler functions and shiftapi automatically generates an OpenAPI 3.1 spec, validates requests, and produces a fully-typed TypeScript client — all from a single source of truth.

Quick start

api := shiftapi.New()
shiftapi.Post(api, "/greet", greet)
shiftapi.ListenAndServe(":8080", api)

where greet is a typed handler:

type GreetRequest struct {
    Name string `json:"name" validate:"required"`
}

type GreetResponse struct {
    Hello string `json:"hello"`
}

func greet(r *http.Request, in *GreetRequest) (*GreetResponse, error) {
    return &GreetResponse{Hello: in.Name}, nil
}

Struct tag conventions

ShiftAPI discriminates input struct fields by their struct tags:

  • json:"name" — parsed from the JSON request body (default for POST/PUT/PATCH)
  • query:"name" — parsed from URL query parameters
  • form:"name" — parsed from multipart/form-data (for file uploads)
  • validate:"rules" — validated using github.com/go-playground/validator/v10 rules and reflected into the OpenAPI schema
  • accept:"mime/type" — constrains accepted MIME types on form file fields

A single input struct can mix query and body fields:

type SearchRequest struct {
    Q     string `query:"q" validate:"required"`
    Page  int    `query:"page"`
    Body  Filter `json:"filter"`
}

File uploads

Use *multipart.FileHeader fields with the form tag for file uploads:

type UploadInput struct {
    File *multipart.FileHeader   `form:"file" validate:"required"`
    Docs []*multipart.FileHeader `form:"docs"`
}

Error handling

Return an *APIError from a handler to control the HTTP status code:

return nil, shiftapi.Error(http.StatusNotFound, "user not found")

Validation failures automatically return 422 with structured ValidationError responses.

Built-in endpoints

Every API automatically serves:

  • GET /openapi.json — the generated OpenAPI 3.1 spec
  • GET /docs — interactive API documentation (Scalar UI)

http.Handler compatibility

API implements http.Handler, so it works with any standard middleware, router, or test framework:

mux := http.NewServeMux()
mux.Handle("/api/", http.StripPrefix("/api", api))
Example
package main

import (
	"log"
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New(shiftapi.WithInfo(shiftapi.Info{
		Title:   "My API",
		Version: "1.0.0",
	}))

	type HelloRequest struct {
		Name string `json:"name" validate:"required"`
	}
	type HelloResponse struct {
		Message string `json:"message"`
	}

	shiftapi.Post(api, "/hello", func(r *http.Request, in HelloRequest) (*HelloResponse, error) {
		return &HelloResponse{Message: "Hello, " + in.Name + "!"}, nil
	})

	log.Fatal(shiftapi.ListenAndServe(":8080", api))
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Connect

func Connect[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Connect registers a CONNECT handler.

func Delete

func Delete[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Delete registers a DELETE handler.

func Get

func Get[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Get registers a handler for GET requests at the given path. The path follows net/http.ServeMux patterns, including wildcards like /users/{id}. Path parameters are accessible via http.Request.PathValue.

Example
package main

import (
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type UserQuery struct {
		ID int `query:"id" validate:"required"`
	}
	type User struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	}

	shiftapi.Get(api, "/user", func(r *http.Request, in UserQuery) (*User, error) {
		return &User{ID: in.ID, Name: "Alice"}, nil
	})
}
Example (PathParameter)
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type User struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	}

	shiftapi.Get(api, "/users/{id}", func(r *http.Request, _ struct{}) (*User, error) {
		id := r.PathValue("id")
		return &User{ID: id, Name: "Alice"}, nil
	})

	// Make a request to verify.
	w := httptest.NewRecorder()
	r := httptest.NewRequest("GET", "/users/42", nil)
	api.ServeHTTP(w, r)
	fmt.Println(w.Body.String())
}
Output:
{"id":"42","name":"Alice"}
func Head[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Head registers a HEAD handler.

func ListenAndServe

func ListenAndServe(addr string, api *API) error

ListenAndServe starts the HTTP server on the given address.

In production builds this is a direct call to http.ListenAndServe with zero additional overhead.

When built with -tags shiftapidev (used automatically by the Vite plugin), the following environment variables are supported:

  • SHIFTAPI_EXPORT_SPEC=<path>: write the OpenAPI spec to the given file and exit without starting the server.
  • SHIFTAPI_PORT=<port>: override the port in addr, allowing the Vite plugin to automatically assign a free port.

func Options

func Options[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Options registers an OPTIONS handler.

func Patch

func Patch[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Patch registers a PATCH handler.

func Post

func Post[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Post registers a handler for POST requests at the given path. The request body is automatically decoded from JSON (or multipart/form-data if the In type has form-tagged fields). Validation is applied before the handler runs.

Example
package main

import (
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type CreateInput struct {
		Name  string `json:"name" validate:"required"`
		Email string `json:"email" validate:"required,email"`
	}
	type CreateOutput struct {
		ID int `json:"id"`
	}

	shiftapi.Post(api, "/users", func(r *http.Request, in CreateInput) (*CreateOutput, error) {
		return &CreateOutput{ID: 1}, nil
	}, shiftapi.WithStatus(http.StatusCreated))
}
Example (FileUpload)
package main

import (
	"mime/multipart"
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type UploadInput struct {
		File *multipart.FileHeader `form:"file" validate:"required"`
	}
	type UploadResult struct {
		Filename string `json:"filename"`
		Size     int64  `json:"size"`
	}

	shiftapi.Post(api, "/upload", func(r *http.Request, in UploadInput) (*UploadResult, error) {
		return &UploadResult{
			Filename: in.File.Filename,
			Size:     in.File.Size,
		}, nil
	})
}
Example (QueryAndBody)
package main

import (
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type Request struct {
		Version string `query:"v"`
		Name    string `json:"name"`
	}
	type Response struct {
		Result string `json:"result"`
	}

	shiftapi.Post(api, "/action", func(r *http.Request, in Request) (*Response, error) {
		return &Response{Result: in.Name + " (v" + in.Version + ")"}, nil
	})
	_ = api
}

func Put

func Put[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Put registers a PUT handler.

func Trace

func Trace[In, Resp any](api *API, path string, fn HandlerFunc[In, Resp], options ...RouteOption)

Trace registers a TRACE handler.

Types

type API

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

API is the central type that collects typed handler registrations, generates an OpenAPI 3.1 schema, and implements http.Handler. Create one with New and register routes with Get, Post, Put, Patch, Delete, etc.

API automatically serves the OpenAPI spec at GET /openapi.json and interactive documentation at GET /docs.

func New

func New(options ...Option) *API

New creates a new API with the given options. By default the API uses a 32 MB upload limit and the standard github.com/go-playground/validator/v10 instance. Use WithInfo, WithMaxUploadSize, WithValidator, and WithExternalDocs to customize behavior.

Example
package main

import (
	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New(
		shiftapi.WithInfo(shiftapi.Info{
			Title:       "Pet Store",
			Version:     "2.0.0",
			Description: "A sample pet store API",
		}),
		shiftapi.WithMaxUploadSize(10<<20), // 10 MB
	)
	_ = api
}

func (*API) ServeHTTP

func (a *API) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	shiftapi.Get(api, "/ping", func(r *http.Request, _ struct{}) (*struct {
		Pong bool `json:"pong"`
	}, error) {
		return &struct {
			Pong bool `json:"pong"`
		}{Pong: true}, nil
	})

	// Use as http.Handler in tests.
	w := httptest.NewRecorder()
	r := httptest.NewRequest("GET", "/ping", nil)
	api.ServeHTTP(w, r)
	fmt.Println(w.Body.String())
}
Output:
{"pong":true}

type APIError

type APIError struct {
	Status  int    `json:"-"`
	Message string `json:"message"`
}

APIError is an error with an HTTP status code. Return it from handlers to control the response status code and message. Unrecognized errors (i.e. errors that are not *APIError or *ValidationError) are mapped to 500 Internal Server Error to prevent leaking implementation details.

func Error

func Error(status int, message string) *APIError

Error creates a new APIError with the given HTTP status code and message.

return nil, shiftapi.Error(http.StatusNotFound, "user not found")
Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type Empty struct{}

	shiftapi.Get(api, "/secret", func(r *http.Request, _ struct{}) (*Empty, error) {
		token := r.Header.Get("Authorization")
		if token == "" {
			return nil, shiftapi.Error(http.StatusUnauthorized, "missing auth token")
		}
		return &Empty{}, nil
	})

	// Make a request without auth to verify.
	w := httptest.NewRecorder()
	r := httptest.NewRequest("GET", "/secret", nil)
	api.ServeHTTP(w, r)
	fmt.Println(w.Code)
	fmt.Println(w.Body.String())
}
Output:
401
{"message":"missing auth token"}

func (*APIError) Error

func (e *APIError) Error() string

type Contact

type Contact struct {
	Name  string
	URL   string
	Email string
}

Contact describes the API contact information.

type ExternalDocs

type ExternalDocs struct {
	Description string
	URL         string
}

ExternalDocs links to external documentation.

type FieldError

type FieldError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

FieldError describes a single field validation failure.

type HandlerFunc

type HandlerFunc[In, Resp any] func(r *http.Request, in In) (Resp, error)

HandlerFunc is a typed handler function for API routes. The type parameters In and Resp are the request and response types — both are automatically reflected into the OpenAPI schema.

The In struct's fields are discriminated by struct tags:

  • query:"name" — parsed from URL query parameters
  • json:"name" — parsed from the JSON request body (default for POST/PUT/PATCH)
  • form:"name" — parsed from multipart/form-data (for file uploads)

Use struct{} as In for routes that take no input, or as Resp for routes that return no body (e.g. health checks that only need a status code).

The *http.Request parameter gives access to headers, cookies, path parameters, and other request metadata.

type Info

type Info struct {
	Title          string
	Description    string
	TermsOfService string
	Contact        *Contact
	License        *License
	Version        string
}

Info describes the API and is rendered into the OpenAPI spec's info object.

type License

type License struct {
	Name string
	URL  string
}

License describes the API license.

type Option

type Option func(*API)

Option configures an API created with New.

func WithExternalDocs

func WithExternalDocs(docs ExternalDocs) Option

WithExternalDocs links to external documentation.

func WithInfo

func WithInfo(info Info) Option

WithInfo configures the API metadata that appears in the OpenAPI spec and documentation UI.

api := shiftapi.New(shiftapi.WithInfo(shiftapi.Info{
    Title:   "My API",
    Version: "1.0.0",
}))

func WithMaxUploadSize added in v0.0.24

func WithMaxUploadSize(size int64) Option

WithMaxUploadSize sets the maximum memory used for parsing multipart form data. The default is 32 MB.

func WithValidator

func WithValidator(v *validator.Validate) Option

WithValidator sets a custom github.com/go-playground/validator/v10 instance on the API. Use this to register custom validations or override default behavior.

type RouteInfo

type RouteInfo struct {
	Summary     string
	Description string
	Tags        []string
}

RouteInfo provides metadata for a route that appears in the OpenAPI spec and the generated documentation UI.

type RouteOption

type RouteOption func(*routeConfig)

RouteOption configures a route.

func WithRouteInfo

func WithRouteInfo(info RouteInfo) RouteOption

WithRouteInfo sets the route's OpenAPI metadata (summary, description, tags).

shiftapi.Post(api, "/greet", greet, shiftapi.WithRouteInfo(shiftapi.RouteInfo{
    Summary: "Greet a person",
    Tags:    []string{"greetings"},
}))
Example
package main

import (
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	shiftapi.Get(api, "/health", func(r *http.Request, _ struct{}) (*struct {
		OK bool `json:"ok"`
	}, error) {
		return &struct {
			OK bool `json:"ok"`
		}{OK: true}, nil
	}, shiftapi.WithRouteInfo(shiftapi.RouteInfo{
		Summary:     "Health check",
		Description: "Returns the health status of the service.",
		Tags:        []string{"monitoring"},
	}))
}

func WithStatus

func WithStatus(status int) RouteOption

WithStatus sets the success HTTP status code for the route (default: 200). Use this for routes that should return 201 Created, 204 No Content, etc.

Example
package main

import (
	"net/http"

	"github.com/fcjr/shiftapi"
)

func main() {
	api := shiftapi.New()

	type Item struct {
		Name string `json:"name"`
	}
	type Created struct {
		ID int `json:"id"`
	}

	shiftapi.Post(api, "/items", func(r *http.Request, in Item) (*Created, error) {
		return &Created{ID: 1}, nil
	}, shiftapi.WithStatus(http.StatusCreated))

	_ = api
}

type ValidationError

type ValidationError struct {
	Message string       `json:"message"`
	Errors  []FieldError `json:"errors"`
}

ValidationError is returned when request validation fails. It is serialized as a 422 Unprocessable Entity response with a structured list of per-field errors. Validation rules are specified using validate struct tags from github.com/go-playground/validator/v10 and are also reflected into the generated OpenAPI schema.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis
examples
greeter command

Jump to

Keyboard shortcuts

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