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.
Files changed (45) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +6 -3
  5. data/Gemfile.lock +35 -1
  6. data/README.md +48 -4
  7. data/Rakefile +3 -1
  8. data/lib/sendgrid/api.rb +3 -2
  9. data/lib/sendgrid/api/client.rb +27 -0
  10. data/lib/sendgrid/api/entities/entity.rb +83 -0
  11. data/lib/sendgrid/api/entities/profile.rb +14 -0
  12. data/lib/sendgrid/api/entities/response.rb +21 -0
  13. data/lib/sendgrid/api/entities/stats.rb +14 -0
  14. data/lib/sendgrid/api/rest/errors/error.rb +60 -0
  15. data/lib/sendgrid/api/rest/resource.rb +56 -0
  16. data/lib/sendgrid/api/rest/response/parse_error.rb +19 -0
  17. data/lib/sendgrid/api/rest/response/parse_json.rb +18 -0
  18. data/lib/sendgrid/api/service.rb +23 -0
  19. data/lib/sendgrid/api/version.rb +2 -2
  20. data/lib/sendgrid/api/web/profile.rb +38 -0
  21. data/lib/sendgrid/api/web/stats.rb +36 -0
  22. data/sendgrid-api.gemspec +4 -1
  23. data/spec/fixtures/forbidden.json +3 -0
  24. data/spec/fixtures/profile.json +18 -0
  25. data/spec/fixtures/stats.json +50 -0
  26. data/spec/fixtures/success.json +3 -0
  27. data/spec/fixtures/unauthorized.json +6 -0
  28. data/spec/sendgrid/api/client_spec.rb +22 -0
  29. data/spec/sendgrid/api/entities/entity_spec.rb +279 -0
  30. data/spec/sendgrid/api/entities/profile_spec.rb +26 -0
  31. data/spec/sendgrid/api/entities/response_spec.rb +28 -0
  32. data/spec/sendgrid/api/entities/stats_spec.rb +25 -0
  33. data/spec/sendgrid/api/rest/errors/error_spec.rb +97 -0
  34. data/spec/sendgrid/api/rest/resource_spec.rb +143 -0
  35. data/spec/sendgrid/api/rest/response/parse_error_spec.rb +39 -0
  36. data/spec/sendgrid/api/rest/response/parse_json_spec.rb +45 -0
  37. data/spec/sendgrid/api/service_spec.rb +44 -0
  38. data/spec/sendgrid/api/version_spec.rb +2 -2
  39. data/spec/sendgrid/api/web/profile_spec.rb +126 -0
  40. data/spec/sendgrid/api/web/stats_spec.rb +100 -0
  41. data/spec/spec_helper.rb +21 -0
  42. data/spec/support/helpers.rb +15 -0
  43. data/spec/support/mock.rb +26 -0
  44. data/spec/support/shared_examples.rb +11 -0
  45. metadata +78 -9
data/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
+ *.gem
1
2
  .bundle
2
3
  vendor
4
+ coverage
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --format documentation
3
+ --order random
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
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
- end
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
@@ -1,13 +1,32 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sendgrid-api (0.0.1)
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::Api
1
+ # Sendgrid::API
2
+
3
+ [![Build Status](https://secure.travis-ci.org/renatosnrg/sendgrid-api.png?branch=master)][gem]
4
+ [![Code Climate](https://codeclimate.com/github/renatosnrg/sendgrid-api.png)][codeclimate]
5
+ [![Coverage Status](https://coveralls.io/repos/renatosnrg/sendgrid-api/badge.png?branch=master)][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
- ## Usage
37
+ ## Configuration
38
+
39
+ ```ruby
40
+ client = Sendgrid::API::Client.new('YOUR_USER', 'YOUR_KEY')
41
+ ```
20
42
 
21
- TODO
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
@@ -1,6 +1,7 @@
1
- require "sendgrid/api/version"
1
+ require 'sendgrid/api/version'
2
+ require 'sendgrid/api/client'
2
3
 
3
4
  module Sendgrid
4
- module Api
5
+ module API
5
6
  end
6
7
  end
@@ -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