{"id":19691528,"url":"https://github.com/kbrw/ewebmachine","last_synced_at":"2025-12-11T23:38:40.372Z","repository":{"id":9865151,"uuid":"11863444","full_name":"kbrw/ewebmachine","owner":"kbrw","description":"The HTTP decision tree as a plug (full elixir rewriting of basho/webmachine with improvements)","archived":false,"fork":false,"pushed_at":"2025-09-17T13:46:20.000Z","size":821,"stargazers_count":97,"open_issues_count":4,"forks_count":18,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-09-17T14:27:43.553Z","etag":null,"topics":["plug","webmachine"],"latest_commit_sha":null,"homepage":"","language":"CSS","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/kbrw.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2013-08-03T13:24:59.000Z","updated_at":"2025-08-01T18:55:04.000Z","dependencies_parsed_at":"2024-07-24T08:25:35.360Z","dependency_job_id":"ea337ae7-d608-4716-a060-d3f9c1c9f901","html_url":"https://github.com/kbrw/ewebmachine","commit_stats":{"total_commits":141,"total_committers":9,"mean_commits":"15.666666666666666","dds":"0.44680851063829785","last_synced_commit":"64b7ed15aa10bee8b012c46383259c24a46a5309"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/kbrw/ewebmachine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fewebmachine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fewebmachine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fewebmachine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fewebmachine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kbrw","download_url":"https://codeload.github.com/kbrw/ewebmachine/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fewebmachine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27672194,"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-12-11T02:00:11.302Z","response_time":56,"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":["plug","webmachine"],"created_at":"2024-11-11T19:09:39.167Z","updated_at":"2025-12-11T23:38:40.326Z","avatar_url":"https://github.com/kbrw.png","language":"CSS","readme":"# Ewebmachine [![Build Status](https://github.com/kbrw/ewebmachine/actions/workflows/.github/workflows/build-and-test.yml/badge.svg)](https://github.com/kbrw/ewebmachine/actions/workflows/build-and-test.yml) [![Hex.pm](https://img.shields.io/hexpm/v/ewebmachine.svg)](https://hex.pm/packages/ewebmachine) [![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/ewebmachine) ![Hex.pm License](https://img.shields.io/hexpm/l/ewebmachine)\n\nEwebmachine is a full rewrite with clean DSL and plug integration\nbased on Webmachine from basho. This version is not backward compatible with\nthe previous one that was only a thin wrapper around webmachine, use the branch\n1.0-legacy to use the old one.\n\nThe principle is to go through the [HTTP decision tree](./assets/http_diagram.png)\nand make decisions according to response of some callbacks called \"handlers\".\n\nTo do that, the library gives you 5 plugs and 2 plug pipeline builders :\n\n- `Ewebmachine.Plug.Run` go through the HTTP decision tree and fill\n  the `conn` response according to it\n- `Ewebmachine.Plug.Send` is used to send a conn set with `Ewebmachine.Plug.Run`\n- `Ewebmachine.Plug.Debug` gives you a debugging web UI to see the\n  HTTP decision path taken by each request.\n- `Ewebmachine.Plug.ErrorAsException` take a conn with a response set but not\n  send, and throw an exception is the status code is an exception\n- `Ewebmachine.Plug.ErrorAsForward` take a conn with a response set but not\n  send, and forward it changing the request to `GET /error/pattern/:status`\n- `Ewebmachine.Builder.Handlers` gives you helpers macros and a\n  `:add_handler` plug to add `handlers` as defined  in\n  `Ewebmachine.Handlers` to your conn, and set the initial user state.\n- `Ewebmachine.Builder.Resources` gives you a `resource` macro to\n  define at the same time an `Ewebmachine.Builder.Handlers` and the\n  matching spec to use it, and a plug `:resource_match` to do the\n  match and execute the associated plug. The macro `resources_plugs` helps you\n  to define common plug pipeline\n\n## Example usage\n\n```elixir\ndefmodule MyJSONApi do \n  use Ewebmachine.Builder.Handlers\n  plug :cors\n  plug :add_handlers, init: %{}\n\n  content_types_provided do: [\"application/json\": :to_json]\n  defh to_json, do: Poison.encode!(state[:json_obj])\n\n  defp cors(conn,_), do: \n    put_resp_header(conn,\"Access-Control-Allow-Origin\",\"*\")\nend\n\n\ndefmodule ErrorRoutes do\n  use Ewebmachine.Builder.Resources ; resources_plugs\n  resource \"/error/:status\" do %{s: elem(Integer.parse(status),0)} after \n    content_types_provided do: ['text/html': :to_html, 'application/json': :to_json]\n    defh to_html, do: \"\u003ch1\u003e Error ! : '#{Ewebmachine.Core.Utils.http_label(state.s)}'\u003c/h1\u003e\"\n    defh to_json, do: ~s/{\"error\": #{state.s}, \"label\": \"#{Ewebmachine.Core.Utils.http_label(state.s)}\"}/\n    finish_request do: {:halt,state.s}\n  end\nend\n\ndefmodule FullApi do\n  use Ewebmachine.Builder.Resources\n  if Mix.env == :dev, do: plug Ewebmachine.Plug.Debug\n  resources_plugs error_forwarding: \"/error/:status\", nomatch_404: true\n  plug ErrorRoutes\n\n  resource \"/hello/:name\" do %{name: name} after \n    content_types_provided do: ['application/xml': :to_xml]\n    defh to_xml, do: \"\u003cPerson\u003e\u003cname\u003e#{state.name}\u003c/name\u003e\u003c/Person\u003e\"\n  end\n\n  resource \"/hello/json/:name\" do %{name: name} after \n    plug MyJSONApi #this is also a plug pipeline\n    allowed_methods do: [\"GET\",\"DELETE\"]\n    delete_resource do: DB.delete(state.name)\n\n    defh resource_exists do\n      user = DB.get(state.name)\n      pass(user !== nil, json_obj: user)\n    end\n  end\n\n  resource \"/static/*path\" do %{path: Enum.join(path,\"/\")} after\n    resource_exists do:\n      File.regular?(path state.path)\n    content_types_provided do:\n      [{state.path|\u003ePlug.MIME.path|\u003edefault_plain,:to_content}]\n    defh to_content, do:\n      File.stream!(path(state.path),[],300_000_000)\n    defp path(relative), do: \"#{:code.priv_dir :ewebmachine_example}/web/#{relative}\"\n    defp default_plain(\"application/octet-stream\"), do: \"text/plain\"\n    defp default_plain(type), do: type\n  end\nend\n```\n\n## Debug UI \n\nGo to `/wm_debug` to see precedent requests and debug there HTTP\ndecision path. The debug UI can be updated automatically on the\nrequests.\n\n![Debug UI example](./assets/debug_ui.png)\n\n## Use Cowboy to serve the plug\n\nCreate a simple supervision tree with only the Cowboy server adapter spec.\n\n```elixir\ndefmodule MyApp do\n  use Application\n  def start(_type, _args), do:\n    Supervisor.start_link([\n        Plug.Cowboy.child_spec(:http,FullApi,[], port: 4000)\n      ], strategy: :one_for_one)\nend\n```\n\nAnd add it as your application entry point in your `mix.exs`\n\n```elixir\ndef application do\n  [applications: [:logger,:ewebmachine,:cowboy], mod: {MyApp,[]}]\nend\ndefp deps, do:\n  [{:ewebmachine, \"2.3.2\"}, {:cowboy, \"~\u003e 1.0\"}]\n```\n\n# CONTRIBUTING\n\nHi, and thank you for wanting to contribute.\nPlease refer to the centralized informations available at: https://github.com/kbrw#contributing\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbrw%2Fewebmachine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkbrw%2Fewebmachine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbrw%2Fewebmachine/lists"}