• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

config/H16-Feb-2018-108

lib/H16-Feb-2018-8,4866,835

src/H16-Feb-2018-471338

test/H16-Feb-2018-5,0974,146

.formatter.exsH A D16-Feb-2018509 2927

.gitignoreH A D16-Feb-201845 76

.travis.ymlH A D16-Feb-2018304 1615

CHANGELOG.mdH A D16-Feb-201814.7 KiB491344

LICENSEH A D16-Feb-2018577 1410

README.mdH A D16-Feb-20188.8 KiB261184

mix.exsH A D16-Feb-20181.1 KiB4236

mix.lockH A D16-Feb-20182 KiB1514

README.md

1# Plug
2
3[![Build Status](https://travis-ci.org/elixir-plug/plug.svg?branch=master)](https://travis-ci.org/elixir-plug/plug)
4[![Inline docs](http://inch-ci.org/github/elixir-plug/plug.svg?branch=master)](http://inch-ci.org/github/elixir-plug/plug)
5
6Plug is:
7
81. A specification for composable modules between web applications
92. Connection adapters for different web servers in the Erlang VM
10
11[Documentation for Plug is available online](http://hexdocs.pm/plug/).
12
13## Hello world
14
15```elixir
16defmodule MyPlug do
17  import Plug.Conn
18
19  def init(options) do
20    # initialize options
21
22    options
23  end
24
25  def call(conn, _opts) do
26    conn
27    |> put_resp_content_type("text/plain")
28    |> send_resp(200, "Hello world")
29  end
30end
31```
32
33The snippet above shows a very simple example on how to use Plug. Save that snippet to a file and run it inside the plug application with:
34
35    $ iex -S mix
36    iex> c "path/to/file.ex"
37    [MyPlug]
38    iex> {:ok, _} = Plug.Adapters.Cowboy.http MyPlug, []
39    {:ok, #PID<...>}
40
41Access "http://localhost:4000/" and we are done! For now, we have directly started the server in our terminal but, for production deployments, you likely want to start it in your supervision tree. See the "Supervised handlers" section below.
42
43## Installation
44
45You can use plug in your projects in two steps:
46
471. Add plug and your webserver of choice (currently cowboy) to your `mix.exs` dependencies:
48
49    ```elixir
50    def deps do
51      [{:cowboy, "~> 1.0.0"},
52       {:plug, "~> 1.0"}]
53    end
54    ```
55
562. List both `:cowboy` and `:plug` as your application dependencies:
57
58    ```elixir
59    def application do
60      [applications: [:cowboy, :plug]]
61    end
62    ```
63
64## Supported Versions
65
66| Branch | Support                  |
67| ------ | ------------------------ |
68| v1.4   | Bug fixes                |
69| v1.3   | Security patches only    |
70| v1.2   | Security patches only    |
71| v1.1   | Security patches only    |
72| v1.0   | Unsupported from 05/2017 |
73
74## The Plug.Conn
75
76In the hello world example, we defined our first plug. What is a plug after all?
77
78A plug takes two shapes. A function plug receives a connection and a set of options as arguments and returns the connection:
79
80```elixir
81def hello_world_plug(conn, _opts) do
82  conn
83  |> put_resp_content_type("text/plain")
84  |> send_resp(200, "Hello world")
85end
86```
87
88A module plug implements an `init/1` function to initialize the options and a `call/2` function which receives the connection and initialized options and returns the connection:
89
90```elixir
91defmodule MyPlug do
92  def init([]), do: false
93  def call(conn, _opts), do: conn
94end
95```
96
97As per the specification above, a connection is represented by the `Plug.Conn` struct:
98
99```elixir
100%Plug.Conn{host: "www.example.com",
101           path_info: ["bar", "baz"],
102           ...}
103```
104
105Data can be read directly from the connection and also pattern matched on. Manipulating the connection often happens with the use of the functions defined in the `Plug.Conn` module. In our example, both `put_resp_content_type/2` and `send_resp/3` are defined in `Plug.Conn`.
106
107Remember that, as everything else in Elixir, **a connection is immutable**, so every manipulation returns a new copy of the connection:
108
109```elixir
110conn = put_resp_content_type(conn, "text/plain")
111conn = send_resp(conn, 200, "ok")
112conn
113```
114
115Finally, keep in mind that a connection is a **direct interface to the underlying web server**. When you call `send_resp/3` above, it will immediately send the given status and body back to the client. This makes features like streaming a breeze to work with.
116
117## The Plug Router
118
119In practice, developers rarely write their own plugs. For example, Plug ships with a router that allows developers to quickly match on incoming requests and perform some action:
120
121```elixir
122defmodule MyRouter do
123  use Plug.Router
124
125  plug :match
126  plug :dispatch
127
128  get "/hello" do
129    send_resp(conn, 200, "world")
130  end
131
132  forward "/users", to: UsersRouter
133
134  match _ do
135    send_resp(conn, 404, "oops")
136  end
137end
138```
139
140The router is a plug and, not only that, it contains its own plug pipeline too. The example above says that when the router is invoked, it will invoke the `:match` plug, represented by a local `match/2` function, and then call the `:dispatch` plug which will execute the matched code.
141
142Plug ships with many plugs that you can add to the router plug pipeline, allowing you to plug something before a route matches or before a route is dispatched to. For example, if you want to add logging to the router, just do:
143
144```elixir
145plug Plug.Logger
146plug :match
147plug :dispatch
148```
149
150Note `Plug.Router` compiles all of your routes into a single function and relies on the Erlang VM to optimize the underlying routes into a tree lookup, instead of a linear lookup that would instead match route-per-route. This means route lookups are extremely fast in Plug!
151
152This also means that a catch all `match` is recommended to be defined, as in the example above, otherwise routing fails with a function clause error (as it would in any regular Elixir function).
153
154Each route needs to return the connection as per the Plug specification. See `Plug.Router` docs for more information.
155
156## Supervised handlers
157
158On a production system, you likely want to start your Plug application under your application's supervision tree. Plug provides the `child_spec/3` function to do just that. Start a new Elixir project with the `--sup` flag:
159
160```elixir
161$ mix new my_app --sup
162```
163
164and then update `lib/my_app.ex` as follows:
165
166```elixir
167defmodule MyApp do
168  use Application
169
170  # See https://hexdocs.pm/elixir/Application.html
171  # for more information on OTP Applications
172  def start(_type, _args) do
173    import Supervisor.Spec
174
175    children = [
176      # Define workers and child supervisors to be supervised
177      Plug.Adapters.Cowboy.child_spec(:http, MyRouter, [], [port: 4001])
178    ]
179
180    # See https://hexdocs.pm/elixir/Supervisor.html
181    # for other strategies and supported options
182    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
183    Supervisor.start_link(children, opts)
184  end
185end
186```
187
188## Testing plugs
189
190Plug ships with a `Plug.Test` module that makes testing your plugs easy. Here is how we can test the router from above (or any other plug):
191
192```elixir
193defmodule MyPlugTest do
194  use ExUnit.Case, async: true
195  use Plug.Test
196
197  @opts MyRouter.init([])
198
199  test "returns hello world" do
200    # Create a test connection
201    conn = conn(:get, "/hello")
202
203    # Invoke the plug
204    conn = MyRouter.call(conn, @opts)
205
206    # Assert the response and status
207    assert conn.state == :sent
208    assert conn.status == 200
209    assert conn.resp_body == "world"
210  end
211end
212```
213
214### Available Plugs
215
216This project aims to ship with different plugs that can be re-used across applications:
217
218  * `Plug.CSRFProtection` - adds Cross-Site Request Forgery protection to your application. Typically required if you are using `Plug.Session`;
219  * `Plug.Head` - converts HEAD requests to GET requests;
220  * `Plug.Logger` - logs requests;
221  * `Plug.MethodOverride` - overrides a request method with one specified in headers;
222  * `Plug.Parsers` - responsible for parsing the request body given its content-type;
223  * `Plug.RequestId` - sets up a request ID to be used in logs;
224  * `Plug.Session` - handles session management and storage;
225  * `Plug.SSL` - enforce requests through SSL;
226  * `Plug.Static` - serves static files;
227
228You can go into more details about each of them [in our docs](http://hexdocs.pm/plug/).
229
230### Helper modules
231
232Modules that can be used after you use `Plug.Router` or `Plug.Builder` to help development:
233
234  * `Plug.Debugger` - shows a helpful debugging page every time there is a failure in a request;
235  * `Plug.ErrorHandler` - allows developers to customize error pages in case of crashes instead of sending a blank one;
236
237## Contributing
238
239We welcome everyone to contribute to Plug and help us tackle existing issues!
240
241Use the [issue tracker][issues] for bug reports or feature requests. You may also start a discussion on the [mailing list][ML] or the **[#elixir-lang][IRC]** channel on [Freenode][freenode] IRC. Open a [pull request][pulls] when you are ready to contribute.
242
243When submitting a pull request you should not update the `CHANGELOG.md`.
244
245If you are planning to contribute documentation, [please check our best practices for writing documentation][writing-docs].
246
247Finally, remember all interactions in our official spaces follow our [Code of Conduct][code-of-conduct].
248
249## License
250
251Plug source code is released under Apache 2 License.
252Check LICENSE file for more information.
253
254  [issues]: https://github.com/elixir-plug/plug/issues
255  [pulls]: https://github.com/elixir-plug/plug/pulls
256  [ML]: https://groups.google.com/group/elixir-lang-core
257  [code-of-conduct]: https://github.com/elixir-lang/elixir/blob/master/CODE_OF_CONDUCT.md
258  [writing-docs]: http://elixir-lang.org/docs/stable/elixir/writing-documentation.html
259  [IRC]: https://webchat.freenode.net/?channels=#elixir-lang
260  [freenode]: http://www.freenode.net
261