<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>falood (Falood)</title>
    <link>https://ruby-china.org/falood</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>类似 Ruby Grape 项目的 Elixir RESTFul 框架 Maru</title>
      <description>&lt;p&gt;自从用 grape 开发过 API，从此爱不释手，从开坑 &lt;a href="https://github.com/falood/maru" rel="nofollow" target="_blank" title=""&gt;maru&lt;/a&gt; 到现在也一年多了，从 elixir 0.11 一路跟过来，也遇到了很多问题。现在 elixir 渐渐成熟，elixir 的 web 项目也越来越多，借此推广下这个框架 :D&lt;/p&gt;
&lt;h3 id="为什么会有 maru"&gt;为什么会有 maru&lt;/h3&gt;
&lt;p&gt;学习 elixir 的人应该都知道 &lt;a href="http://www.phoenixframework.org" rel="nofollow" target="_blank" title=""&gt;phoenix&lt;/a&gt; ，毫无疑问 &lt;code&gt;phoenix&lt;/code&gt; 是个非常棒的 elixir web 框架，但就像 ruby 中有 &lt;code&gt;rails&lt;/code&gt; 并没有影响 &lt;code&gt;sinatra&lt;/code&gt; 和 &lt;code&gt;grape&lt;/code&gt; 这种新框架的出现。&lt;code&gt;maru&lt;/code&gt; 也是基于 plug 开发的框架，可以无缝拉入 &lt;code&gt;phoenix&lt;/code&gt; 作为 restful server。&lt;/p&gt;
&lt;h3 id="maru 有什么特点"&gt;maru 有什么特点&lt;/h3&gt;
&lt;p&gt;maru 的灵感来源是 &lt;a href="https://github.com/intridea/grape" rel="nofollow" target="_blank" title=""&gt;grape&lt;/a&gt;，甚至大多数的地方在语法层面上保持一致，如果熟悉 &lt;code&gt;grape&lt;/code&gt; 是非常容易上手的，这里简单介绍一下 maru 的 DSL&lt;/p&gt;
&lt;h4 id="路由"&gt;路由&lt;/h4&gt;
&lt;p&gt;以下路由方案对应了 '/users/:id' 这个 url 的 &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt; 和 &lt;code&gt;delete&lt;/code&gt; 方法：&lt;/p&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;route_param&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;user:&lt;/span&gt; &lt;span class="no"&gt;XXX&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;result:&lt;/span&gt; &lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;delete&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;result:&lt;/span&gt; &lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时 &lt;code&gt;resource&lt;/code&gt; 是可以嵌套的，也支持 &lt;code&gt;get&lt;/code&gt; 、&lt;code&gt;post&lt;/code&gt; 等宏的路径参数，例如：&lt;/p&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:level1&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="ss"&gt;:level2&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;XXX&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;"/users/:id"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;XXX&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="参数"&gt;参数&lt;/h4&gt;
&lt;p&gt;参数的用法同样类似 &lt;code&gt;grape&lt;/code&gt;，但根据 elixir 的语言改变了一些名称，比如说 &lt;code&gt;grape&lt;/code&gt; 里的 Hash 改成了 Map，Symble 改成了 Atom 等。&lt;/p&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="ss"&gt;:age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="no"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;values:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;65&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="ss"&gt;:sex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="no"&gt;Atom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;values:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:male&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:female&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;default:&lt;/span&gt; &lt;span class="ss"&gt;:female&lt;/span&gt;
  &lt;span class="n"&gt;group&lt;/span&gt;    &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="no"&gt;Map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="ss"&gt;:first_name&lt;/span&gt;
    &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="ss"&gt;:intro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;regexp:&lt;/span&gt; &lt;span class="sr"&gt;~r/^[a-z]+$/&lt;/span&gt;
  &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="ss"&gt;:avatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;
  &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="ss"&gt;:avatar_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;
  &lt;span class="n"&gt;exactly_one_of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:avatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:avatar_url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="在 phoenix 框架中使用 maru"&gt;在 phoenix 框架中使用 maru&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;mix.exs 的 deps 里加入 
&lt;code&gt;elixir
{:maru, github: "falood/maru"}
&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;编写 maru router
```elixir
defmodule MyAPP.API do
use Maru.Router&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;get do
    "It Works!" |&amp;gt; text
  end
end&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3. endpoint.ex 里 加一行
```elixir
plug Maru.Plugs.Forword, at: "/api", to: MyAPP.API
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就把 &lt;code&gt;/api&lt;/code&gt; 下的请求 forward 到 maru 了，其它的请求继续走 phoenix，&lt;a href="https://github.com/falood/maru_examples/tree/master/phoenix_maru" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;有个示例。&lt;/p&gt;

&lt;p&gt;PS. 目前 hex 里的最新版是 0.2.7，&lt;code&gt;forword&lt;/code&gt; 的特性已经进入 master 分支，会在 hex 0.2.8 中发布。&lt;/p&gt;
&lt;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;p&gt;更多的特性就不在这里写了，非常欢迎喜欢 &lt;code&gt;grape&lt;/code&gt; 的童鞋试用 &lt;a href="https://github.com/falood/maru" rel="nofollow" target="_blank" title=""&gt;maru&lt;/a&gt; ，也非常欢迎拍砖或贡献代码。&lt;/p&gt;

&lt;p&gt;PS. 希望 github 上的 issue 和 commit 都使用英文。不是为了装 B，虽然我自己英文也比较烂，但中文的 commit 过多，会导致无法与国外的牛人交流，望理解。&lt;/p&gt;</description>
      <author>falood</author>
      <pubDate>Sat, 10 Jan 2015 11:30:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/23654</link>
      <guid>https://ruby-china.org/topics/23654</guid>
    </item>
  </channel>
</rss>
