{"id":13646753,"url":"https://github.com/fbeline/rooster","last_synced_at":"2025-04-21T21:31:21.109Z","repository":{"id":113361554,"uuid":"80791142","full_name":"fbeline/rooster","owner":"fbeline","description":"Erlang REST framework","archived":true,"fork":false,"pushed_at":"2017-11-19T23:35:35.000Z","size":1039,"stargazers_count":173,"open_issues_count":1,"forks_count":10,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-05-19T05:04:25.408Z","etag":null,"topics":["erlang","rest-api"],"latest_commit_sha":null,"homepage":"","language":"Erlang","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/fbeline.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2017-02-03T02:44:10.000Z","updated_at":"2024-06-20T17:33:19.454Z","dependencies_parsed_at":null,"dependency_job_id":"db3aca97-fbf8-4583-b19b-679cd08a08a0","html_url":"https://github.com/fbeline/rooster","commit_stats":null,"previous_names":["felipebb/rooster"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeline%2Frooster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeline%2Frooster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeline%2Frooster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fbeline%2Frooster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fbeline","download_url":"https://codeload.github.com/fbeline/rooster/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223880272,"owners_count":17219094,"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":["erlang","rest-api"],"created_at":"2024-08-02T01:03:04.968Z","updated_at":"2024-11-09T20:30:31.467Z","avatar_url":"https://github.com/fbeline.png","language":"Erlang","funding_links":[],"categories":["Erlang"],"sub_categories":[],"readme":"# Rooster [![Build Status](https://travis-ci.org/fbeline/rooster.svg?branch=master)](https://travis-ci.org/fbeline/rooster)\nSimplistic REST framework that runs on top of mochiweb.\n## Features\n- **Routes** Composable routing system that supports `GET` `POST` `PUT` and `DELETE` http verbs.\n- **Middleware**: Functions that have access to the request and the response, intercepting routes before and/or after execution.\n- **Basic Authentication**: Authentication module that can be easily integrated with Middleware.\n- **HTTPS Support**\n\n## Installation\n1) Download and install [rebar3](https://www.rebar3.org/)\n\n2) Create a new application using rebar\n\n3) Edit the file **rebar.config** and add the following lines inside deps:\n\n`{deps, [ {rooster, \".*\", {git, \"git://github.com/fbeline/rooster.git\", {branch, \"master\"}}} ]}.`\n\n4) Compile and download dependencies with `rebar3 compile`\n\n## Quick start\nCreate an entry file that will be the initialization module of your application:\n\n```Erlang\n-module(server).\n-export([start/0]).\n\nstart() -\u003e\n  rooster:start(#{port =\u003e 8080},\n                #{routes =\u003e [hello()]}).\n\nhello() -\u003e\n  {'GET', \"/hello\", fun(_) -\u003e {200, #{message =\u003e \u003c\u003c\"hello world\"\u003e\u003e}} end}.\n```\n\nStart it using the command:\n\n```Bash\nerl \\\n  -pa ebin _build/default/lib/*/ebin \\\n  -boot start_sasl \\\n  -s server \\\n  -s reloader\n```\n\nRun `curl localhost:8080/hello` and it should return:\n\n```JSON\n{\"message\": \"hello world\"}\n```\n\n## Routes\nGiven the following functions, you will find how to define routes using *generic* or *nested* definition.\n\n```Erlang\n-export([exports/0]).\n\n% custom header\nget_products(_Req) -\u003e\n  {200, [#{..}, #{..}], [{\"custom-header\", \"foo\"}]}.\n\n% request path param\nget_product(#{params := params}) -\u003e\n  Id = maps:get(id, params),\n  {200, #{id =\u003e Id, price =\u003e 8000}}.\n\n% request payload\nsave_product(#{body := Body}) -\u003e\n  {201, Body}.\n```\nIs important to note that the function **must** have one parameter, that will contain the request information.\n\n### Generic definition\nThe simplest way of defining routes.\n\n```Erlang\nexports() -\u003e\n  [{'GET', \"/products\", fun get_products/1, [auth]},\n   {'POST', \"/products\", fun save_product/1, [auth, admin]}\n   {'GET', \"/products/:id\", fun get_product/1, [auth]}].\n```\n\nThe **exports** method will provide the list of available endpoints that this module contains. Each tuple should have `{HTTP verb, route path, route handler, list of middleware}`, the list of middleware is not a required parameter as a specific route may use none.\n\n### Nested definition\nFor routes that gonna share a specific root path and or middleware, declaring routes in a nested way should be the proper solution.\n\n```Erlang\nexports() -\u003e\n  [{\"/products\", [auth],\n    [{'GET', fun get_products/1},\n     {'POST', fun save_product/1, [admin]}\n     {'GET', \"/:id\", fun get_product/1}]}].\n```\nThe nested definition should fit on the specification:\n\n```\n{root path, list of middleware,\n   [{HTTP verb, *nested path*, route handler, *list of middleware*}]}\n```\nPs: The parameters surround by * are not required.\n\n### Request\nThe request that will be passed to the route handlers is a map as the one bellow:\n\n```erlang\n#{path          =\u003e ...,\n  method        =\u003e ...,\n  headers       =\u003e ...,\n  body          =\u003e ...,\n  qs            =\u003e ...,\n  params        =\u003e ...,\n  cookies       =\u003e ...,\n  authorization =\u003e ...}\n```\n\n## Middleware\n\nThe middleware map can have both `leave` and `enter` keys. The `enter` function will have access to the request information and will be able to change it, the `leave` function will have access to the response and will be able to change it as well.\nAt any moment that a middleware returns `{break, {status, response}}` the chain of execution will terminate and the `response` will be evaluated as the request result.\n\n![middleware](https://user-images.githubusercontent.com/5730881/32140052-75ae38aa-bc3a-11e7-9f54-855b96390bd9.png)\n\n### CORS\nSimple example using a middleware that intercepts the route handler response and\nadd to it custom headers.\n\n```Erlang\n-export([cors/0]).\n\naccess_control() -\u003e\n  [{\"access-control-allow-methods\", \"*\"},\n   {\"access-control-allow-headers\", \"*\"},\n   {\"access-control-allow-origin\", \"*\"}].\n\ncors() -\u003e\n  #{name  =\u003e cors,\n    leave =\u003e fun({Status, Resp, Headers}) -\u003e {Status, Resp, Headers ++ access_control()} end}.\n```\n\n### Basic authentication\nIntercepts the http request before the route handler executes and returns `403` if\ncredentials do not match.\n\n```erlang\n-export([auth/0]).\n\nbasic_auth(#{authorization := Auth} = Req) -\u003e\n  Authorizated = rooster_basic_auth:is_authorized(Auth, {\"admin\", \"admin\"}),\n  case Authorizated of\n    true -\u003e\n      Req;\n    _ -\u003e\n      {break, {403, #{reason =\u003e \u003c\u003c\"Access Forbidden\"\u003e\u003e}}}\n  end.\n\nauth() -\u003e\n  #{name =\u003e auth,\n    enter =\u003e fun basic_auth/1}.\n```\n\n## SSL\nAfter generating the SSL certificate for your domain, everything that needs to be done is to pass some extra parameters for the server configuration map: (**ssl** and **ssl_opts**).\n\n```Erlang\n#{port     =\u003e 8080,\n  ssl      =\u003e {ssl, true},\n  ssl_opts =\u003e {ssl_opts, [{certfile, \"{PATH}/server_cert.pem\"},\n                          {keyfile, \"{PATH}/server_key.pem\"}]}}\n```\n\n## Dependencies\n- mochiweb: HTTP server\n- jsx: JSON parser\n\n## License\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffbeline%2Frooster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffbeline%2Frooster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffbeline%2Frooster/lists"}