zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

README.md (9487B)


      1 # Plug
      2 
      3 [![Build Status](https://github.com/elixir-plug/plug/workflows/CI/badge.svg)](https://github.com/elixir-plug/plug/actions?query=workflow%3A%22CI%22)
      4 [![Inline docs](https://inch-ci.org/github/elixir-plug/plug.svg?branch=master)](http://inch-ci.org/github/elixir-plug/plug)
      5 
      6 Plug is:
      7 
      8   1. A specification for composing web applications with functions
      9   2. Connection adapters for different web servers in the Erlang VM
     10 
     11 [Documentation for Plug is available online](http://hexdocs.pm/plug/).
     12 
     13 ## Installation
     14 
     15 In order to use Plug, you need a webserver and its bindings for Plug. The Cowboy webserver is the most common one, which can be installed by adding `plug_cowboy` as a dependency to your `mix.exs`:
     16 
     17 ```elixir
     18 def deps do
     19   [
     20     {:plug_cowboy, "~> 2.0"}
     21   ]
     22 end
     23 ```
     24 
     25 ## Hello world
     26 
     27 ```elixir
     28 Mix.install([:plug, :plug_cowboy])
     29 
     30 defmodule MyPlug do
     31   import Plug.Conn
     32 
     33   def init(options) do
     34     # initialize options
     35     options
     36   end
     37 
     38   def call(conn, _opts) do
     39     conn
     40     |> put_resp_content_type("text/plain")
     41     |> send_resp(200, "Hello world")
     42   end
     43 end
     44 
     45 require Logger
     46 {:ok, _} = Plug.Cowboy.http(MyPlug, [])
     47 Logger.info("Plug now running on localhost:4000")
     48 ```
     49 
     50 The snippet above shows a very simple example on how to use Plug. Save that snippet to a file and execute it as `elixir --no-halt hello_world.exs`. Access <http://localhost:4000/> and you should be greeted!
     51 
     52 For now, we have directly started the server in a single file but, for production deployments, you likely want to start it in your supervision tree. See the [Supervised handlers](#supervised-handlers) section next.
     53 
     54 ## Supervised handlers
     55 
     56 On a production system, you likely want to start your Plug pipeline under your application's supervision tree. Start a new Elixir project with the `--sup` flag:
     57 
     58 ```shell
     59 $ mix new my_app --sup
     60 ```
     61 
     62 Add both `:plug` and `:plug_cowboy` as dependencies in your `mix.exs`:
     63 
     64 ```elixir
     65 def deps do
     66   [
     67     {:plug, "~> 1.13"},
     68     {:plug_cowboy, "~> 2.0"}
     69   ]
     70 end
     71 ```
     72 
     73 Now update `lib/my_app/application.ex` as follows:
     74 
     75 ```elixir
     76 defmodule MyApp.Application do
     77   # See https://hexdocs.pm/elixir/Application.html
     78   # for more information on OTP Applications
     79   @moduledoc false
     80 
     81   use Application
     82 
     83   def start(_type, _args) do
     84     # List all child processes to be supervised
     85     children = [
     86       {Plug.Cowboy, scheme: :http, plug: MyPlug, options: [port: 4001]}
     87     ]
     88 
     89     # See https://hexdocs.pm/elixir/Supervisor.html
     90     # for other strategies and supported options
     91     opts = [strategy: :one_for_one, name: MyApp.Supervisor]
     92     Supervisor.start_link(children, opts)
     93   end
     94 end
     95 ```
     96 
     97 Finally create `lib/my_app/my_plug.ex` with the `MyPlug` module.
     98 
     99 Now run `mix run --no-halt` and it will start your application with a web server running at <http://localhost:4001>.
    100 
    101 ## Supported Versions
    102 
    103 | Branch | Support                  |
    104 |--------|--------------------------|
    105 | v1.13  | Bug fixes                |
    106 | v1.12  | Security patches only    |
    107 | v1.11  | Security patches only    |
    108 | v1.10  | Security patches only    |
    109 | v1.9   | Security patches only    |
    110 | v1.8   | Security patches only    |
    111 | v1.7   | Unsupported from 01/2022 |
    112 | v1.6   | Unsupported from 01/2022 |
    113 | v1.5   | Unsupported from 03/2021 |
    114 | v1.4   | Unsupported from 12/2018 |
    115 | v1.3   | Unsupported from 12/2018 |
    116 | v1.2   | Unsupported from 06/2018 |
    117 | v1.1   | Unsupported from 01/2018 |
    118 | v1.0   | Unsupported from 05/2017 |
    119 
    120 ## The `Plug.Conn` struct
    121 
    122 In the hello world example, we defined our first plug. What is a plug after all?
    123 
    124 A plug takes two shapes. A function plug receives a connection and a set of options as arguments and returns the connection:
    125 
    126 ```elixir
    127 def hello_world_plug(conn, _opts) do
    128   conn
    129   |> put_resp_content_type("text/plain")
    130   |> send_resp(200, "Hello world")
    131 end
    132 ```
    133 
    134 A 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:
    135 
    136 ```elixir
    137 defmodule MyPlug do
    138   def init([]), do: false
    139   def call(conn, _opts), do: conn
    140 end
    141 ```
    142 
    143 As per the specification above, a connection is represented by the `Plug.Conn` struct:
    144 
    145 ```elixir
    146 %Plug.Conn{
    147   host: "www.example.com",
    148   path_info: ["bar", "baz"],
    149   ...
    150 }
    151 ```
    152 
    153 Data 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`.
    154 
    155 Remember that, as everything else in Elixir, **a connection is immutable**, so every manipulation returns a new copy of the connection:
    156 
    157 ```elixir
    158 conn = put_resp_content_type(conn, "text/plain")
    159 conn = send_resp(conn, 200, "ok")
    160 conn
    161 ```
    162 
    163 Finally, 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.
    164 
    165 ## `Plug.Router`
    166 
    167 To write a "router" plug that dispatches based on the path and method of incoming requests, Plug provides `Plug.Router`:
    168 
    169 ```elixir
    170 defmodule MyRouter do
    171   use Plug.Router
    172 
    173   plug :match
    174   plug :dispatch
    175 
    176   get "/hello" do
    177     send_resp(conn, 200, "world")
    178   end
    179 
    180   forward "/users", to: UsersRouter
    181 
    182   match _ do
    183     send_resp(conn, 404, "oops")
    184   end
    185 end
    186 ```
    187 
    188 The router is a plug. 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 (imported) `match/2` function, and then call the `:dispatch` plug which will execute the matched code.
    189 
    190 Plug 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:
    191 
    192 ```elixir
    193 plug Plug.Logger
    194 plug :match
    195 plug :dispatch
    196 ```
    197 
    198 Note `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!
    199 
    200 This also means that a catch all `match` block 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).
    201 
    202 Each route needs to return the connection as per the Plug specification. See the `Plug.Router` docs for more information.
    203 
    204 ## Testing plugs
    205 
    206 Plug 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):
    207 
    208 ```elixir
    209 defmodule MyPlugTest do
    210   use ExUnit.Case, async: true
    211   use Plug.Test
    212 
    213   @opts MyRouter.init([])
    214 
    215   test "returns hello world" do
    216     # Create a test connection
    217     conn = conn(:get, "/hello")
    218 
    219     # Invoke the plug
    220     conn = MyRouter.call(conn, @opts)
    221 
    222     # Assert the response and status
    223     assert conn.state == :sent
    224     assert conn.status == 200
    225     assert conn.resp_body == "world"
    226   end
    227 end
    228 ```
    229 
    230 ## Available plugs
    231 
    232 This project aims to ship with different plugs that can be re-used across applications:
    233 
    234   * `Plug.BasicAuth` - provides Basic HTTP authentication;
    235   * `Plug.CSRFProtection` - adds Cross-Site Request Forgery protection to your application. Typically required if you are using `Plug.Session`;
    236   * `Plug.Head` - converts HEAD requests to GET requests;
    237   * `Plug.Logger` - logs requests;
    238   * `Plug.MethodOverride` - overrides a request method with one specified in the request parameters;
    239   * `Plug.Parsers` - responsible for parsing the request body given its content-type;
    240   * `Plug.RequestId` - sets up a request ID to be used in logs;
    241   * `Plug.RewriteOn` - rewrite the request's host/port/protocol from `x-forwarded-*` headers;
    242   * `Plug.Session` - handles session management and storage;
    243   * `Plug.SSL` - enforces requests through SSL;
    244   * `Plug.Static` - serves static files;
    245   * `Plug.Telemetry` - instruments the plug pipeline with `:telemetry` events;
    246 
    247 You can go into more details about each of them [in our docs](http://hexdocs.pm/plug/).
    248 
    249 ## Helper modules
    250 
    251 Modules that can be used after you use `Plug.Router` or `Plug.Builder` to help development:
    252 
    253   * `Plug.Debugger` - shows a helpful debugging page every time there is a failure in a request;
    254   * `Plug.ErrorHandler` - allows developers to customize error pages in case of crashes instead of sending a blank one;
    255 
    256 ## Contributing
    257 
    258 We welcome everyone to contribute to Plug and help us tackle existing issues!
    259 
    260 Use the [issue tracker][issues] for bug reports or feature requests. Open a [pull request][pulls] when you are ready to contribute. When submitting a pull request you should not update the `CHANGELOG.md`.
    261 
    262 If you are planning to contribute documentation, [please check our best practices for writing documentation][writing-docs].
    263 
    264 Finally, remember all interactions in our official spaces follow our [Code of Conduct][code-of-conduct].
    265 
    266 ## License
    267 
    268 Plug source code is released under Apache License 2.0.
    269 Check LICENSE file for more information.
    270 
    271   [issues]: https://github.com/elixir-plug/plug/issues
    272   [pulls]: https://github.com/elixir-plug/plug/pulls
    273   [code-of-conduct]: https://github.com/elixir-lang/elixir/blob/master/CODE_OF_CONDUCT.md
    274   [writing-docs]: https://hexdocs.pm/elixir/writing-documentation.html