{"id":21185261,"url":"https://github.com/stfsy/go-api-kit","last_synced_at":"2025-09-03T13:39:49.591Z","repository":{"id":260947160,"uuid":"882775780","full_name":"stfsy/go-api-kit","owner":"stfsy","description":"API Starter Kit for Golang applications","archived":false,"fork":false,"pushed_at":"2025-08-26T00:27:09.000Z","size":88,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-26T02:37:10.025Z","etag":null,"topics":["api","api-starter","api-starter-kit","go"],"latest_commit_sha":null,"homepage":"","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/stfsy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"zenodo":null}},"created_at":"2024-11-03T18:20:01.000Z","updated_at":"2025-08-26T00:26:58.000Z","dependencies_parsed_at":"2024-11-03T20:19:48.723Z","dependency_job_id":"f6e3b1a6-b383-4ac5-a3a3-bce0e4dc4b91","html_url":"https://github.com/stfsy/go-api-kit","commit_stats":null,"previous_names":["stfsy/go-api-kit"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/stfsy/go-api-kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stfsy%2Fgo-api-kit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stfsy%2Fgo-api-kit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stfsy%2Fgo-api-kit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stfsy%2Fgo-api-kit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stfsy","download_url":"https://codeload.github.com/stfsy/go-api-kit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stfsy%2Fgo-api-kit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273453420,"owners_count":25108470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["api","api-starter","api-starter-kit","go"],"created_at":"2024-11-20T18:15:34.808Z","updated_at":"2025-09-03T13:39:49.560Z","avatar_url":"https://github.com/stfsy.png","language":"Go","readme":"\u003cdiv align=\"center\"\u003e\n\n[![contributions - welcome](https://img.shields.io/badge/contributions-welcome-blue/green)](/CONTRIBUTING.md \"Go to contributions doc\")\n[![GitHub License](https://img.shields.io/github/license/stfsy/go-api-kit.svg)](https://github.com/stfsy/go-api-kit/blob/master/LICENSE)\n\u003cbr/\u003e\n[![Go Report Card](https://goreportcard.com/badge/github.com/stfsy/go-api-kit)](https://goreportcard.com/report/github.com/stfsy/go-api-kit)\n[![Go](https://img.shields.io/github/go-mod/go-version/stfsy/go-api-kit\n)](https://go.dev/ \"Go to golang homepage\")\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n# go-api-kit\nKickstarts your API by providing out-of-the-box implementations for must-have modules and components for a successful API.\n\nProvides a solid foundation for SaaS, Client/Server and API products. It provides out-of-the-box mitigations for the [10 OWASP risks for APIs](https://owasp.org/API-Security/editions/2023/en/0x11-t10/):\n\n\n## 📦 Installation\n\n```bash\ngo get https://github.com/stfsy/go-api-kit\n```\n\n## 🚀 Usage\n### main.go\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/stfsy/go-api-kit/server\"\n)\n\nvar s *server.Server\n\nfunc main() {\n\tstartServerNonBlocking()\n\tstopServerAfterSignal()\n}\n\nfunc stopServerAfterSignal() {\n\tsigChan := make(chan os.Signal, 1)\n\tsignal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)\n\t\u003c-sigChan\n\n\ts.Stop()\n\n\tfmt.Println(\"Graceful shutdown complete.\")\n}\n\nfunc startServerNonBlocking() {\n\ts = server.NewServer(\u0026server.ServerConfig{\n\t\tMuxCallback: func(*http.ServeMux) {\n\t\t\t// add your endpoints and middlewares here\n\t\t},\n\t\tListenCallback: func() {\n\t\t\t// do sth just after listen was called on the server instance and\n\t\t\t// just before the server starts serving requests\n\t\t},\n\t\t// port override is optional but can be used if you want to\n\t\t// define the port manually. If empty the value of env.PORT is used.\n\t\tPortOverride: \"8080\",\n\t})\n\tgo func() {\n\t\terr := s.Start()\n\t\tif err != nil {\n\t\t\tpanic(fmt.Errorf(\"unable to start server %w\", err))\n\t\t}\n\t}()\n}\n```\n\n## Configuration\nThis module will read the following environment variables.\n\n### Env Vars\n- `API_KIT_ENV`: default=production\n- `API_KIT_MAX_BODY_SIZE`: default=10485760 (bytes) = 10 MB\n- `API_KIT_READ_TIMEOUT`: default=10 (seconds)\n- `API_KIT_WRITE_TIMEOUT`: default=10 (seconds)\n- `API_KIT_IDLE_TIMEOUT`: default=620 (seconds)\n### Standard Env Vars\n- `PORT`: default=8080\n\n## Middlewares\nThe module provides several ready-to use middlewares which are compatible with e.g. https://github.com/urfave/negroni.\n\n### Access Log Middleware\nLogs each incoming request to give insights about usage and response times.\n\n```go\nimport (\n\t\"net/http\"\n\t\"github.com/urfave/negroni\"\n\t\"github.com/stfsy/go-api-kit/server/middlewares\"\n)\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"OK\"))\n\t})\n\tn := negroni.New()\n\tn.Use(middlewares.NewAccessLog())\n\tn.UseHandler(mux)\n\thttp.ListenAndServe(\":8080\", n)\n}\n```\n[Source](server/middlewares/access-log.go)\n\n### Content Type Middleware\nValidates the incoming content type, if the request method implies a state change (e.g. POST).\n\n```go\nimport (\n\t\"net/http\"\n\t\"github.com/urfave/negroni\"\n\t\"github.com/stfsy/go-api-kit/server/middlewares\"\n)\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"OK\"))\n\t})\n\tn := negroni.New()\n\tn.Use(middlewares.NewRequireContentTypeMiddleware(\"application/json\"))\n\tn.UseHandler(mux)\n\thttp.ListenAndServe(\":8080\", n)\n}\n```\n[Source](server/middlewares/require-content-type.go)\n\n### Max Body Length Middleware\nLimits the maximum allowed size of the request body.\n\n```go\nimport (\n\t\"net/http\"\n\t\"github.com/urfave/negroni\"\n\t\"github.com/stfsy/go-api-kit/server/middlewares\"\n)\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"OK\"))\n\t})\n\tn := negroni.New()\n\tn.Use(middlewares.NewRequireMaxBodyLengthMiddleware())\n\tn.UseHandler(mux)\n\thttp.ListenAndServe(\":8080\", n)\n}\n```\n[Source](server/middlewares/require-body-length.go)\n\n### Security Headers Middleware\nAdds additional security headers to the response to prevent common attacks and protect users and their data.\n\n```go\nimport (\n\t\"net/http\"\n\t\"github.com/urfave/negroni\"\n\t\"github.com/stfsy/go-api-kit/server/middlewares\"\n)\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"OK\"))\n\t})\n\tn := negroni.New()\n\tn.Use(middlewares.NewRespondWithSecurityHeadersMiddleware())\n\tn.UseHandler(mux)\n\thttp.ListenAndServe(\":8080\", n)\n}\n```\n[Source](server/middlewares/respond-with-security-headers.go)\n\n### Upstream Cache Control Middleware\nInstructs proxy servers between the client and the API to not cache responses.\n\n```go\nimport (\n\t\"net/http\"\n\t\"github.com/urfave/negroni\"\n\t\"github.com/stfsy/go-api-kit/server/middlewares\"\n)\n\nfunc main() {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Write([]byte(\"OK\"))\n\t})\n\tn := negroni.New()\n\tn.Use(middlewares.NewNoCacheHeadersMiddleware())\n\tn.UseHandler(mux)\n\thttp.ListenAndServe(\":8080\", n)\n}\n```\n[Source](server/middlewares/respond-with-no-cache-headers.go)\n\n\n## Functions\n\n### Response Sender Functions\nThese functions help you send plain text or JSON responses easily:\n\n#### SendText\nSends a plain text response.\n\n```go\nimport \"github.com/stfsy/go-api-kit/server/handlers\"\n\nhandlers.SendText(w, \"Hello, world!\")\n```\n[Source](server/handlers/response-sender.go)\n\n\n#### SendJson\nSends a JSON response (sets Content-Type to application/json).\n\n```go\nimport \"github.com/stfsy/go-api-kit/server/handlers\"\n\nhandlers.SendJson(w, []byte(`{\"message\":\"ok\"}`))\n```\n[Source](server/handlers/response-sender.go)\n\n#### SendStructAsJson\nSends a struct as a JSON response (sets Content-Type to application/json). The struct is marshaled to JSON automatically.\n\n```go\nimport \"github.com/stfsy/go-api-kit/server/handlers\"\n\ntype MyResponse struct {\n\tStatus int    `json:\"status\"`\n\tTitle  string `json:\"title\"`\n}\n\nhandlers.SendStructAsJson(w, MyResponse{Status: 200, Title: \"Success\"})\n```\n[Source](server/handlers/response-sender.go)\n\n---\n\n### Response Error Sender Functions\nThese functions send standardized error responses with the correct HTTP status code and a JSON body. Each function takes an `http.ResponseWriter` and an optional `details` map for additional error info. The error response now uses the following structure:\n\n```json\n{\n\t\"status\": 400,\n\t\"title\": \"Bad Request\",\n\t\"details\": {\n\t\t\"zip_code\": {\n\t\t\t\"validator\": \"required\",\n\t\t\t\"message\": \"must not be undefined\",\n\t\t}\n\t}\n}\n```\n\n#### Example usage:\n```go\nimport \"github.com/stfsy/go-api-kit/server/handlers\"\n\n// With details (field-level errors):\nhandlers.SendBadRequest(w, handlers.ErrorDetails{\n\t\"zip_code\": {\n\t\t\"validator\": \"required\",\n\t\t\"message\": \"must not be undefined\",\n\t}\n})\nhandlers.SendUnauthorized(w, handlers.ErrorDetails{\n\t\"x-api-key\": {\n\t\t\"message\": \"must not be null\",\n\t},\n})\n\n// Without details (generic error):\nhandlers.SendInternalServerError(w, nil)\n```\n[Source](server/handlers/response-error-sender.go)\n\n#### Available error response functions:\n\n| Status Code | Title                        | Function                   |\n|-------------|------------------------------|----------------------------|\n| 400         | Bad Request                  | SendBadRequest             |\n| 401         | Unauthorized                 | SendUnauthorized           |\n| 403         | Forbidden                    | SendForbidden              |\n| 404         | Not Found                    | SendNotFound               |\n| 405         | Method Not Allowed           | SendMethodNotAllowed       |\n| 406         | Not Acceptable               | SendNotAcceptable          |\n| 408         | Request Timeout              | SendRequestTimeout         |\n| 409         | Conflict                     | SendConflict               |\n| 410         | Gone                         | SendGone                   |\n| 411         | Length Required              | SendLengthRequired         |\n| 412         | Precondition Failed          | SendPreconditionFailed     |\n| 413         | Payload Too Large            | SendPayloadTooLarge        |\n| 414         | URI Too Long                 | SendURITooLong             |\n| 415         | Unsupported Media Type       | SendUnsupportedMediaType   |\n| 416         | Range Not Satisfiable        | SendRangeNotSatisfiable    |\n| 417         | Expectation Failed           | SendExpectationFailed      |\n| 422         | Unprocessable Entity         | SendUnprocessableEntity    |\n| 429         | Too Many Requests            | SendTooManyRequests        |\n| 500         | Internal Server Error        | SendInternalServerError    |\n| 501         | Not Implemented              | SendNotImplemented         |\n| 502         | Bad Gateway                  | SendBadGateway             |\n| 503         | Service Unavailable          | SendServiceUnavailable     |\n| 504         | Gateway Timeout              | SendGatewayTimeout         |\n| 505         | HTTP Version Not Supported   | SendHTTPVersionNotSupported|\n\n---\n\n### ValidatingHandler (Generic Request Validation)\nWraps your handler to automatically decode and validate JSON request bodies for POST, PUT, and PATCH methods. For other methods, the handler receives nil as the payload.\n\nTo enable JSON payload validation, add https://github.com/go-playground/validator compatible tags to your struct. \n\n#### Usage\n```go\nimport \"github.com/stfsy/go-api-kit/server/handlers\"\n\ntype MyPayload struct {\n    Name string `json:\"name\" validate:\"required\"`\n}\n\nhandlers.ValidatingHandler[MyPayload](func(w http.ResponseWriter, r *http.Request, p *MyPayload) {\n    // Use validated payload\n    w.Write([]byte(p.Name))\n})\n```\n[Source](server/handlers/validating_handler.go)\n\n#### Validation Errors\nValidation errors will be sent to the client automatically with status code `400`. The response will have content type `application/problem+json`. Here's an example:\n\n```json\n{\n\t\"status\": 400,\n\t\"title\": \"Bad Request\",\n\t\"details\": {\n\t\t\"zip_code\": {\n\t\t\t\"validator\": \"required\",\n\t\t\t\"message\": \"must not be undefined\",\n\t\t}\n\t}\n}\n```\n\n\n## 🧪 Running Tests\nTo run tests, run the following command\n\n```bash\n./test.sh\n```\n\n## 📄 License\n[MIT](https://choosealicense.com/licenses/mit/)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstfsy%2Fgo-api-kit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstfsy%2Fgo-api-kit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstfsy%2Fgo-api-kit/lists"}