README.md

# ExWechat [![Build Status](https://travis-ci.org/h1u2i3/ex_wechat.svg?branch=master)](https://travis-ci.org/h1u2i3/ex_wechat.svg?branch=master)

Elixir/Phoenix wechat api, ([documentation](http://hexdocs.pm/ex_wechat/)).
Issues and pullrequests are welcome.

Still in development, so there may be some bugs.

## Installation

1. Add `ex_wechat` to your list of dependencies in `mix.exs`:

    ```elixir
    def deps do
      [{:ex_wechat, "~> 0.1.4"}]
    end
    ```

2. Add config for your Wechat app:

    ```elixir
    config :ex_wechat, ExWechat,
      appid: System.get_env("WECHAT_APPID") || "your_appid",
      secret: System.get_env("WECHAT_APPSECRET") || "your_appsecret",
      token: System.get_env("WECHAT_TOKEN") || "your_token",
      access_token_cache: "/tmp/access_token"
    ```

## Usage

1. Add route for Wechat:

    ```elixir
    pipeline :api do
      plug :accepts, ["json"]
    end

    pipeline :wechat do
      plug ExWechat.Plugs.WechatSignatureResponder
      plug ExWechat.Plugs.WechatMessageParser
    end

    scope "/wechat", Demo do
      pipe_through [:api, :wechat]
      get "/", WechatController, :index
      post "/", WechatController, :create
    end
    ```
2. In your `WechatController`:

    ```elixir
    defmodule Demo.WechatController do
      use ExWechat.Responder    # interact with user, return message to user
      import ExWechat.Message   # function that parse and render wechat message
    end
    ```
Then your application should work.

## Advanced Usage

1. You can interact with follower ( when receives text message from user, it will return a text message with reverse text ):

    ```elixir
    defmodule Wechat.WechatController do
      require Logger

      use Wechat.Web, :controller
      use ExWechat.Responder

      import ExWechat.Message

      defp on_text_responder(conn) do
        message = conn.assigns[:message]
        case message do
          %{content: "我要图"} ->
            reply_with(conn, build_message(
              %{
                  fromusername: message.tousername,
                  tousername: message.fromusername,
                  msgtype: "news",
                  articlecount: "2",
                  articles:
                    %{
                      item: [
                        %{
                            title: "title",
                            description: "description",
                            picurl: "picurl",
                            url: "url"
                          },
                         %{
                            title: "title",
                            description: "description",
                            picurl: "picurl",
                            url: "url"
                         }]
                     }
                }))
          %{content: content} ->
            reply_with(conn, build_message(
              %{
                fromusername: message.tousername,
                tousername: message.fromusername,
                msgtype: "text",
                content: String.reverse(content)
              }))
          _ ->
            conn
        end
      end
    end
    ```
 Methods you can override:

    ```elixir
    defp on_text_responder(conn),         do: conn
    defp on_image_responder(conn),        do: conn
    defp on_voice_responder(conn),        do: conn
    defp on_video_responder(conn),        do: conn
    defp on_shortvideo_responder(conn),   do: conn
    defp on_location_responder(conn),     do: conn
    defp on_link_responder(conn),         do: conn
    defp on_event_responder(conn),        do: conn
    ```
these methods must return a `Plug.Conn`, just choose what you need.

2. You can import the Wechat Api to any module by:

    ```elixir
    use ExWechat.Api
    ```
All api function are well classified by their function, the api definition files are in `lib/ex_wechat/apis` folder.
If you only want to operate the follower in your wechat app:

    ```elixir
    defmodule Demo.UserController do
      use ExWechat.Api

      @api [:user]

      def index(conn, _opts) do
        # your code you want.
        get_user_list  # return user list
      end
    end
    ```
if you didn't add the `@api` attribute, it will imports all the api methods to the module.

3. With `ExWechat` you can add your own api methods. Set the api definition folder in `config.exs`, then you can use the api you define.
For example:

    ```elixir
    # config/config.exs
    config :ex_wechat, ExWechat,
      appid: System.get_env("WECHAT_APPID"),
      secret: System.get_env("WECHAT_APPSECRET"),
      token: System.get_env("WECHAT_TOKEN"),
      access_token_cache: "/tmp/access_token"
      api_definition_files: Path.join(__DIR__, "lib/demo/apis")

    # api definition file
    # lib/demo/apis/simple_user
    @endpoint https://api.weixin.qq.com/cgi-bin

    # get user list
    function: get_user_list
    path: /user/get
    http: get
    params: access_token

    # web/controller/user_controller.ex
    defmodule Demo.UserController do
      use Demo.Web, :controller
      use ExWechat.Api

      @api [:simple_user] # file name of the api definition file

      def index(conn, _) do
        get_user_list
      end
    end
    ```
4. You can get all the methods defined by check the api definition file, or goto ([documentation](http://hexdocs.pm/ex_wechat/)) and check the `ExWechat` module, of course, you can add your own api definition too.

## Some Tips
1. Upload media to Wechat:

    ```elixir
    iex(2)> ExWechat.upload_media {:multipart, [{:file, "/Users/xiaohui/Desktop/xyz.jpg"}]}, type: "image"
    %{created_at: 1478594562, media_id: "NgGUXaSTGizWyG5Kc0xpydHHIm2PGy68ZViXmpXnojYLV7pw-6zuZaRkTu1cnhja", type: "image"}
    ```
2. Read media from wechat server:

    ```elixir
    iex(1)> ExWechat.get_media media_id: "NgGUXaSTGizWyG5Kc0xpydHHIm2PGy68ZViXmpXnojYLV7pw-6zuZaRkTu1cnhja"
    <<255, 216, 255, 225, 1, 130, 69, 120, 105, 102, 0, 0, 77, 77, 0, 42, 0, 0, 0,
      8, 0, 12, 1, 0, 0, 3, 0, 0, 0, 1, 4, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1, 3, 124,
      0, 0, 1, 2, 0, 3, ...>>
    iex(2)> File.write! "/Users/xiaohui/Desktop/y.jpg", ExWechat.get_media media_id: "NgGUXaSTGizWyG5Kc0xpydHHIm2PGy68ZViXmpXnojYLV7pw-6zuZaRkTu1cnhja"
    :ok
    ```
3. Because we got the base usage with Wechat Api, we can define our own module to do more semantic work.
Media example:

    ```elixir
    defmodule Wechat.Media do
      use ExWechat.Api

      @api [:media]

      def upload_image(path) do
        upload_media {:multipart, [{:file, path}]}, type: "image"
      end

      def download(media_id) do
        get_media media_id: media_id
      end
    end
    ```
User example:

    ```elixir
    defmodule Wechat.User do
      use ExWechat.Api

      @api [:user]

      def info(openid)
        get_user_info openid: openid
      end

      def list do
        get_user_list
      end
    end
    ```
in this Wechat Api sdk, I don't add these modules, I let you to create your own.

## License
MIT license.