{"id":18994033,"url":"https://github.com/swaggest/rest-fasthttp","last_synced_at":"2026-05-13T21:35:41.538Z","repository":{"id":74802820,"uuid":"507534984","full_name":"swaggest/rest-fasthttp","owner":"swaggest","description":"Web services with OpenAPI and JSON Schema done quick in Go","archived":false,"fork":false,"pushed_at":"2022-06-27T07:33:50.000Z","size":388,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-31T21:29:36.534Z","etag":null,"topics":["fasthttp","go","json-schema","openapi3","rest-api","swagger"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/swaggest/rest-fasthttp","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swaggest.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-26T09:49:48.000Z","updated_at":"2026-02-11T12:53:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"5cdfef7e-8e64-4fa1-8050-54867cfee838","html_url":"https://github.com/swaggest/rest-fasthttp","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/swaggest/rest-fasthttp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggest%2Frest-fasthttp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggest%2Frest-fasthttp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggest%2Frest-fasthttp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggest%2Frest-fasthttp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swaggest","download_url":"https://codeload.github.com/swaggest/rest-fasthttp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggest%2Frest-fasthttp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33001284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"ssl_error","status_checked_at":"2026-05-13T13:14:51.610Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fasthttp","go","json-schema","openapi3","rest-api","swagger"],"created_at":"2024-11-08T17:23:53.110Z","updated_at":"2026-05-13T21:35:41.520Z","avatar_url":"https://github.com/swaggest.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# REST with Clean Architecture for Go\n\n[![Build Status](https://github.com/swaggest/rest/workflows/test/badge.svg)](https://github.com/swaggest/rest/actions?query=branch%3Amaster+workflow%3Atest)\n[![Coverage Status](https://codecov.io/gh/swaggest/rest/branch/master/graph/badge.svg)](https://codecov.io/gh/swaggest/rest)\n[![GoDevDoc](https://img.shields.io/badge/dev-doc-00ADD8?logo=go)](https://pkg.go.dev/github.com/swaggest/rest)\n[![Time Tracker](https://wakatime.com/badge/github/swaggest/rest.svg)](https://wakatime.com/badge/github/swaggest/rest)\n![Code lines](https://sloc.xyz/github/swaggest/rest/?category=code)\n![Comments](https://sloc.xyz/github/swaggest/rest/?category=comments)\n\nThis module implements HTTP transport level for [`github.com/swaggest/usecase`](https://github.com/swaggest/usecase) \nto build REST services.\n\n## This Fork\n\nThis is a reduced fork of [`github.com/swaggest/rest`](https://github.com/swaggest/rest) \nthat uses [`fasthttp`](https://github.com/valyala/fasthttp) instead of standard `net/http`.\n\n`fasthttp` brings better performance and memory efficiency to highly loaded services, \nbut it is not compatible with many existing middlewares and may require additional \ndev effort for such cases.\n\n## Goals\n\n* Maintain single source of truth for documentation, validation and input/output of HTTP API.\n* Avoid dependency on compile time code generation.\n* Improve productivity and reliability by abstracting HTTP details with simple API for common case.\n* Allow low-level customizations for advanced cases.\n* Maintain reasonable performance with low GC impact.\n\n## Non-Goals\n\n* Support for legacy documentation schemas like Swagger 2.0 or RAML.\n* Zero allocations.\n* Explicit support for XML in request or response bodies.\n\n## Features\n\n* Compatible with `net/http`.\n* Built with [`github.com/go-chi/chi`](https://github.com/go-chi/chi) router.\n* Modular flexible structure.\n* HTTP [request mapping](#request-decoder) into Go value based on field tags.\n* Decoupled business logic with Clean Architecture use cases.\n* Automatic type-safe OpenAPI 3 documentation with [`github.com/swaggest/openapi-go`](https://github.com/swaggest/openapi-go).\n* Single source of truth for the documentation and endpoint interface.\n* Automatic request/response JSON schema validation with [`github.com/santhosh-tekuri/jsonschema`](https://github.com/santhosh-tekuri/jsonschema).\n* Dynamic gzip compression and fast pass through mode.\n* Optimized performance.\n* Embedded [Swagger UI](https://swagger.io/tools/swagger-ui/).\n* Integration test helpers.\n* Generic interface for [use case interactors](https://pkg.go.dev/github.com/swaggest/usecase#NewInteractor). \n\n## Usage\n\nPlease check this [tutorial](https://dev.to/vearutop/tutorial-developing-a-restful-api-with-go-json-schema-validation-and-openapi-docs-2490) for end-to-end usage example.\n\n### Request Decoder\n\nGo struct with optional field tags defines input port. \nRequest decoder populates field values from `http.Request` data before use case interactor is invoked. \n\n```go\n// Declare input port type.\ntype helloInput struct {\n    Locale string `query:\"locale\" default:\"en-US\" pattern:\"^[a-z]{2}-[A-Z]{2}$\" enum:\"ru-RU,en-US\"`\n    Name   string `path:\"name\" minLength:\"3\"` // Field tags define parameter location and JSON schema constraints.\n\n    // Field tags of unnamed fields are applied to parent schema, \n\t// they are optional and can be used to disallow unknown parameters.\n    // For non-body params, name tag must be provided explicitly.\n    // E.g. here no unknown `query` and `cookie` parameters allowed,\n    // unknown `header` params are ok.\n    _ struct{} `query:\"_\" cookie:\"_\" additionalProperties:\"false\"`\n}\n```\n\nInput data can be located in:\n* `path` parameter in request URI, e.g. `/users/{name}`,\n* `query` parameter in request URI, e.g. `/users?locale=en-US`,\n* `formData` parameter in request body with `application/x-www-form-urlencoded` or `multipart/form-data` content,\n* `json` parameter in request body with `application/json` content,\n* `cookie` parameter in request cookie,\n* `header` parameter in request header.\n\nFor more explicit separation of concerns between use case and transport it is possible to provide request mapping \nseparately when initializing handler (please note, such mapping is [not applied](https://github.com/swaggest/rest/issues/61#issuecomment-1059851553) to `json` body).\n\n```go\n// Declare input port type.\ntype helloInput struct {\n    Locale string `default:\"en-US\" pattern:\"^[a-z]{2}-[A-Z]{2}$\"`\n    Name   string `minLength:\"3\"` // Field tags define parameter location and JSON schema constraints.\n}\n```\n\n```go\n// Add use case handler with custom input mapping to router.\nr.Method(http.MethodGet, \"/hello/{name}\", fhttp.NewHandler(u,\n    fhttp.RequestMapping(new(struct {\n       Locale string `query:\"locale\"`\n       Name   string `path:\"name\"` // Field tags define parameter location and JSON schema constraints.\n    })),\n))\n```\n\nAdditional field tags describe JSON schema constraints, please check \n[documentation](https://pkg.go.dev/github.com/swaggest/jsonschema-go#Reflector.Reflect).\n\nMore schema customizations are possible with [`github.com/swaggest/jsonschema-go interfaces`](https://github.com/swaggest/jsonschema-go#implementing-interfaces-on-a-type).\n\nBy default `default` tags are only contributing to documentation, \nif [`request.DecoderFactory.ApplyDefaults`](https://pkg.go.dev/github.com/swaggest/rest/request#DecoderFactory) is \nset to `true`, fields of request structure that don't have explicit value but have `default` will be populated with \ndefault value.\n\nIf input structure implements [`request.Loader`](https://pkg.go.dev/github.com/swaggest/rest/request#Loader),  \nthen `LoadFromHTTPRequest(r *http.Request) error` method will be invoked to populate input structure instead \nof automatic decoding. This allows low level control for cases that need it.\n\n### Response Encoder\n\nGo struct with field tags defines output port.\nResponse encoder writes data from output to `http.ResponseWriter` after use case interactor invocation finishes.\n\n```go\n// Declare output port type.\ntype helloOutput struct {\n    Now     time.Time `header:\"X-Now\" json:\"-\"`\n    Message string    `json:\"message\"`\n}\n```\n\nOutput data can be located in:\n* `json` for response body with `application/json` content,\n* `header` for values in response header.\n\nFor more explicit separation of concerns between use case and transport it is possible to provide response header mapping \nseparately when initializing handler.\n\n```go\n// Declare output port type.\ntype helloOutput struct {\n    Now     time.Time `json:\"-\"`\n    Message string    `json:\"message\"`\n}\n```\n\n```go\n// Add use case handler with custom output headers mapping to router.\nr.Method(http.MethodGet, \"/hello/{name}\", fhttp.NewHandler(u,\n    fhttp.ResponseHeaderMapping(new(struct {\n        Now     time.Time `header:\"X-Now\"`\n    })),\n))\n```\n\nAdditional field tags describe JSON schema constraints, please check \n[documentation](https://pkg.go.dev/github.com/swaggest/jsonschema-go#Reflector.Reflect).\n\n### Creating Use Case Interactor\n\nHTTP transport is decoupled from business logic by adapting\n[use case interactors](https://pkg.go.dev/github.com/swaggest/usecase#Interactor).\n\nUse case interactor can define input and output ports that are used to map data between Go values and transport.\nIt can provide information about itself that will be exposed in generated documentation.\n\n```go\n// Create use case interactor with references to input/output types and interaction function.\nu := usecase.NewIOI(new(helloInput), new(helloOutput), func(ctx context.Context, input, output interface{}) error {\n    var (\n        in  = input.(*helloInput)\n        out = output.(*helloOutput)\n    )\n\n    msg, available := messages[in.Locale]\n    if !available {\n        return status.Wrap(errors.New(\"unknown locale\"), status.InvalidArgument)\n    }\n\n    out.Message = fmt.Sprintf(msg, in.Name)\n    out.Now = time.Now()\n\n    return nil\n})\n```\n\nFor modularity particular use case interactor instance can be assembled by embedding relevant traits in a struct,\nfor example you can skip adding `usecase.WithInput` if your use case does not imply any input.\n\n```go\n// Create use case interactor.\nu := struct {\n    usecase.Info\n    usecase.Interactor\n    usecase.WithInput\n    usecase.WithOutput\n}{}\n\n// Describe use case interactor.\nu.SetTitle(\"Greeter\")\nu.SetDescription(\"Greeter greets you.\")\nu.Input = new(helloInput)\nu.Output = new(helloOutput)\nu.Interactor = usecase.Interact(func(ctx context.Context, input, output interface{}) error {\n    // Do something about input to prepare output.\n    return nil\n})\n```\n\n### Initializing Web Service\n\n[Web Service](https://pkg.go.dev/github.com/swaggest/rest/web#DefaultService) is an instrumented facade in front of \nrouter, it simplifies configuration and provides more compact API to add use cases.\n\n```go\n// Service initializes router with required middlewares.\nservice := web.DefaultService()\n\n// It allows OpenAPI configuration.\nservice.OpenAPI.Info.Title = \"Albums API\"\nservice.OpenAPI.Info.WithDescription(\"This service provides API to manage albums.\")\nservice.OpenAPI.Info.Version = \"v1.0.0\"\n\n// Additional middlewares can be added.\nservice.Use(\n    middleware.StripSlashes,\n)\n\n// Use cases can be mounted using short syntax .\u003cMethod\u003e(...).\nservice.Post(\"/albums\", postAlbums(), fhttp.SuccessStatus(http.StatusCreated))\n\nlog.Println(\"Starting service at http://localhost:8080\")\n\nif err := http.ListenAndServe(\"localhost:8080\", service); err != nil {\n    log.Fatal(err)\n}\n\n```\n\nUsually, `web.Service` API is sufficient, but if it is not, router can be configured manually, please check \nthe documentation below.\n\n### Adding use case to router\n\n```go\n// Add use case handler to router.\nr.Method(http.MethodGet, \"/hello/{name}\", fhttp.NewHandler(u))\n```\n\n## API Schema Collector\n\nOpenAPI schema should be initialized with general information about REST API.\n\nIt uses [type-safe mapping](https://github.com/swaggest/openapi-go) for the configuration, \nso any IDE will help with available fields. \n\n```go\n// Init API documentation schema.\napiSchema := \u0026openapi.Collector{}\napiSchema.Reflector().SpecEns().Info.Title = \"Basic Example\"\napiSchema.Reflector().SpecEns().Info.WithDescription(\"This app showcases a trivial REST API.\")\napiSchema.Reflector().SpecEns().Info.Version = \"v1.2.3\"\n```\n\n## Router Setup\n\nREST router is based on [`github.com/go-chi/chi`](https://github.com/go-chi/chi), wrapper allows unwrapping instrumented\nhandler in middleware.\n\nThese middlewares are required:\n* `nethttp.OpenAPIMiddleware(apiSchema)`, \n* `request.DecoderMiddleware(decoderFactory)`,\n* `response.EncoderMiddleware`.\n\nOptionally you can add more middlewares with some performance impact:\n* `request.ValidatorMiddleware(validatorFactory)` (request validation, recommended)\n* `response.ValidatorMiddleware(validatorFactory)`\n* `gzip.Middleware`\n\nYou can also add any other 3rd party middlewares compatible with `net/http` at your discretion.\n\n```go\n// Setup request decoder and validator.\nvalidatorFactory := jsonschema.NewFactory(apiSchema, apiSchema)\ndecoderFactory := request.NewDecoderFactory()\ndecoderFactory.SetDecoderFunc(rest.ParamInPath, chirouter.PathToURLValues)\n\n// Create router.\nr := chirouter.NewWrapper(fchi.NewRouter())\n\n// Setup middlewares.\nr.Use(\n    middleware.Recoverer,                          // Panic recovery.\n    nethttp.OpenAPIMiddleware(apiSchema),          // Documentation collector.\n    request.DecoderMiddleware(decoderFactory),     // Request decoder setup.\n    request.ValidatorMiddleware(validatorFactory), // Request validator setup.\n    response.EncoderMiddleware,                    // Response encoder setup.\n    gzip.Middleware,                               // Response compression with support for direct gzip pass through.\n)\n```\n\nRegister Swagger UI to serve documentation at `/docs`.\n\n```go\n// Swagger UI endpoint at /docs.\nr.Method(http.MethodGet, \"/docs/openapi.json\", apiSchema)\nr.Mount(\"/docs\", v3cdn.NewHandler(apiSchema.Reflector().Spec.Info.Title,\n    \"/docs/openapi.json\", \"/docs\"))\n```\n\n## Security Setup\n\n```go\n// Prepare middleware with suitable security schema.\n// It will perform actual security check for every relevant request.\nadminAuth := middleware.BasicAuth(\"Admin Access\", map[string]string{\"admin\": \"admin\"})\n\n// Prepare API schema updater middleware.\n// It will annotate handler documentation with security schema.\nadminSecuritySchema := nethttp.HTTPBasicSecurityMiddleware(apiSchema, \"Admin\", \"Admin access\")\n\n// Endpoints with admin access.\nr.Route(\"/admin\", func(r fchi.Router) {\n    r.Group(func(r fchi.Router) {\n        r.Wrap(adminAuth, adminSecuritySchema) // Add both middlewares to routing group to enforce and document security.\n        r.Method(http.MethodPut, \"/hello/{name}\", fhttp.NewHandler(u))\n    })\n})\n```\n\nSee [example](./_examples/task-api/internal/infra/nethttp/router.go).\n\n## Handler Setup\n\nHandler is a generalized adapter for use case interactor, so usually setup is trivial.\n\n```go\n// Add use case handler to router.\nr.Method(http.MethodGet, \"/hello/{name}\", fhttp.NewHandler(u))\n```\n\n## Example\n\nFor non-generic use case, see another [example](./_examples/basic/main.go).\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/swaggest/fchi\"\n\t\"github.com/swaggest/rest-fasthttp/response/gzip\"\n\t\"github.com/swaggest/rest-fasthttp/web\"\n\tswgui \"github.com/swaggest/swgui/v4emb\"\n\t\"github.com/swaggest/usecase\"\n\t\"github.com/swaggest/usecase/status\"\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc main() {\n\ts := web.DefaultService()\n\n\t// Init API documentation schema.\n\ts.OpenAPI.Info.Title = \"Basic Example\"\n\ts.OpenAPI.Info.WithDescription(\"This app showcases a trivial REST API.\")\n\ts.OpenAPI.Info.Version = \"v1.2.3\"\n\n\t// Setup middlewares.\n\ts.Wrap(\n\t\tgzip.Middleware, // Response compression with support for direct gzip pass through.\n\t)\n\n\t// Declare input port type.\n\ttype helloInput struct {\n\t\tLocale string `query:\"locale\" default:\"en-US\" pattern:\"^[a-z]{2}-[A-Z]{2}$\" enum:\"ru-RU,en-US\"`\n\t\tName   string `path:\"name\" minLength:\"3\"` // Field tags define parameter location and JSON schema constraints.\n\n\t\t// Field tags of unnamed fields are applied to parent schema.\n\t\t// they are optional and can be used to disallow unknown parameters.\n\t\t// For non-body params, name tag must be provided explicitly.\n\t\t// E.g. here no unknown `query` and `cookie` parameters allowed,\n\t\t// unknown `header` params are ok.\n\t\t_ struct{} `query:\"_\" cookie:\"_\" additionalProperties:\"false\"`\n\t}\n\n\t// Declare output port type.\n\ttype helloOutput struct {\n\t\tNow     time.Time `header:\"X-Now\" json:\"-\"`\n\t\tMessage string    `json:\"message\"`\n\t}\n\n\tmessages := map[string]string{\n\t\t\"en-US\": \"Hello, %s!\",\n\t\t\"ru-RU\": \"Привет, %s!\",\n\t}\n\n\t// Create use case interactor with references to input/output types and interaction function.\n\tu := usecase.NewInteractor(func(ctx context.Context, input helloInput, output *helloOutput) error {\n\t\tmsg, available := messages[input.Locale]\n\t\tif !available {\n\t\t\treturn status.Wrap(errors.New(\"unknown locale\"), status.InvalidArgument)\n\t\t}\n\n\t\toutput.Message = fmt.Sprintf(msg, input.Name)\n\t\toutput.Now = time.Now()\n\n\t\treturn nil\n\t})\n\n\t// Describe use case interactor.\n\tu.SetTitle(\"Greeter\")\n\tu.SetDescription(\"Greeter greets you.\")\n\n\tu.SetExpectedErrors(status.InvalidArgument)\n\n\t// Add use case handler to router.\n\ts.Get(\"/hello/{name}\", u)\n\n\t// Swagger UI endpoint at /docs.\n\ts.Docs(\"/docs\", swgui.New)\n\n\t// Start server.\n\tlog.Println(\"http://localhost:8011/docs\")\n\tif err := fasthttp.ListenAndServe(\":8011\", fchi.RequestHandler(s)); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n![Documentation Page](./_examples/basic/screen.png)\n\n## Versioning\n\nThis project adheres to [Semantic Versioning](https://semver.org/#semantic-versioning-200).\n\nBefore version `1.0.0`, breaking changes are tagged with `MINOR` bump, features and fixes are tagged with `PATCH` bump.\nAfter version `1.0.0`, breaking changes are tagged with `MAJOR` bump.\n\nBreaking changes are described in [UPGRADE.md](./UPGRADE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswaggest%2Frest-fasthttp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswaggest%2Frest-fasthttp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswaggest%2Frest-fasthttp/lists"}