sendgrid-api 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +6 -3
- data/Gemfile.lock +35 -1
- data/README.md +48 -4
- data/Rakefile +3 -1
- data/lib/sendgrid/api.rb +3 -2
- data/lib/sendgrid/api/client.rb +27 -0
- data/lib/sendgrid/api/entities/entity.rb +83 -0
- data/lib/sendgrid/api/entities/profile.rb +14 -0
- data/lib/sendgrid/api/entities/response.rb +21 -0
- data/lib/sendgrid/api/entities/stats.rb +14 -0
- data/lib/sendgrid/api/rest/errors/error.rb +60 -0
- data/lib/sendgrid/api/rest/resource.rb +56 -0
- data/lib/sendgrid/api/rest/response/parse_error.rb +19 -0
- data/lib/sendgrid/api/rest/response/parse_json.rb +18 -0
- data/lib/sendgrid/api/service.rb +23 -0
- data/lib/sendgrid/api/version.rb +2 -2
- data/lib/sendgrid/api/web/profile.rb +38 -0
- data/lib/sendgrid/api/web/stats.rb +36 -0
- data/sendgrid-api.gemspec +4 -1
- data/spec/fixtures/forbidden.json +3 -0
- data/spec/fixtures/profile.json +18 -0
- data/spec/fixtures/stats.json +50 -0
- data/spec/fixtures/success.json +3 -0
- data/spec/fixtures/unauthorized.json +6 -0
- data/spec/sendgrid/api/client_spec.rb +22 -0
- data/spec/sendgrid/api/entities/entity_spec.rb +279 -0
- data/spec/sendgrid/api/entities/profile_spec.rb +26 -0
- data/spec/sendgrid/api/entities/response_spec.rb +28 -0
- data/spec/sendgrid/api/entities/stats_spec.rb +25 -0
- data/spec/sendgrid/api/rest/errors/error_spec.rb +97 -0
- data/spec/sendgrid/api/rest/resource_spec.rb +143 -0
- data/spec/sendgrid/api/rest/response/parse_error_spec.rb +39 -0
- data/spec/sendgrid/api/rest/response/parse_json_spec.rb +45 -0
- data/spec/sendgrid/api/service_spec.rb +44 -0
- data/spec/sendgrid/api/version_spec.rb +2 -2
- data/spec/sendgrid/api/web/profile_spec.rb +126 -0
- data/spec/sendgrid/api/web/stats_spec.rb +100 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/helpers.rb +15 -0
- data/spec/support/mock.rb +26 -0
- data/spec/support/shared_examples.rb +11 -0
- metadata +78 -9
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gemspec
|
4
|
-
|
5
3
|
group :development do
|
6
4
|
gem "bundler", "~> 1.3"
|
7
5
|
gem "rake"
|
@@ -9,4 +7,9 @@ end
|
|
9
7
|
|
10
8
|
group :test do
|
11
9
|
gem "rspec", "~> 2.14.1"
|
12
|
-
|
10
|
+
gem "coveralls", "~> 0.7.0", :require => false
|
11
|
+
gem "simplecov", "~> 0.7.1", :require => false
|
12
|
+
gem "webmock", "~> 1.15.0"
|
13
|
+
end
|
14
|
+
|
15
|
+
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,32 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sendgrid-api (0.0.
|
4
|
+
sendgrid-api (0.0.2)
|
5
|
+
faraday (~> 0.8.8)
|
6
|
+
json (~> 1.8.0)
|
5
7
|
|
6
8
|
GEM
|
7
9
|
remote: https://rubygems.org/
|
8
10
|
specs:
|
11
|
+
addressable (2.3.5)
|
12
|
+
coveralls (0.7.0)
|
13
|
+
multi_json (~> 1.3)
|
14
|
+
rest-client
|
15
|
+
simplecov (>= 0.7)
|
16
|
+
term-ansicolor
|
17
|
+
thor
|
18
|
+
crack (0.4.1)
|
19
|
+
safe_yaml (~> 0.9.0)
|
9
20
|
diff-lcs (1.2.4)
|
21
|
+
faraday (0.8.8)
|
22
|
+
multipart-post (~> 1.2.0)
|
23
|
+
json (1.8.0)
|
24
|
+
mime-types (1.25)
|
25
|
+
multi_json (1.8.0)
|
26
|
+
multipart-post (1.2.0)
|
10
27
|
rake (10.1.0)
|
28
|
+
rest-client (1.6.7)
|
29
|
+
mime-types (>= 1.16)
|
11
30
|
rspec (2.14.1)
|
12
31
|
rspec-core (~> 2.14.0)
|
13
32
|
rspec-expectations (~> 2.14.0)
|
@@ -16,12 +35,27 @@ GEM
|
|
16
35
|
rspec-expectations (2.14.3)
|
17
36
|
diff-lcs (>= 1.1.3, < 2.0)
|
18
37
|
rspec-mocks (2.14.3)
|
38
|
+
safe_yaml (0.9.7)
|
39
|
+
simplecov (0.7.1)
|
40
|
+
multi_json (~> 1.0)
|
41
|
+
simplecov-html (~> 0.7.1)
|
42
|
+
simplecov-html (0.7.1)
|
43
|
+
term-ansicolor (1.2.2)
|
44
|
+
tins (~> 0.8)
|
45
|
+
thor (0.18.1)
|
46
|
+
tins (0.11.0)
|
47
|
+
webmock (1.15.0)
|
48
|
+
addressable (>= 2.2.7)
|
49
|
+
crack (>= 0.3.2)
|
19
50
|
|
20
51
|
PLATFORMS
|
21
52
|
ruby
|
22
53
|
|
23
54
|
DEPENDENCIES
|
24
55
|
bundler (~> 1.3)
|
56
|
+
coveralls (~> 0.7.0)
|
25
57
|
rake
|
26
58
|
rspec (~> 2.14.1)
|
27
59
|
sendgrid-api!
|
60
|
+
simplecov (~> 0.7.1)
|
61
|
+
webmock (~> 1.15.0)
|
data/README.md
CHANGED
@@ -1,7 +1,25 @@
|
|
1
|
-
# Sendgrid::
|
1
|
+
# Sendgrid::API
|
2
|
+
|
3
|
+
[][gem]
|
4
|
+
[][codeclimate]
|
5
|
+
[][coveralls]
|
6
|
+
|
7
|
+
[gem]: http://travis-ci.org/renatosnrg/sendgrid-api
|
8
|
+
[codeclimate]: https://codeclimate.com/github/renatosnrg/sendgrid-api
|
9
|
+
[coveralls]: https://coveralls.io/r/renatosnrg/sendgrid-api
|
2
10
|
|
3
11
|
A Ruby interface to the SendGrid API.
|
4
12
|
|
13
|
+
## API Coverage
|
14
|
+
|
15
|
+
The SendGrid API is being covered on demand. The next APIs to be supported are the complete [Marketing Email API](http://sendgrid.com/docs/API_Reference/Marketing_Emails_API/index.html) and [Mail](http://sendgrid.com/docs/API_Reference/Web_API/mail.html) (Web API).
|
16
|
+
|
17
|
+
Check which SendGrid APIs are currently being covered by this gem:
|
18
|
+
|
19
|
+
[https://github.com/renatosnrg/sendgrid-api/wiki/SendGrid-API-Coverage][coverage]
|
20
|
+
|
21
|
+
[coverage]: https://github.com/renatosnrg/sendgrid-api/wiki/SendGrid-API-Coverage
|
22
|
+
|
5
23
|
## Installation
|
6
24
|
|
7
25
|
Add this line to your application's Gemfile:
|
@@ -16,14 +34,40 @@ Or install it yourself as:
|
|
16
34
|
|
17
35
|
$ gem install sendgrid-api
|
18
36
|
|
19
|
-
##
|
37
|
+
## Configuration
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
client = Sendgrid::API::Client.new('YOUR_USER', 'YOUR_KEY')
|
41
|
+
```
|
20
42
|
|
21
|
-
|
43
|
+
## Usage Examples
|
44
|
+
|
45
|
+
**Get your SendGrid Profile**
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
profile = client.profile.get
|
49
|
+
```
|
50
|
+
|
51
|
+
**Modify your SendGrid Profile**
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
profile = Sendgrid::API::Entities::Profile.new(:first_name => 'Your first name',
|
55
|
+
:last_name => 'Your last name')
|
56
|
+
response = client.profile.set(profile)
|
57
|
+
```
|
58
|
+
|
59
|
+
**Get Advanced Statistics**
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
stats = client.stats.advanced(:start_date => '2013-01-01', :data_type => 'global')
|
63
|
+
```
|
22
64
|
|
23
65
|
## Contributing
|
24
66
|
|
67
|
+
If you want to contribute to cover more APIs or improve something already implemented, follow these steps:
|
68
|
+
|
25
69
|
1. Fork it
|
26
70
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
+
3. Commit your changes - do not forget tests (`git commit -am 'Add some feature'`)
|
28
72
|
4. Push to the branch (`git push origin my-new-feature`)
|
29
73
|
5. Create new Pull Request
|
data/Rakefile
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
|
4
|
-
RSpec::Core::RakeTask.new(:spec)
|
4
|
+
RSpec::Core::RakeTask.new(:spec, :tag) do |t, task_args|
|
5
|
+
t.rspec_opts = "--tag #{task_args[:tag]}" if task_args[:tag]
|
6
|
+
end
|
5
7
|
|
6
8
|
task :default => :spec
|
7
9
|
task :test => :spec
|
data/lib/sendgrid/api.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sendgrid/api/rest/resource'
|
2
|
+
require 'sendgrid/api/web/profile'
|
3
|
+
require 'sendgrid/api/web/stats'
|
4
|
+
|
5
|
+
module Sendgrid
|
6
|
+
module API
|
7
|
+
class Client
|
8
|
+
|
9
|
+
include Web::Profile
|
10
|
+
include Web::Stats
|
11
|
+
|
12
|
+
attr_reader :user, :key
|
13
|
+
|
14
|
+
def initialize(user, key)
|
15
|
+
@user = user
|
16
|
+
@key = key
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def resource
|
22
|
+
@resource ||= REST::Resource.new(user, key)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Sendgrid
|
4
|
+
module API
|
5
|
+
module Entities
|
6
|
+
class Entity
|
7
|
+
|
8
|
+
attr_reader :attributes
|
9
|
+
|
10
|
+
def initialize(attributes = {})
|
11
|
+
@attributes = sanitize_attributes(attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json
|
15
|
+
as_json.to_json
|
16
|
+
end
|
17
|
+
|
18
|
+
def as_json
|
19
|
+
attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(method, *args, &block)
|
23
|
+
setter = method.to_s.gsub(/=$/, '').to_sym
|
24
|
+
if has_attribute?(method)
|
25
|
+
attributes[method]
|
26
|
+
elsif has_attribute?(setter)
|
27
|
+
attributes[setter] = args.first
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def respond_to?(method, include_private = false)
|
34
|
+
super || has_attribute?(method)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def has_attribute?(attribute)
|
40
|
+
self.class.attributes.include?(attribute)
|
41
|
+
end
|
42
|
+
|
43
|
+
def sanitize_attributes(attributes)
|
44
|
+
attributes.reject { |key, value| !has_attribute?(key) }
|
45
|
+
end
|
46
|
+
|
47
|
+
class << self
|
48
|
+
|
49
|
+
# Instantiate the entity from API response body.
|
50
|
+
# Can generate multiple entities if response is an Array.
|
51
|
+
def from_response(response)
|
52
|
+
body = response.body
|
53
|
+
if body.is_a?(Array)
|
54
|
+
body.map { |item| new(item) }
|
55
|
+
elsif body.is_a?(Hash)
|
56
|
+
new(body)
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Add attributes to the entity
|
63
|
+
def attribute(*args)
|
64
|
+
@attributes = attributes
|
65
|
+
@attributes += args
|
66
|
+
@attributes.uniq!
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get the entity attributes
|
70
|
+
def attributes
|
71
|
+
@attributes ||= []
|
72
|
+
end
|
73
|
+
|
74
|
+
def clear_attributes
|
75
|
+
@attributes = []
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'sendgrid/api/entities/entity'
|
2
|
+
|
3
|
+
module Sendgrid
|
4
|
+
module API
|
5
|
+
module Entities
|
6
|
+
class Profile < Entity
|
7
|
+
|
8
|
+
attribute :username, :email, :active, :first_name, :last_name, :address,
|
9
|
+
:address2, :city, :state, :zip, :country, :phone, :website, :website_access
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'sendgrid/api/entities/entity'
|
2
|
+
|
3
|
+
module Sendgrid
|
4
|
+
module API
|
5
|
+
module Entities
|
6
|
+
class Response < Entity
|
7
|
+
|
8
|
+
attribute :message, :errors
|
9
|
+
|
10
|
+
def success?
|
11
|
+
message == 'success'
|
12
|
+
end
|
13
|
+
|
14
|
+
def error?
|
15
|
+
message == 'error'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'sendgrid/api/entities/entity'
|
2
|
+
|
3
|
+
module Sendgrid
|
4
|
+
module API
|
5
|
+
module Entities
|
6
|
+
class Stats < Entity
|
7
|
+
|
8
|
+
attribute :delivered, :request, :unique_open, :unique_click, :processed, :date, :open, :click,
|
9
|
+
:blocked, :spamreport, :drop, :bounce, :deferred
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Sendgrid
|
2
|
+
module API
|
3
|
+
module REST
|
4
|
+
module Errors
|
5
|
+
|
6
|
+
class Error < StandardError
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def from_response(env)
|
11
|
+
status_error(env) || body_error(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def status_error(env)
|
17
|
+
body = env[:body]
|
18
|
+
status = env[:status].to_i
|
19
|
+
if status != 200
|
20
|
+
message = body[:error] if body.is_a?(Hash)
|
21
|
+
error_class(status).new(message)
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def body_error(env)
|
28
|
+
body = env[:body]
|
29
|
+
if body.is_a?(Hash) && body.has_key?(:error)
|
30
|
+
status = body[:error][:code]
|
31
|
+
message = body[:error][:message]
|
32
|
+
error_class(status).new(message)
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def error_class(status)
|
39
|
+
Errors::CODES[status] || Errors::Unknown
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class BadRequest < Error; end
|
47
|
+
class Unauthorized < Error; end
|
48
|
+
class Forbidden < Error; end
|
49
|
+
class Unknown < Error; end
|
50
|
+
|
51
|
+
CODES = {
|
52
|
+
400 => BadRequest,
|
53
|
+
401 => Unauthorized,
|
54
|
+
403 => Forbidden,
|
55
|
+
}.freeze
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'sendgrid/api/rest/response/parse_json'
|
3
|
+
require 'sendgrid/api/rest/response/parse_error'
|
4
|
+
|
5
|
+
module Sendgrid
|
6
|
+
module API
|
7
|
+
module REST
|
8
|
+
class Resource
|
9
|
+
|
10
|
+
attr_reader :user, :key
|
11
|
+
|
12
|
+
ENDPOINT = 'https://sendgrid.com/api'.freeze
|
13
|
+
|
14
|
+
def initialize(user, key)
|
15
|
+
@user = user
|
16
|
+
@key = key
|
17
|
+
end
|
18
|
+
|
19
|
+
def post(url, params = {})
|
20
|
+
request(:post, url, params)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def request(method, url, params = {})
|
26
|
+
params.merge!(authentication_params)
|
27
|
+
connection.send(method, url, params)
|
28
|
+
rescue Faraday::Error::ClientError, JSON::ParserError
|
29
|
+
raise Errors::Unknown
|
30
|
+
end
|
31
|
+
|
32
|
+
def middleware
|
33
|
+
@middleware ||= Faraday::Builder.new do |builder|
|
34
|
+
# form-encode POST params
|
35
|
+
builder.request :url_encoded
|
36
|
+
# Parse response errors
|
37
|
+
builder.use Response::ParseError
|
38
|
+
# Parse JSON response bodies
|
39
|
+
builder.use Response::ParseJson
|
40
|
+
# Set Faraday's HTTP adapter
|
41
|
+
builder.adapter Faraday.default_adapter
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def connection
|
46
|
+
@connection ||= Faraday.new(ENDPOINT, :builder => middleware)
|
47
|
+
end
|
48
|
+
|
49
|
+
def authentication_params
|
50
|
+
{ :api_user => @user, :api_key => @key }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|