{"id":22025289,"url":"https://github.com/beeceej/structural","last_synced_at":"2026-04-29T22:02:08.088Z","repository":{"id":246432086,"uuid":"445957794","full_name":"beeceej/structural","owner":"beeceej","description":null,"archived":false,"fork":false,"pushed_at":"2024-06-27T20:01:15.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-23T10:46:18.324Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beeceej.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-01-09T00:17:20.000Z","updated_at":"2024-06-27T20:02:21.000Z","dependencies_parsed_at":"2024-06-27T23:48:52.508Z","dependency_job_id":"9907f467-5cc2-47c3-adc8-975f5bf266e6","html_url":"https://github.com/beeceej/structural","commit_stats":null,"previous_names":["beeceej/structural"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/beeceej/structural","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beeceej%2Fstructural","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beeceej%2Fstructural/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beeceej%2Fstructural/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beeceej%2Fstructural/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beeceej","download_url":"https://codeload.github.com/beeceej/structural/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beeceej%2Fstructural/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32445555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T20:22:27.477Z","status":"ssl_error","status_checked_at":"2026-04-29T20:22:26.507Z","response_time":110,"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":[],"created_at":"2024-11-30T07:15:33.381Z","updated_at":"2026-04-29T22:02:08.056Z","avatar_url":"https://github.com/beeceej.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Structural\n\nstructural is a Proof of Concept project, that generates API's with automatic request body parsing into discreet types.\n\n`structural` templates are valid Go files in themselves.\n\nFor example:\n\nGiven a `structural` template of:\n\n\n```go\npackage helloworld\n\nimport (\n\tst \"github.com/beeceej/structural\"\n)\n\ntype (\n\n\t// IntroduceRequest is a struct that represents the request body containing ID, Name, Age\n\t// this type may be hooked up to a `structural.Route`\n\tIntroduceRequest struct {\n\t\tID   string `json:\"id\"`\n\t\tName string `json:\"name\"`\n\t\tAge  int    `json:\"age\"`\n\t}\n\n\t// IntroduceRequest is a struct that represents the response body containing a message\n\t// this type may be hooked up to a `structural.Route`\n\tIntroduceResponse struct {\n\t\tMessage string `json:\"response\"`\n\t}\n\n\t// Introduce is a `structural.Route`. When the structural tool finds this `route`,\n\t// it will generate a route with the following:\n\t// - automatic marshalling of request body into the `IntroduceRequest` type.\n\t// - automatic unmarshalling of response body into the `IntroduceResponse` type.\n\tIntroduce struct {\n\t\tst.Route\n\t\tRequestBody          IntroduceRequest\n\t\tResponse             IntroduceResponse\n\t\tRequestBodyEncoding  st.JSON\n\t\tResponseBodyEncoding st.JSON\n\t}\n\n\t// SayHi is a `structural.Route`. When the structural tool finds this `route`,\n\t// it will generate a route with the following:\n\t// - automatic marshalling of request body into the `IntroduceRequest` type.\n\t// - automatic unmarshalling of response body into the `IntroduceResponse` type.\n\tSayHi struct {\n\t\tst.Route\n\t\tRequestBody          IntroduceRequest\n\t\tResponse             IntroduceResponse\n\t\tRequestBodyEncoding  st.JSON\n\t\tResponseBodyEncoding st.JSON\n\t}\n\n\t// SayHi is a `structural.Route`. This showcases that you may have a generic\n\t// `map[string]interface` request body rather than a discreet type.,\n\tGenericHello struct {\n\t\tst.Route\n\t\tRequestBody          map[string]interface{}\n\t\tResponse             IntroduceResponse\n\t\tRequestBodyEncoding  st.JSON\n\t\tResponseBodyEncoding st.JSON\n\t\tAge                  int `arg:\"age\"`\n\t}\n\n\t// HelloWorld is a `structural.API`, it bundles together the various routes.\n\tHelloWorld struct {\n\t\tst.API\n\t\tRouteIntroduce    Introduce    `route:\"/introduction\"`\n\t\tRouteSayHi        SayHi        `route:\"/say-hi\"`\n\t\tRouteGenericHello GenericHello `route:\"/hi\"`\n\t}\n)\n```\n\nthe following code would be generated:\n\n```go\npackage helloworld\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\ntype HelloWorldAPI struct{}\n\nfunc (a *HelloWorldAPI) Routes(mux *http.ServeMux) {\n\tmux.HandleFunc(\"/introduction\", a.HandleRouteIntroduce)\n\tmux.HandleFunc(\"/say-hi\", a.HandleRouteSayHi)\n\tmux.HandleFunc(\"/hi\", a.HandleRouteGenericHello)\n}\n\nfunc (a *HelloWorldAPI) HandleRouteIntroduce(w http.ResponseWriter, r *http.Request) {\n\tvar (\n\t\trb       IntroduceRequest\n\t\tresponse IntroduceResponse\n\t\terr      error\n\t)\n\n\tif err = json.NewDecoder(r.Body).Decode(\u0026rb); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif response, err = a.handleRouteIntroduce(rb); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif err = json.NewEncoder(w).Encode(response); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\nfunc (a *HelloWorldAPI) HandleRouteSayHi(w http.ResponseWriter, r *http.Request) {\n\tvar (\n\t\trb       IntroduceRequest\n\t\tresponse IntroduceResponse\n\t\terr      error\n\t)\n\n\tif err = json.NewDecoder(r.Body).Decode(\u0026rb); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif response, err = a.handleRouteSayHi(rb); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif err = json.NewEncoder(w).Encode(response); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\nfunc (a *HelloWorldAPI) HandleRouteGenericHello(w http.ResponseWriter, r *http.Request) {\n\tvar (\n\t\trb       map[string]interface{}\n\t\tresponse IntroduceResponse\n\t\terr      error\n\t)\n\n\tif err = json.NewDecoder(r.Body).Decode(\u0026rb); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif response, err = a.handleRouteGenericHello(rb); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif err = json.NewEncoder(w).Encode(response); err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n```\n\nThe above code handles boiler plate and allows the user to focus on writing api handlers with discreet request body and response body types.\n\nto see an example of the code in action, clone this repository, then run `bin/example`.\n\n```\n~/Code/beeceej/structural main*\nλ ./bin/example\n{\"response\":\"hi my name is brian, I am 32 years old. my user id is abc-123\"}\n{\"response\":\"map[age:32 id:1 name:brian random-key:abc]\"}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeeceej%2Fstructural","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeeceej%2Fstructural","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeeceej%2Fstructural/lists"}