Coder Social home page Coder Social logo

ex_twilio's Introduction

ExTwilio

Hex.pm Build Status Inline docs Module Version Hex Docs Total Download License Last Updated

ExTwilio is a relatively full-featured API client for the Twilio API.

Installation

ExTwilio is currently beta software. You can install it from Hex:

def deps do
  [
    {:ex_twilio, "~> 0.10.0"}
  ]
end

Or from Github:

def deps do
  [
    {:ex_twilio, github: "danielberkompas/ex_twilio"}
  ]
end

and run mix deps.get.

If using Elixir 1.3 or lower add :ex_twilio as a application dependency:

def application do
  [
    applications: [:ex_twilio]
  ]
end

Configuration

You will need to set the following configuration variables in your config/config.exs file:

import Config

config :ex_twilio, account_sid:   {:system, "TWILIO_ACCOUNT_SID"},
                   auth_token:    {:system, "TWILIO_AUTH_TOKEN"},
                   workspace_sid: {:system, "TWILIO_WORKSPACE_SID"} # optional

For security, I recommend that you use environment variables rather than hard coding your account credentials. If you don't already have an environment variable manager, you can create a .env file in your project with the following content:

export TWILIO_ACCOUNT_SID=<account sid here>
export TWILIO_AUTH_TOKEN=<auth token>
export TWILIO_WORKSPACE_SID=<workspace sid here> #optional

Then, just be sure to run source .env in your shell before compiling your project.

Multiple Environments

If you want to use different Twilio credentials for different environments, then create separate Mix configuration files for each environment. To do this, change config/config.exs to look like this:

# config/config.exs

import Config

# shared configuration for all environments here ...

import_config "#{Mix.env}.exs"

Then, create a config/#{environment_name}.exs file for each environment. You can then set the config :ex_twilio variables differently in each file.

Usage

ExTwilio comes with a module for each supported Twilio API resource. For example, the "Call" resource is accessible through the ExTwilio.Call module. Depending on what the underlying API supports, a resource module may have the following methods:

Method Description
all Eager load all of the resource items on all pages. Use with care!
stream Create a Stream of all the items. Use like any Stream.
find Find a resource given its SID.
create Create a resource.
update Update a resource.
destroy Destroy a resource.

Resource modules may contain their own custom methods. If the underlying API endpoint does not support an action, the related method will not be available on that module.

Supported Endpoints

ExTwilio currently supports the following Twilio endpoints:

Twilio's Lookup Rest API:

Twilio's TaskRouter API:

Twilio's ProgrammableChat API:

Twilio Capability Tokens:

Twilio Access Token Grants:

Example

# Get all the calls in the Call endpoint. Be warned, this will block
# until all the pages of calls have been fetched.
calls = ExTwilio.Call.all

# Create a stream of all the calls
stream = ExTwilio.Call.stream

# Lazily filter calls by duration, then map to get only their SIDs
stream
|> Stream.filter(fn(call) -> call.duration > 120 end)
|> Stream.map(fn(call) -> call.sid end)
|> Enum.into([]) # Only here does any work happen.
# => ["CAc14d7...", "CA649ea861..."]

# Find a call
{:ok, call} = ExTwilio.Call.find("CA13a9c7f80c6f3761fabae43242b5b6c6")
inspect(call)
# %ExTwilio.Call{
#   account_sid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#   answered_by: nil, caller_name: "",
#   date_created: "Sat, 14 Mar 2015 14:27:38 +0000",
#   date_updated: "Sat, 14 Mar 2015 14:28:35 +0000",
#   direction: "outbound-api",
#   duration: "52",
#   end_time: "Sat, 14 Mar 2015 14:28:35 +0000",
#   forwarded_from: nil,
#   from: "+1xxxxxxxxxx",
#   parent_call_sid: nil,
#   phone_number_sid: "",
#   price: "-0.01500",
#   price_unit: "USD",
#   sid: "CA13a9c7f80c6f3761fabae43242b5b6c6",
#   start_time: "Sat, 14 Mar 2015 14:27:43 +0000",
#   status: "completed",
#   to: "+1xxxxxxxxxx",
#   uri: "/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/Calls/CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.json"
# }

# Update a call
call = ExTwilio.Call.update(call, status: "canceled")

# Get a call's recordings. This pattern is repeated wherever you are
# getting a nested resource.
recordings = ExTwilio.Recording.all(call: call.sid)

# Destroy a call
ExTwilio.Call.destroy(call)

For more in-depth documentation, see the generated docs for each module.

Making and Receiving Calls

See the CALLING_TUTORIAL.md file for instructions on making and receiving calls from the browser with ExTwilio.

Sending SMS messages

Please look at ExTwilio.Message

Contributing

See the CONTRIBUTING.md file for contribution guidelines.

Copyright and License

Copyright (c) 2015 Daniel Berkompas

ExTwilio is licensed under the MIT license. For more details, see the LICENSE file at the root of the repository. It depends on Elixir, which is under the Apache 2 license.

Twilio™ is trademark of Twilio, Inc.

ex_twilio's People

Contributors

andrewshatnyy avatar brentonannan avatar danielberkompas avatar drgmr avatar dshvimer2 avatar enilsen16 avatar ferd avatar he9lin avatar imrying avatar jeffrafter avatar kianmeng avatar kiere avatar m4ttsch avatar mahcloud avatar michalmuskala avatar mjaric avatar mortadaak avatar novaugust avatar ostap0207 avatar paulanthonywilson avatar pdgonzalez872 avatar rlb3 avatar rrebane avatar scarfacedeb avatar seantanly avatar swelham avatar techgaun avatar tokafish avatar tomciopp avatar yakryder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ex_twilio's Issues

Call vs. Messaging

Why are all your docs and tutorials around calls? Don't people use this library for messaging much more? I'm stuck. I created one message, but can't create more. I could only find small parts of examples in your issues, but not in the docs. Once I get this working, I'm happy to provide a working example.

Error while creating sms

My error is similar to this: #33

I am not using env variables, but config files:

config :ex_twilio, 
    account_sid:   {:system, "any sid"},
    auth_token:    {:system, "any token"} 

Any idea? Thank you!

Utilizing subaccounts / credentials

I was looking over this library out of curiosity (not yet using on a project). I use Twilio Ruby heavily and was comparing against this. One thing that I noticed is that it might not be possible to specify the account sid / token that an API request will be made against.

Is it possible to specify the sid / token that an API request will make?

If it's not, is this something you'd consider accepting a PR for? I was looking at how I might go about it and do not see an obvious path forward currently which is why I ask.

Subaccounts support

Currently sid and token are taken from configuration. That doesn't play well with subaccount set up.

Support API Keys

In my Twilio project (in the Twilio console), we have the Account SID and Auth Token by default, but we use API Keys to hit the endpoints (for the basic auth portion). Unfortunately, you can't use the API Key SID as the Account SID; you still have to provide the Account SID in the API endpoints. I tried letting the Account SID be set by ENV var and then passing in the account and token options for the API key, but ExTwilio seems to take the account option as the account sid when generating the Endpoint URLs.

Does that sound right? And how much effort do you think it would take to modify the library to allow you to pass the account SID as a config option using ENVs and passing the auth "username" as an option to the command (I'm still using ENV, but doing via Application.get_env/3)?

We may end up using subaccounts (inside a Twilio Project) for our customers, but API Key support would be nice for a more secure devops configuration. (Thinking more like AWS IAM vs using AWS root credentials.)

Support for Verify API

I was unable to figure out exactly whether or not the Verify API was supported.

It feels as though some of it lies in the ExTwilio.ProgrammableChat.Service module, but it is not obvious to me how I would go about replicating the behaviour from the Phone Verification Workflow example from Twilio's docs.

`ExTwilio.Member.all queue: queue_sid` fails to parse correct response

When calling ExTwilio.Members.all queue: queue_sid error is risen like below:

** (Protocol.UndefinedError) protocol Enumerable not implemented for nil. This protocol is implemented for: Amnesia.Table.Stream, DBConnection.PrepareStream, DBConnection.Stream, Date.Range, Ecto.Adapters.SQL.Stream, ExCsv.Table, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Range, Scrivener.Page, Stream, Timex.Interval
    (elixir) /home/ubuntu/bob/tmp/b6b304296ade3b61cddf7cdf277daacf/elixir/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) /home/ubuntu/bob/tmp/b6b304296ade3b61cddf7cdf277daacf/elixir/lib/elixir/lib/enum.ex:141: Enumerable.reduce/3
    (elixir) lib/stream.ex:1411: Stream.do_enum_resource/6
    (elixir) lib/enum.ex:1919: Enum.reverse/1
    (elixir) lib/enum.ex:2588: Enum.to_list/1
    (elixir) lib/enum.ex:1163: Enum.into/2

But HTTP response that twilio returns is like this:

{:ok,
 %HTTPoison.Response{
   body: "{\"first_page_uri\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Queues/QUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Members.json?PageSize=50&Page=0\", \"end\": 0, \"previous_page_uri\": null, \"uri\": \"/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Queues/QUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Members.json?PageSize=50&Page=0\", \"page_size\": 50, \"start\": 0, \"next_page_uri\": null, \"queue_members\": [], \"page\": 0}",
   headers: [
     {"Access-Control-Allow-Credentials", "true"},
     {"Access-Control-Allow-Headers",
      "Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since"},
     {"Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS"},
     {"Access-Control-Allow-Origin", "*"},
     {"Access-Control-Expose-Headers", "ETag"},
     {"Content-Type", "application/json"},
     {"Date", "Wed, 28 Nov 2018 23:25:10 GMT"},
     {"Strict-Transport-Security", "max-age=15768000"},
     {"Twilio-Concurrent-Requests", "1"},
     {"Twilio-Request-Duration", "0.032"},
     {"Twilio-Request-Id", "RQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"},
     {"X-Powered-By", "AT-5000"},
     {"X-Shenanigans", "none"},
     {"Content-Length", "412"},
     {"Connection", "keep-alive"}
   ],
   request_url: "https://api.twilio.com/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Queues/QUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Members.json",
   status_code: 200
 }}

From my observation I noticed that ExTwilio.Parser.parse tries to find key in body of response where list of resources is, by using name thatresource_collection_name/0 function in ExTwilio.Member module returns. But since the name is resolved as "members" it tries to access wrong key in response JSON to get list from json response.

The correct name for collection name should be queue_members

Simplify URL generation logic

It's tricky to infer which URL a request should be made to, especially with Twilio's nested APIs. The logic that handles this now is convoluted and spread throughout the Api module.

Ideally, there would be a new module, UrlGenerator or something, which would handle the complexities here.

problem with lib

Hi,
I have following error with poison 2.2.0 :(

iex(1)> use Mix.Config
#PID<0.282.0>
iex(2)> config :ex_twilio, account_sid: "sid", auth_token: "token"
:ok
iex(3)> calls = ExTwilio.Call.all
** (HTTPoison.Error) {:noproc, {:gen_server, :call, [:hackney_manager, {:new_request, #PID<0.278.0>, #Reference<0.0.7.981>, {:client, :undefined, {:metrics_ng, :metrics_dummy}, :hackney_ssl_transport, 'api.twilio.com', 443, "api.twilio.com", [], nil, nil, nil, true, :hackney_pool, 5000, false, 5, false, 5, nil, nil, nil, :undefined, :start, nil, :normal, false, false, false, :undefined, false, nil, :waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, ...}}, :infinity]}}
             lib/ex_twilio/api.ex:19: ExTwilio.Api.request!/5
             lib/ex_twilio/result_stream.ex:45: ExTwilio.ResultStream.fetch_page/2
    (elixir) lib/stream.ex:1121: anonymous fn/5 in Stream.resource/3
    (elixir) lib/enum.ex:1636: Enum.reduce/3
    (elixir) lib/enum.ex:2346: Enum.to_list/1
    (elixir) lib/enum.ex:1057: Enum.into/2

Setting MaxPrice on message

Is it possible to set MaxPrice when sending an SMS with ex_twilio?

I tried with test credentials this:

Message.create([to: number, from: from_number, body: body, max_price: "0.1"])

But I am not sure max_price is the correct flag because test credentials return canned response.

Thanks!

Support for :create on Participant Resource

Currently the Participant resource does not include :create as an option. I've added it locally and verified it does function as expected. Diff is simply:

-  use ExTwilio.Resource, import: [:stream, :all, :find, :update, :destroy]
+  use ExTwilio.Resource, import: [:stream, :all, :find, :update, :create, :destroy]

In the file at:
https://github.com/danielberkompas/ex_twilio/blob/master/lib/ex_twilio/resources/participant.ex

Documentation from Twilio noting creation of a conference participant can be found by scrolling down to the second HTTP POST section here:
https://www.twilio.com/docs/voice/api/conference-participant#http-post

Example usage:

ExTwilio.Participant.create(%{"From" => "+15555555555", "To" => "+15555555556"}, account: "HelloWorldAccount", conference: "12345")

Accessing the Usage logs

Hello,
Thank you for this library.

I was able to send a SMS message but I would like to see the log of the all the SMS message sent for a sid. How would I do that with this library?

Requesting a release

Hello, I would like to request a release. The typespec fix that was merged in April would fix an issue that I'm having with dialyzer. Thanks for your consideration!

Update to Poison >= 3

mix deps.get is complaining locally, that ex_twilio requires an older version of Poison:

Running dependency resolution...

Failed to use "poison" (version 3.1.0) because
  ecto (version 2.1.4) requires ~> 2.2 or ~> 3.0
  ex_twilio (version 0.3.0) requires ~> 2.2
  maru (version 0.11.4) requires ~> 1.5 or ~> 2.0 or ~> 3.0
  mix.lock specifies 3.1.0

** (Mix) Hex dependency resolution failed, relax the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, "~> 1.0", override: true}

Of course one can override with {:poison, "~> 3.1", override: true}, but it would be nicer, if ex_twilio would get upgraded to support ~> 3.0.

Drop using `Mix.Utils` in runtime.

Right now Mix.Utils module is being used in two places:

Mix is a build tool that isn't meant to be used in a runtime, but only for compilation purposes.

When building a production release of a project that uses ex_twillio developers are forced to add

defp apps do
  [
    :logger,
    :ex_twilio,
    :mix,
  ]
end

which should not happen.

ExTwilio.Signature for creating a "x-twilio-signiture" string

I was recently writing some testing for an authorization plug that I wrote that uses the ExTwilio.RequestValidator and could not find a module or method that can create a x-twilio-token to put to my tests Plug.Conn header.

I propose we take this functionality that builds the token in the validator and make a module that creates a twilio signature if you pass in say url and params which may making unit testing controllers and plugs that are using the validator easier!

def create_signature(url, params) do
    token = Config.auth_token()

    url
    |> data_for(params)
    |> compute_hmac(token)
    |> Base.encode64()
  end

  defp data_for(url, params), do: url <> combine(params)

  defp combine(params) do
    params
    |> Map.to_list()
    |> Enum.sort()
    |> Enum.map(fn {key, value} -> key <> value end)
    |> Enum.join()
  end

  defp compute_hmac(data, key), do: :crypto.hmac(:sha, key, data)

Update all inline documentation

  • Ensure accuracy by converting as many examples to doctests as possible
  • Ensure that docs generated by ExTwilio.Resource look right.
  • Make sure all modules have @moduledocs

HTTPoison.Error :nxdomain in lib/ex_twilio/api.ex:19

After upgrading to 0.5.1, Message API calls through ExTwilio are crashing with an error:

HTTPoison.Error :nxdomain in lib/ex_twilio/api.ex:19

I've been tried specifying the API domain in my config files, or leaving it out so the defaults apply. I verified that HTTPoison can connect to the api.twilio.com domain via iex -S mix. All ex_twilio source code I reviewed appears to be correct. Name resolution is working correctly on my testing system inside and out of BEAM.

I can't think of anything else to identify if the issue is local to my system, but wanted to open an issue in case others are finding the same behavior. Feel free to close if you can't reproduce.

Thanks

Date range scoping

At a glance, I haven't seen a way to scope queries by date.
With the Calls resource as an example, Twilio can be queried for calls within a date range.
Calls.json?StartTime%3E=2017-11-01T10%3A00%3A00-07%3A00&EndTime%3C=2017-11-24T16%3A00%3A00-08%3A00

That will query calls between Nov 1, 2017 - Nov 24, 2017.

I believe it would also work unencoded and with dates, i.e. Calls.json?StartTime>=2017-11-01&EndTime<=2017-11-24

Is there a way to do this in ex_twilio that I haven't seen yet?

Getting error after creating/sending message

When I use ExTwilio.Message.create, I receive error but I do receive the message successfully.

The error message reads:

(Protocol.UndefinedError) protocol Enumerable not implemented for %ExTwilio.Message{account_sid: nil, api_version: nil, body: nil, date_created: nil, date_sent: nil, date_updated: nil, direction: nil, error_code: nil, error_message: nil, from: nil, num_media: nil, num_segments: nil, price: nil, price_unit: nil, sid: nil, status: nil, subresource_uri: nil, to: nil, uri: nil}
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:116: Enumerable.reduce/3
    (elixir) lib/enum.ex:1477: Enum.reduce/3
    (ex_twilio) lib/ex_twilio/parser.ex:104: ExTwilio.Parser.handle_errors/2

My code looks something like below:

data = [
      from: "+1...",
      to: "+1...",
      body: "Test msg"
    ]
ExTwilio.Message.create(data)

Also, I saw mentions of httpoison. Any plan on switching to httpoison.

Hex dependency resolution issues

I'm trying to use ex_twilio v0.1.7 with phoenix v1.1.4
There's an issue with poison versions that both apps require:

Conflict on poison from 1.5.0 to 1.5.2
  ecto 1.1.5: ~> 1.0
  ex_twilio 0.1.7: >= 2.0.0
  phoenix 1.1.4: ~> 1.5 or ~> 2.0
  phoenix_ecto 2.0.1: ~> 1.3

Conflict on poison from 2.0.0 to 2.1.0
  phoenix 1.1.4: ~> 1.5 or ~> 2.0
  phoenix_ecto 2.0.0, 2.0.1: ~> 1.3

** (Mix) Hex dependency resolution failed, relax the version requirements or unlock dependencies

Finding Subaccount by Friendly Name

In the Twilio docs, one can fetch a subaccount sid by calling Read on the friendly name. Can this be done in ExTwilio? I can pull a subaccount by sid, but I would prefer not to have to store the sid in my database and instead call via the friendly name, which I can associate with an existing value.

How can I use the Message module?

I'm confused on how I should use the sms message module. I've looked at the readme, docs, and source and can't see what needs to be passed into where.

For example I'm trying to send the sms "Hello World" to +15550002222. Any guidance is much appreciated!

Retrieving A Programmable Chat User.

I've been trying to retrieve a user I created for the programmable chat but I get

>> Built url: https://chat.twilio.com/v2/Users/sid-here

{:error,
 "The requested resource /Users/USd908c37b2f444856a5e52122f6370d01 was not found",
 404}

when I run ExTwilio.Api.find(ExTwilio.ProgrammableChat.User, "sid")

Am I doing anything silly?

Configure accound_sid and auth_token in run time

Hi.

I've tried to use ex_twilio as you specify in documentation and found out the following problem:

  1. Do not define account_sid & auth_token during the build step
  2. Build application
  3. Define account_sid and auth_token
  4. Run application.
  5. Get an error (because account_sid and auth_token is undefined)

It seems that all the configurations are compiled into the binaries and any changes to the configuration in runtime doesn't influence it.

I'm strongly against this approach, as we should have different binaries for the dev and for production, we should have access to the production secrets on our building machine, etc.

If you need more details how I'm doing this - don't hesitate to ask.

PS:
If I'm doing smth wrong and there's a workaround - could you explain it please.

next_page and etc implementation?

Where are the below functions implemented? I only see documentation in the Readme for them, no tests or implementation (I would expect them to be in ExTwilio.Resource). Are they not implemented yet or is their implementation just hiding from me?

next_page   Given the current page, get the next page.
previous_page   Given the current page, get the previous page.
first_page  Given the current page, get the first page.
last_page   Given the current page, get the last page.

Doesn't work with Dotenv

Not sure if it's Dotenv, but I've noticed that when I use that to set my ENV variables, it doesn't seem to notice them in the mix config file.

Bypass with ExTwilio

Hey guys,

What's the implementation to test ExTwilio? Been trying to figure out how to test around it, but I keep being given:

"The requested resource /2010-04-01/Accounts/test/Messages.json was not found"

My config for config/test.exs is as follows:

use Mix.Config

config :ex_twilio,
  account_sid: "test",
  auth_token: "test"

I want to pass a Bypass host to Twilio, but I can't figure out how that would happen with this library. I'm also trying to get a message to be created with the config given and that's proving to be quite problematic.

Looking for help on this :)


Bypass: https://github.com/PSPDFKit-labs/bypass

Lack of domain when running ExTwilio.Call.all()

when you run ExTwilio.Call.all() to look up all previous calls, it went error due to lack of domain, the error message :

(HTTPotion.HTTPError) {:EXIT, {:badarg, {:gen_server, :call, [#PID<0.401.0>, {:send_req, {{:url, 'http:///2010-04-01/Accounts/xxxxx/Calls.json?PageSize=50&Page=1&PageToken=xxxxx', [], 80, :undefined, :undefined, '/2010-04-01/Accounts/xxxxx/Calls.json?PageSize=50&Page=1&PageToken=xxxxx', :http, :hostname}, [{'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'}], :get, "", [basic_auth: {'xxxxx', 'xxxx'}], 5000}}, 5000]}}}

if I add domain with that {:url} address, everything works.

protocol String.Chars not implemented for %{"mms" => false, "sms" => false, "voice" => true}

Hi,

I am trying to update a phone number:

{:ok, phone} = ExTwilio.IncomingPhoneNumber.find(phone_sid, account: user.twilio_sid)

{:ok, updated_phone} = ExTwilio.IncomingPhoneNumber.update(
      phone.sid,
      %{ phone | voice_method: "GET", voice_url: @incoming_url}
 )

But I get this error.

** (exit) an exception was raised:
    ** (Protocol.UndefinedError) protocol String.Chars not implemented for %{"mms" => false, "sms" => false, "voice" => true}
        (elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1
        (elixir) lib/string/chars.ex:17: String.Chars.to_string/1
        (elixir) lib/uri.ex:105: URI.encode_kv_pair/1
        (elixir) lib/enum.ex:1216: anonymous fn/4 in Enum.map_join/3
        (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
        (elixir) lib/enum.ex:1214: Enum.map_join/3
        (ex_twilio) lib/ex_twilio/api.ex:90: ExTwilio.Api.do_update/4
        (kokokog) web/controllers/api/incoming_phone_controller.ex:30: Kokokog.Api.IncomingPhonesController.create/2
        (kokokog) web/controllers/api/incoming_phone_controller.ex:1: Kokokog.Api.IncomingPhonesController.action/2
        (kokokog) web/controllers/api/incoming_phone_controller.ex:1: Kokokog.Api.IncomingPhonesController.phoenix_controller_pipeline/2
        (kokokog) lib/kokokog/endpoint.ex:1: Kokokog.Endpoint.instrument/4
        (kokokog) lib/phoenix/router.ex:261: Kokokog.Router.dispatch/2
        (kokokog) web/router.ex:1: Kokokog.Router.do_call/2
        (kokokog) lib/kokokog/endpoint.ex:1: Kokokog.Endpoint.phoenix_pipeline/1
        (kokokog) lib/plug/debugger.ex:122: Kokokog.Endpoint."call (overridable 3)"/2
        (kokokog) lib/kokokog/endpoint.ex:1: Kokokog.Endpoint.call/2
        (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
        (cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

Am I doing something wrong ?

Best regards

Error on sending messages

I keep getting this error when attempting to create a message. I'd appreciate some guidance.

iex(11)> ExTwilio.Message.create(%{from: "+14782200451", to: "xxx", body: "test"})
** (HTTPotion.HTTPError) {:EXIT, {:function_clause, [{:ibrowse, :ensure_bin, [%{body: "test", from: "+14782200452", to: "xxx"}], [file: 'src/ibrowse.erl', line: 522]}, {:ibrowse, :do_send_req, 7, [file: 'src/ibrowse.erl', line: 475]}, {:ibrowse, :try_routing_request, 14, [file: 'src/ibrowse.erl', line: 366]}, {ExTwilio.Api, :request, 3, [file: 'lib/ex_twilio/api.ex', line: 19]}, {ExTwilio.Api, :create, 3, [file: 'lib/ex_twilio/api.ex', line: 65]}, {:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 670]}, {:elixir, :erl_eval, 3, [file: 'src/elixir.erl', line: 215]}, {:elixir, :eval_forms, 4, [file: 'src/elixir.erl', line: 203]}, {IEx.Evaluator, :handle_eval, 6, [file: 'lib/iex/evaluator.ex', line: 135]}, {IEx.Evaluator, :do_eval, 4, [file: 'lib/iex/evaluator.ex', line: 128]}, {IEx.Evaluator, :eval, 4, [file: 'lib/iex/evaluator.ex', line: 108]}, {IEx.Evaluator, :loop, 3, [file: 'lib/iex/evaluator.ex', line: 27]}, {IEx.Evaluator, :init, 3, [file: 'lib/iex/evaluator.ex', line: 18]}]}}
    lib/ex_twilio/api.ex:19: ExTwilio.Api.handle_response/1
    lib/ex_twilio/api.ex:65: ExTwilio.Api.create/3

Create tests for all Resource modules

Each module should have the following tests:

  • Doctests for any custom methods
  • Verify that all the methods that are supposed to be imported from Resource are in fact defined

202 http status code is handled as error

Twilio complete-room(update room) API returns 202 http status, while Parser.parse will handle 202 status as a error.
https://github.com/danielberkompas/ex_twilio/blob/master/lib/ex_twilio/parser.ex#L99-L102

I think it should return :ok just like 204 status.

e.g)

sid = "YOUR SID"
ExTwilio.Api.post!("https://video.twilio.com/v1/Rooms/#{sid}", %{status: "completed"})
#=>
%HTTPoison.Response{body: "{\"status\": \"completed\", \"unique_name\": \"<<ROOM SID>>\", \"date
_updated\": \"2018-05-21T19:37:53Z\", \"video_codecs\": [\"H264\"], \"max_participants\": 50, \"record_participants_on_connect\": true,
\"enable_turn\": true, \"account_sid\": \"<<ACOUNT SID>>\", \"url\": \"https://video.twilio.com/v1/Rooms/<<ROOM SID>>\",
\"end_time\": \"2018-05-21T19:38:31Z\", \"sid\": \"<<ROOM SID>>\", \"duration\": 39, \"
date_created\": \"2018-05-21T19:37:52Z\", \"media_region\": \"us1\", \"type\": \"group\", \"status_callback_method\": \"POST\", \"status
_callback\": \"https://pjlee.localtunnel.me/hooks/twilio/rooms\", \"links\": {\"recordings\": \"https://video.twilio.com/v1/Rooms/<<ROOM SID>>/Recordings\",
\"participants\": \"https://video.twilio.com/v1/Rooms/<<ROOM SID>>/Part
icipants\"}}",
headers: [{"Access-Control-Allow-Credentials", "true"},
 {"Access-Control-Allow-Headers",
  "Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since"},
 {"Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS"},
 {"Access-Control-Allow-Origin", "*"},
 {"Access-Control-Expose-Headers", "ETag"},
 {"Content-Type", "application/json"},
 {"Date", "Mon, 21 May 2018 19:38:31 GMT"},
 {"Twilio-Concurrent-Requests", "1"}, {"Twilio-Request-Duration", "0.020"},
 {"Twilio-Request-Id", "RQ0011b71af2b545f18b15c76d3f02dbbb"},
 {"X-Powered-By", "AT-5000"}, {"X-Shenanigans", "none"},
 {"Content-Length", "849"}, {"Connection", "keep-alive"}],
request_url: "https://video.twilio.com/v1/Rooms/<<ROOM SID>>",
status_code: 202}

PR: #98

problem with AvailablePhoneNumbers.all

This is the error I get with ExTwilio.AvailablePhoneNumber.all()

** (Protocol.UndefinedError) protocol Enumerable not implemented for nil. This protocol is implemented for: Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Range, Stream
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:141: Enumerable.reduce/3
    (elixir) lib/stream.ex:1411: Stream.do_enum_resource/6
    (elixir) lib/enum.ex:1919: Enum.reverse/1
    (elixir) lib/enum.ex:2588: Enum.to_list/1
    (elixir) lib/enum.ex:1163: Enum.into/2
    (ex_twilio) lib/ex_twilio/resources/available_phone_number.ex:20: ExTwilio.AvailablePhoneNumber.all/1

The problem seems to be because of the way ExTwilio is expecting the body to be. The response body has the following structure:

{
	"uri": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers.json",
	"countries": [{
		"country_code": "IL",
		"country": "Israel",
		"uri": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/IL.json",
		"beta": false,
		"subresource_uris": {
			"local": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/IL/Local.json",
			"toll_free": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/IL/TollFree.json",
			"mobile": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/IL/Mobile.json"
		}
	}, {
		"country_code": "US",
		"country": "United States",
		"uri": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/US.json",
		"beta": false,
		"subresource_uris": {
			"local": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/US/Local.json",
			"toll_free": "/2010-04-01/Accounts/AC6fc00e901b08cf09d865ba437f8ae0d1/AvailablePhoneNumbers/US/TollFree.json"
		}
	}]
}

Looks like the implementation would try to look at available_phone_numbers key under the response but the result does not have that.

Also, I am not sure how we would go about fixing this esp. it would be probably good to generate ExTwilio.AvailablePhoneNumbers.US.all() and so

2 Factor Authentication

Hi, I never used twilio before, so not sure how to setup up two factor authentication. If you have an example of that would be great. If not could you may be just give some hints on how to approach that

Thx

Message.create() works in v0.6.0 and broken in v0.6.1

I'm seeing this result in v0.6.1

>> alias ExTwilio.Message
>> ExTwilio.Message.create(%Message{from: "+19992345678", to: "+19998765432", body: "Hello"})
{:error, "The Messaging Service Sid  is invalid.", 400}

The above works in v0.6.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.