Skip to content

Commit f42133c

Browse files
authored
Merge pull request #49 from sarco3t/contacts-api
Contacts API
2 parents c53f606 + 825b934 commit f42133c

14 files changed

+1430
-34
lines changed

examples/contacts_api.rb

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
require 'mailtrap'
2+
3+
client = Mailtrap::Client.new(api_key: 'your-api-key')
4+
contact_lists = Mailtrap::ContactListsAPI.new 3229, client
5+
contacts = Mailtrap::ContactsAPI.new 3229, client
6+
contact_fields = Mailtrap::ContactFieldsAPI.new 3229, client
7+
8+
# Set your API credentials as environment variables
9+
# export MAILTRAP_API_KEY='your-api-key'
10+
# export MAILTRAP_ACCOUNT_ID=your-account-id
11+
12+
# contact_lists = Mailtrap::ContactListsAPI.new
13+
# contacts = Mailtrap::ContactsAPI.new
14+
# contact_fields = Mailtrap::ContactFieldsAPI.new
15+
16+
# Create new contact list
17+
list = contact_lists.create(name: 'Test List')
18+
# => ContactList.new(id: 1, name: 'Test List')
19+
20+
# Get all contact lists
21+
contact_lists.list
22+
# => [ContactList.new(id: 1, name: 'Test List')]
23+
24+
# Update contact list
25+
contact_lists.update(list.id, name: 'Test List Updated')
26+
# => ContactList.new(id: 1, name: 'Test List Updated')
27+
28+
# Get contact list
29+
list = contact_lists.get(list.id)
30+
# => ContactList.new(id: 1, name: 'Test List Updated')
31+
32+
# Create new contact field
33+
field = contact_fields.create(name: 'Nickname', data_type: 'text', merge_tag: 'nickname')
34+
# => ContactField.new(id: 1, name: 'Nickname', data_type: 'text', merge_tag: 'nickname')
35+
36+
# Get all contact fields
37+
contact_fields.list
38+
# => [ContactField.new(id: 1, name: 'Nickname', data_type: 'text', merge_tag: 'nickname')]
39+
40+
# Update contact field
41+
contact_fields.update(field.id, name: 'Nickname 2', merge_tag: 'nickname')
42+
# => ContactField.new(id: 1, name: 'Nickname 2', data_type: 'text', merge_tag: 'nickname')
43+
44+
# Get contact field
45+
field = contact_fields.get(field.id)
46+
# => ContactField.new(id: 1, name: 'Nickname 2', data_type: 'text', merge_tag: 'nickname')
47+
48+
# Create new contact with all possible fields
49+
contact = contacts.create(
50+
51+
fields: { field.merge_tag => 'John Doe' },
52+
list_ids: [list.id]
53+
)
54+
# => Contact.new(
55+
# id: 1,
56+
# email: '[email protected]',
57+
# fields: { 'nickname' => 'John Doe' },
58+
# list_ids: [1],
59+
# status: 'subscribed',
60+
# created_at: 1721212345,
61+
# updated_at: 1721212345
62+
# )
63+
contact.newly_created? # => true
64+
65+
# Get contact
66+
contact = contacts.get(contact.id)
67+
# => Contact.new(
68+
# id: 1,
69+
# email: '[email protected]',
70+
# fields: { 'nickname' => 'John Doe' },
71+
# list_ids: [1],
72+
# status: 'subscribed',
73+
# created_at: 1721212345,
74+
# updated_at: 1721212345
75+
# )
76+
77+
# Update contact using id
78+
updated_contact = contacts.upsert(
79+
contact.id,
80+
81+
fields: { field.merge_tag => 'Jane Doe' }
82+
)
83+
# => Contact.new(
84+
# id: 1,
85+
# email: '[email protected]',
86+
# fields: { 'nickname' => 'Jane Doe' },
87+
# list_ids: [1],
88+
# status: 'subscribed',
89+
# created_at: 1721212345,
90+
# updated_at: 1721212350
91+
# )
92+
updated_contact.newly_created? # => false
93+
94+
# Update contact using email
95+
contacts.upsert(
96+
updated_contact.email,
97+
98+
fields: { field.merge_tag => 'Jane Doe' }
99+
)
100+
# => Contact.new(
101+
# id: 1,
102+
# email: '[email protected]',
103+
# fields: { 'nickname' => 'Jane Doe' },
104+
# list_ids: [1],
105+
# status: 'subscribed',
106+
# created_at: 1721212345,
107+
# updated_at: 1721212355
108+
# )
109+
updated_contact.newly_created? # => false
110+
111+
# Remove contact from lists
112+
contacts.remove_from_lists(contact.id, [list.id])
113+
# => Contact.new(
114+
# id: 1,
115+
# email: '[email protected]',
116+
# fields: { 'nickname' => 'Jane Doe' },
117+
# list_ids: [],
118+
# status: 'subscribed',
119+
# created_at: 1721212345,
120+
# updated_at: 1721212360
121+
# )
122+
123+
# Add contact to lists
124+
contacts.add_to_lists(contact.id, [list.id])
125+
# => Contact.new(
126+
# id: 1,
127+
# email: '[email protected]',
128+
# fields: { 'nickname' => 'Jane Doe' },
129+
# list_ids: [1],
130+
# status: 'subscribed',
131+
# created_at: 1721212345,
132+
# updated_at: 1721212365
133+
# )
134+
135+
# Delete contact
136+
contacts.delete(contact.id)
137+
138+
# Delete contact list
139+
contact_lists.delete(list.id)
140+
141+
# Delete contact field
142+
contact_fields.delete(field.id)

lib/mailtrap.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
require_relative 'mailtrap/errors'
66
require_relative 'mailtrap/version'
77
require_relative 'mailtrap/email_templates_api'
8+
require_relative 'mailtrap/contacts_api'
9+
require_relative 'mailtrap/contact_lists_api'
10+
require_relative 'mailtrap/contact_fields_api'
811

912
module Mailtrap
1013
# @!macro api_errors

lib/mailtrap/base_api.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# frozen_string_literal: true
2+
3+
module Mailtrap
4+
module BaseAPI
5+
attr_reader :account_id, :client
6+
7+
def self.included(base)
8+
base.extend(ClassMethods)
9+
end
10+
11+
module ClassMethods
12+
attr_accessor :supported_options, :response_class
13+
end
14+
15+
# @param account_id [Integer] The account ID
16+
# @param client [Mailtrap::Client] The client instance
17+
# @raise [ArgumentError] If account_id is nil
18+
def initialize(account_id = ENV.fetch('MAILTRAP_ACCOUNT_ID'), client = Mailtrap::Client.new)
19+
raise ArgumentError, 'account_id is required' if account_id.nil?
20+
21+
@account_id = account_id
22+
@client = client
23+
end
24+
25+
private
26+
27+
def supported_options
28+
self.class.supported_options
29+
end
30+
31+
def response_class
32+
self.class.response_class
33+
end
34+
35+
def validate_options!(options, supported_options)
36+
invalid_options = options.keys - supported_options
37+
return if invalid_options.empty?
38+
39+
raise ArgumentError, "invalid options are given: #{invalid_options}, supported_options: #{supported_options}"
40+
end
41+
42+
def build_entity(options, response_class)
43+
response_class.new(options.slice(*response_class.members))
44+
end
45+
46+
def base_get(id)
47+
response = client.get("#{base_path}/#{id}")
48+
handle_response(response)
49+
end
50+
51+
def base_create(options, supported_options_override = supported_options)
52+
validate_options!(options, supported_options_override)
53+
response = client.post(base_path, wrap_request(options))
54+
handle_response(response)
55+
end
56+
57+
def base_update(id, options, supported_options_override = supported_options)
58+
validate_options!(options, supported_options_override)
59+
response = client.patch("#{base_path}/#{id}", wrap_request(options))
60+
handle_response(response)
61+
end
62+
63+
def base_delete(id)
64+
client.delete("#{base_path}/#{id}")
65+
end
66+
67+
def base_list
68+
response = client.get(base_path)
69+
response.map { |item| handle_response(item) }
70+
end
71+
72+
def handle_response(response)
73+
build_entity(response, response_class)
74+
end
75+
76+
def wrap_request(options)
77+
options
78+
end
79+
80+
def base_path
81+
raise NotImplementedError, 'base_path must be implemented in the including class'
82+
end
83+
end
84+
end

lib/mailtrap/contact.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# frozen_string_literal: true
2+
3+
module Mailtrap
4+
# Data Transfer Object for Contact
5+
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/220a54e31e5ca-contact
6+
# @attr_reader id [String] The contact ID
7+
# @attr_reader email [String] The contact's email address
8+
# @attr_reader fields [Hash] Object of fields with merge tags
9+
# @attr_reader list_ids [Array<Integer>] Array of list IDs
10+
# @attr_reader status [String] The contact status (subscribed/unsubscribed)
11+
# @attr_reader created_at [Integer] The creation timestamp
12+
# @attr_reader updated_at [Integer] The last update timestamp
13+
Contact = Struct.new(
14+
:id,
15+
:email,
16+
:fields,
17+
:list_ids,
18+
:status,
19+
:created_at,
20+
:updated_at,
21+
keyword_init: true
22+
) do
23+
def initialize(options)
24+
@action = options[:action]
25+
super(options.except(:action))
26+
end
27+
28+
# @return [Boolean] Whether the contact was newly created
29+
def newly_created?
30+
@action != 'updated'
31+
end
32+
33+
# @return [Hash] The contact attributes as a hash
34+
def to_h
35+
super.compact
36+
end
37+
end
38+
end

lib/mailtrap/contact_field.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module Mailtrap
4+
# Data Transfer Object for Contact Field
5+
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/33efe96c91dcc-get-all-contact-fields
6+
# @attr_reader id [Integer] The contact field ID
7+
# @attr_reader name [String] The name of the contact field (max 80 characters)
8+
# @attr_reader data_type [String] The data type of the field
9+
# Allowed values: text, integer, float, boolean, date
10+
# @attr_reader merge_tag [String] Personalize your campaigns by adding a merge tag.
11+
# This field will be replaced with unique contact details for each recipient (max 80 characters)
12+
ContactField = Struct.new(:id, :name, :data_type, :merge_tag, keyword_init: true) do
13+
# @return [Hash] The contact field attributes as a hash
14+
def to_h
15+
super.compact
16+
end
17+
end
18+
end

lib/mailtrap/contact_fields_api.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'base_api'
4+
require_relative 'contact_field'
5+
6+
module Mailtrap
7+
class ContactFieldsAPI
8+
include BaseAPI
9+
10+
self.supported_options = %i[name data_type merge_tag]
11+
12+
self.response_class = ContactField
13+
14+
# Retrieves a specific contact field
15+
# @param field_id [Integer] The contact field identifier
16+
# @return [ContactField] Contact field object
17+
# @!macro api_errors
18+
def get(field_id)
19+
base_get(field_id)
20+
end
21+
22+
# Creates a new contact field
23+
# @param [Hash] options The parameters to create
24+
# @option options [String] :name The contact field name
25+
# @option options [String] :data_type The data type of the field
26+
# @option options [String] :merge_tag The merge tag of the field
27+
# @return [ContactField] Created contact field object
28+
# @!macro api_errors
29+
# @raise [ArgumentError] If invalid options are provided
30+
def create(options)
31+
base_create(options)
32+
end
33+
34+
# Updates an existing contact field
35+
# @param field_id [Integer] The contact field ID
36+
# @param [Hash] options The parameters to update
37+
# @option options [String] :name The contact field name
38+
# @option options [String] :merge_tag The merge tag of the field
39+
# @return [ContactField] Updated contact field object
40+
# @!macro api_errors
41+
# @raise [ArgumentError] If invalid options are provided
42+
def update(field_id, options)
43+
base_update(field_id, options, %i[name merge_tag])
44+
end
45+
46+
# Deletes a contact field
47+
# @param field_id [Integer] The contact field ID
48+
# @return nil
49+
# @!macro api_errors
50+
def delete(field_id)
51+
base_delete(field_id)
52+
end
53+
54+
# Lists all contact fields for the account
55+
# @return [Array<ContactField>] Array of contact field objects
56+
# @!macro api_errors
57+
def list
58+
base_list
59+
end
60+
61+
private
62+
63+
def base_path
64+
"/api/accounts/#{account_id}/contacts/fields"
65+
end
66+
end
67+
end

lib/mailtrap/contact_list.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
module Mailtrap
4+
# Data Transfer Object for Contact List
5+
# @see https://api-docs.mailtrap.io/docs/mailtrap-api-docs/6ec7a37234af2-contact-list
6+
# @attr_reader id [Integer] The contact list ID
7+
# @attr_reader name [String] The name of the contact list
8+
ContactList = Struct.new(:id, :name, keyword_init: true) do
9+
# @return [Hash] The contact list attributes as a hash
10+
def to_h
11+
super.compact
12+
end
13+
end
14+
end

0 commit comments

Comments
 (0)