{"id":37106225,"url":"https://github.com/ehsoc/rest","last_synced_at":"2026-01-14T12:48:05.325Z","repository":{"id":57559854,"uuid":"290048680","full_name":"ehsoc/rest","owner":"ehsoc","description":"experimental web resource abstraction for composing REST APIs in Go (Golang).","archived":false,"fork":false,"pushed_at":"2020-12-19T23:37:34.000Z","size":580,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-06-20T10:22:47.573Z","etag":null,"topics":["api","go","golang","openapi2","rest","swagger","web"],"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/ehsoc.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":"security.go","support":null}},"created_at":"2020-08-24T21:57:56.000Z","updated_at":"2020-12-20T02:54:20.000Z","dependencies_parsed_at":"2022-08-27T10:51:30.966Z","dependency_job_id":null,"html_url":"https://github.com/ehsoc/rest","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/ehsoc/rest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehsoc%2Frest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehsoc%2Frest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehsoc%2Frest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehsoc%2Frest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ehsoc","download_url":"https://codeload.github.com/ehsoc/rest/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ehsoc%2Frest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28420814,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:47:48.104Z","status":"ssl_error","status_checked_at":"2026-01-14T10:46:19.031Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["api","go","golang","openapi2","rest","swagger","web"],"created_at":"2026-01-14T12:48:04.503Z","updated_at":"2026-01-14T12:48:05.308Z","avatar_url":"https://github.com/ehsoc.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rest\nRest is an experimental web resource abstraction for composing REST APIs in Go (Golang).\n\n- **Rapid prototyping**.\n- **Web Server generation (http.Handler)**\n- **REST API Specification generation (OpenAPI v2)**\n\n## Base components:\n- **API**: It's the root that contains resources and server information. Also, it generates the server handler and the API specification.\n- **Resource**: Each resource is a node in a URL path, and contains methods and other resources.\n\n**Code example:**\n\n```go\napi := rest.NewAPI(\"/api/v1\", \"localhost\", \"My simple car API\", \"v1\")\n\napi.Resource(\"car\", func(r *rest.Resource) {\n\tr.Resource(\"findMatch\", func(r *rest.Resource) {\n\t})\n\tcarID := rest.NewURIParameter(\"carID\", reflect.String)\n\tr.ResourceP(carID, func(r *rest.Resource) {\n\t})\n})\n\napi.Resource(\"ping\", func(r *rest.Resource) {\n})\n\napi.Resource(\"user\", func(r *rest.Resource) {\n\tr.Resource(\"signOut\", func(r *rest.Resource) {\n\t})\n})\n\t\n```\n\n**Diagram of the above code:**\n\n```\n                                     +-----------+\n                                     |   API     |\n                          +----------+   \"/2\"    +-----------+\n                          |          |           |           |\n                          |          +-----+-----+           |\n                          |                |                 |\n                   +------v-----+    +-----v------+    +-----v------+\n                   |  Resource  |    |  Resource  |    |  Resource  |\n       +-----------+   \"car\"    |    |   \"ping\"   |    |  \"user\"    |\n       |           |            |    |            |    |            |\n       |           +-----+------+    +------------+    +-----+------+\n       |                 |                                   |\n+------v-----+     +-----v------+                      +-----v------+\n|  Resource  |     |  Resource  |                      |  Resource  |\n| \"findMatch\"|     | \"{carId}\"  |                      |  \"signOut\" |\n|            |     |            |                      |            |\n+------------+     +------------+                      +------------+\n\n```\n\n\n## API methods:\n- GenerateServer(g rest.ServerGenerator) http.Handler\n- GenerateSpec(w io.Writer, api rest.API)\n\n## Example:\n```go\napi := rest.NewAPI(\"/v1\", \"localhost\", \"My simple car API\", \"v1\")\n// Generating OpenAPI v2 specification to standard output\napi.GenerateSpec(os.Stdout, \u0026oaiv2.OpenAPIV2SpecGenerator{})\n// Generating server handler\nserver := api.GenerateServer(chigenerator.ChiGenerator{})\n```\n\n## Resource\nResource main components:\n- Methods: A collection of HTTP methods.\n- Resources: Collection of child resources.\n\n## Example:\n```go\napi.Resource(\"user\", func(r *rest.Resource) {\n    // Method\n    r.Get(getUser, ct)\n    // Resource\n    r.Resource(\"logout\", func(r *rest.Resource) {\n        // Method\n        r.Get(logOut, ct)\n    })\n})\n```\n\n## ResourceP (URI parameter Resource)\nResourceP creates a new URI parameter resource node.\nThe first argument must be a Parameter of URIParameter type. Use NewURIParameter to create one.\n\n## Example:\n```go\ncarID := rest.NewURIParameter(\"carID\", reflect.String)\nr.ResourceP(carID, func(r *rest.Resource) {\n    r.Get(getCar, ct).WithParameter(carID)\n})\n```\nIn the example the route to get a car will be `/car/{carID}`, where `{carID}` is the variable part.\n\n### Method\nA `Method` represents an HTTP method with an HTTP Handler. A default handler will make sense of the method specification and return the appropriate HTTP response. The specification elements to be managed by the default handler are: **Content negotiation, security, validation, and operation.**\n\n- MethodOperation: Describes an `Operation` and responses (`Response` for success and failure).\n- ContentTypes: Describes the available content-types and encoder/decoders for request and responses. \n- Negotiator: Interface for content negotiation. A default implementation will be set when you create a Method.\n- SecurityCollection: Is the security definition.\n- Parameters: The parameters expected to be sent by the client. The main purpose of the declaration of parameters is for API specification generation.\n- Handler: The http.Handler of the method.  The default handler will be set when you create a new Method.\n\n### Operation\nRepresents a logical operation upon a resource, like delete, list, create, ping, etc. `Operation` is an interface defined by an `Execute` method.\n\n#### Execute method\n- \tInputs: `Input` type\n- \tOutput: `body` interface{}, `success` bool, and `err` error .\n\n\n\t1. `body` (interface{}): Is the body that is going to be send to the client.(Optional)\n\t2. `success` (bool): If the value is true, it will trigger the `successResponse` (argument passed in the `NewMethodOperation` function). If the value is false, it will trigger the `failResponse` (set it with `WithFailResponse` method). False means that the most positive operation output didn't happened, but is not an API nor a client error.\n\t3.  `err` (error): The `err`(error) is meant to indicate an API error, or any internal server error, like a database failure, i/o error, etc. The `err`!=nil will always trigger a 500 code error.\n\n### Method:\n\n```\n                               +----------------+\n                               |                |\n                               |     Method     |\n                               |                |\n                               +--------+-------+\n                                        |\n                               +--------+-------+\n                               |                |\n                           +---+ MethodOperation+---+\n                           |   |                |   |\nYour operation method      |   +--------+-------+   |\ngoes here                  |            |           |\n      +                    |            |           |\n      |             +------+----+ +-----+-----+ +---+-------+\n      |             |           | | Response  | |  Response |\n      +-----------\u003e | Operation | | success   | |  fail     |\n                    |           | |           | |           |\n                    +-----------+ +-----------+ +-----------+\n\n```\n\n## Full code example:\n```go\n// Responses\nsuccessResponse := rest.NewResponse(200).WithOperationResultBody(Car{})\nfailResponse := rest.NewResponse(404)\n\ngetCarOperation := func(i rest.Input) (body interface{}, success bool, err error) {\n    carID, err := i.GetURIParam(\"carID\")\n\n    if err != nil {\n        log.Println(\"error getting parameter: \", err)\n        return Car{}, false, err\n    }\n\n    if carID == \"error\" {\n        // Internal error trying to get the car. This will trigger a response code 500\n        return nil, false, errors.New(\"Internal error\")\n    }\n\n    if carID != \"101\" {\n        // Car not found, success is false, no error. This will trigger the `failResponse` (response code 404)\n        return nil, false, nil\n    }\n\n    // Car found, success true, error nil. This will trigger the `successResponse` (response code 200)\n    return Car{carID, \"Foo\"}, true, nil\n}\n// Method Operation\ngetCar := rest.NewMethodOperation(rest.OperationFunc(getCarOperation), successResponse).WithFailResponse(failResponse)\n// ContentTypes\nct := rest.NewContentTypes()\nct.Add(\"application/json\", encdec.JSONEncoderDecoder{}, true)\n\napi := rest.NewAPI(\"/v1\", \"localhost\", \"My simple car API\", \"v1\")\napi.Resource(\"car\", func(r *rest.Resource) {\n    carID := rest.NewURIParameter(\"carID\", reflect.String)\n    r.ResourceP(carID, func(r *rest.Resource) {\n        r.Get(getCar, ct).WithParameter(carID)\n    })\n})\n// Generating OpenAPI v2 specification to standard output\napi.GenerateSpec(os.Stdout, \u0026oaiv2.OpenAPIV2SpecGenerator{})\n\n// Generating server routes\nserver := api.GenerateServer(chigenerator.ChiGenerator{})\nhttp.ListenAndServe(\":8080\", server)\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehsoc%2Frest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fehsoc%2Frest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehsoc%2Frest/lists"}