{"id":20537033,"url":"https://github.com/cvik/heja","last_synced_at":"2025-07-03T13:35:21.364Z","repository":{"id":55446204,"uuid":"113199650","full_name":"cvik/heja","owner":"cvik","description":"Heja - HTTP Erlang JSON APIs","archived":false,"fork":false,"pushed_at":"2022-06-28T00:15:18.000Z","size":26,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-02T15:05:02.554Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cvik.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":".github/CODEOWNERS","security":null,"support":null}},"created_at":"2017-12-05T15:31:02.000Z","updated_at":"2022-06-28T00:15:21.000Z","dependencies_parsed_at":"2022-08-15T00:30:39.952Z","dependency_job_id":null,"html_url":"https://github.com/cvik/heja","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/cvik/heja","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvik%2Fheja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvik%2Fheja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvik%2Fheja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvik%2Fheja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cvik","download_url":"https://codeload.github.com/cvik/heja/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cvik%2Fheja/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263335795,"owners_count":23450931,"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","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-16T00:38:41.929Z","updated_at":"2025-07-03T13:35:21.343Z","avatar_url":"https://github.com/cvik.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Heja - HTTP Erlang JSON APIs\n**Warning** Heja is brand new and is not yet stable enough for any serious use.\n\nHeja is a library for easy creation of HTTP/JSON-APIs, with as little boilerplate\nas possible. The user have no exposure to either HTTP or JSON, but are instead\nrequired to implement their handlers according to a strict spec. The library can\nmanage multiple APIs at the same time and can dynamically add and remove dispatch\nrules and handlers.\n\n\nHeja will only ever accept bodies with `Content-Type: application/json` and will\nalways return JSON, even for errors or calls that are expected to return no value\n(like DELETE requests). Heja will further never return any other codes than 200\nfor success, 400 for client errors and 500 for server errors. The user is expected\nto encode what kind of error has happened in the response body.\n\nThe handlers are erlang `fun`s and must follow this spec:\n```erlang\n-type json()       :: json_map()|json_array().\n-type json_map()   :: #{key():=val()}.\n-type json_array() :: [val()].\n-type key()        :: atom()|string()|binary().\n-type val()        :: true|false|null|atom()|binary()|integer()|float()|json().\n\n-spec fn(Body::json(), Context::#{atom():=binary()}) -\u003e\n\t\t{ok, json_map()} | {ok, {text, binary()}} | {error, atom()}.\n```\n\nThe above JSON spec is not exhaustive. For more details, see\n[lejson](https://github.com/cvik/lejson).\n\n**Note** that heja requires the returned value to be a `json_map()`. Arrays\nare not allowed as a top level return value.\n\nAll query values and path-variables are collected into the `Context::map()`\nargument. The `Body::map()` is the decoded JSON value from `PUT` and `POST`\nrequests. It will always be the empty map for `GET` and `DELETE` requests.\n\n### Abstractions\n - API - a collection of dispatch rules and handlers that run on a specific port\n - Handler - An erlang fun, bound to a path and method\n\n### Example usage\n\n```erlang\n1\u003e heja:start().\n{ok, [heja]}\n\n2\u003e {ok, Ref} = heja:new(my_api).\n{ok, #Ref\u003c0.2100316181.119799809.110578\u003e}\n\n3\u003e heja:get(Ref, \"/api/v1/users/:id\", fun(_Body, #{id:=Id}) -\u003e {ok, #{user=\u003e#{id=\u003eId}}} end).\nok\n\n4\u003e heja:serve(Ref, 8080).\nok\n```\n\nThen try:\n```bash\n$ curl localhost:8080/api/v1/users/25 \u0026\u0026 echo\n{\"user\": {\"id\":\"25\"}}\n$\n```\n\n### Todo\n - [x] Need to be able to remove endpoints\n - [x] Add query-map to context (handle conflicts)\n - [x] should be able to stop API (via ref)\n - [x] Should be able to get api dispatch list\n - [x] Need to only accept and always return `Content-Type: application/json`\n - [x] Need to return proper errors for:\n   - [x] 400 (bad request)\n   - [x] 404 (not found),\n   - [x] 405 (method not allowed)\n   - [x] 406 (not acceptable)\n - [x] Should be able to get api status\n - [x] Should handle multiple tries to serve on same port\n - [x] Better handle of handler-funs return types\n - [x] Support returning raw text: `{ok {text, binary()}}`\n - [x] Serve should not start a new server if one is already running on that port\n - [x] New/x should not add an api, if one with the same name and version exists\n - [x] Should handle iodata paths\n - Documentation:\n   - [ ] Function descriptions in the facade\n   - [ ] More README.md examples\n   - [ ] Better description of intent and purpose of the library\n - Error handling:\n   - [ ] Verfify which error check should be handled first, 405 or 406.\n   - [ ] Catch json decode errors -\u003e 400\n   - [ ] Catch json encode errors -\u003e 500 (it's a `handler_failure` of sorts)\n   - [ ] Catch server crashes and restart (linked to the api-manager)\n - Features:\n   - [ ] Context keys should always be atoms\n   - [ ] Bindings should handle constraints (int|func|non\\_empty)\n   - [ ] Option to include stacktrace in crash response (500s)\n - Testing:\n   - [ ] Test the router\n   - [ ] Test the dispatcher\n   - [ ] test the api-manager (maybe skip the serve/deserve code paths)\n\n### License\n\nApache license version 2.0. See the LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcvik%2Fheja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcvik%2Fheja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcvik%2Fheja/lists"}