build status Master (GitLab CI)

Master (Solano CI)

Adparlor::Facebook

The adparlor-facebook gem is a ruby library for interacting with the Facebook ads API. Supporting both REST and batch requests.

Installation

Add this line to your application's Gemfile:

gem 'adparlor-facebook', git: 'https://gitlab.ak-networks.com/adparlor/facebook_ruby_ads_sdk.git'

or locally for development

bundle config local.adparlor-facebook ~/Projects/facebook_ruby_ads_sdk
gem 'adparlor-facebook', branch: 'master'

And then execute:

$ bundle

Usage

Graph API

Once an access token is obtained https://developers.facebook.com/docs/facebook-login/access-tokens you can begin making requests to the GraphApi.

#Get an ad account by the id
account = Adparlor::Facebook::GraphApi::AdAccount.get(account_id, access_token: 'access_token')
account.name #-> 'the account name'
account.account_status #-> 'the account status'

#Get an ad creative  by the id
creative = Adparlor::Facebook::GraphApi::AdCreative.get(creative_id, access_token: 'access_token')
creative.id #-> '11111111111111111'

#The Get method also takes the fields option like the graph api by default only returning the minimal fields
creative = Adparlor::Facebook::GraphApi::AdCreative.get(creative_id, access_token: 'access_token', fields: %w(body image_hash image_url ...))
#OR
creative = Adparlor::Facebook::GraphApi::AdCreative.get(creative_id, access_token: 'access_token', fields: Adparlor::Facebook::GraphApi::AdCreative.fields(:all))
creative.id #-> '11111111111111111'
creative.name #-> 'the creatives name'
creative.thumbnail_url #-> 'https://facebook.com/image...'

#You can also get objects by their edges as referred to in the Facebook documentation
#which returns a memoized array of object types.
account = Adparlor::Facebook::GraphApi::AdAccount.get(account_id, access_token: 'access_token')
account.adcreatives.all #-> [Adparlor::Facebook::GraphApi::AdCreative<...>, Adparlor::Facebook::GraphApi::AdCreative<...>, Adparlor::Facebook::GraphApi::AdCreative<...>, ...]
account.adimages.all #-> [Adparlor::Facebook::GraphApi::AdImage<...>, Adparlor::Facebook::GraphApi::AdImage<...>, Adparlor::Facebook::GraphApi::AdImage<...>, ...]
account.campaigns.all #-> [Adparlor::Facebook::GraphApi::Campaign<...>, Adparlor::Facebook::GraphApi::Campaign<...>, Adparlor::Facebook::GraphApi::Campaign<...>, ...]

#The all method also takes the fields option like the graph api by default only returning the minimal fields
account.adcreatives.all.first #-> Adparlor::Facebook::GraphApi::AdCreative<@id => '1111111111111111'>
account.adcreatives.all(Adparlor::Facebook::GraphApi::AdCreative.fields(:all))).first #-> Adparlor::Facebook::GraphApi::AdCreative<@id='1111111111111111', @body='...', @image_hash='...'>

#The edges also implement create and delete options
account.adimages.delete(hash: '6aec0dd976393abfad84e8f2511960a8') #-> response.body = {"success" => true}

account.adimages.create(source: 'http://www.example.com/url/to/image.png')
#OR
account.adimages.create(source: '/path/to/image.png') #-> response.body = :images => { :url => 'https://facebook.com/image/localtion.png', :hash => 'd0f7567af280e1f6760457ff4df782d8' }

Batch requests

If making large numbers of requests at the same time or requests that depend on each other the batch object can be used.

#The batch api requires an access token in the case some of the requests use different tokens
#or one is not supplied for fallback purposes.
 = Adparlor::Facebook::GraphApi::AdAccount.get(, access_token: 'access_token')
response = .batch do |batch|
  batch.get .id, AdImage, fields: [:id, :name, :hash] # uses the parent objects token
  batch.get .id, Campaign, access_token: .access_token # uses the parent objects token but it is supplied
  batch.get account2.id, AdImage, access_token: account2.access_token, fields: [:id, :name, :height]
end
response #-> [[AdImage, AdImage, ...],[Campaign, Campaign, ...],[AdImage, AdImage, ...]]

#The object can also be created without an account if the requests are all different accounts or non account level objects
#This will use the access token of the first object to be the top level access token
response = Adparlor::Facebook::GraphObject.new.batch do |batch|
  batch.get nil, AdCreative, id: '6666666666666', access_token: 'access_token'
  batch.get nil, AdCreative, id: '7777777777777', access_token: 'access_token'
end

#Posting follows the same style request, files should be accompanied by the source key.
response = .batch do |batch|
  batch.post .id, AdImage, source: 'http://www.example.com/url/for/image.png' # uses the parent objects token
  batch.post account2.id, AdImage, source: 'http://www.example.com/url/for/othe-image.png', access_token: account2.access_token # uses its own token
end
response #-> [AdImage, AdImage]

#Deleting follows the same style request
response = .batch do |batch|
  batch.delete .id, AdImage, hash: 'bee06e2e03f9b5a32419855e2c7a4225'
  batch.delete .id, AdImage, hash: 'd8ebd0caddecb512ec3b782ae9498e13'
end

#You can mix up requests
response = .batch do |batch|
  batch.post .id, AdImage, source: 'http://www.example.com/url/for/image.png'
  batch.post account2.id, AdImage, source: 'http://www.example.com/url/for/othe-image.png', access_token: account2.access_token
  batch.get .id, AdImage, fields: [:id, :name, :hash]
  batch.get .id, Campaign
end
response #-> [AdImage, AdImage, [AdImage, AdImage, ...],[Campaign, Campaign, ...]]

#You can post requests that are dependent on other requests
#In this case the post that another post is dependent on will supply a name to the options parameter
#which is then referred to in dependents posts appropriate column.
#in this case the campaign post gets the name 'create_campaign' the following request refers to it
#using the JSONPath expression format required by the batch api '{result=create_campaign:$.id}'
# for more information visit: https://developers.facebook.com/docs/marketing-api/batch-requests/v2.5
response = .batch do |batch|
  batch.post .id, Campaign,
             { name: 'A Test Campaign', objective: 'LOCAL_AWARENESS', status: 'PAUSED' },
             name: 'create_campaign'
  batch.post .id, AdSet,
             name: 'A Test AdSet', daily_budget: 135, start_time: '00:05:00',
             campaign_id: '{result=create_campaign:$.id}', bid_amount: 150,
             billing_event: 'IMPRESSIONS', optimization_goal: 'REACH',
             targeting: {
               geo_locations: { cities: [{ key: '2418956', radius: 12, distance_unit: 'mile' }] },
               page_types: %w(desktopfeed mobilefeed)
             }, status: 'PAUSED',
             promoted_object: { page_id: your_page_id }
end
response #-> [null, AdSet]

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

License

The gem is available as open source under the terms of the MIT License.

TODO

  • Create requests should probably return an instance of the object instead of the Faraday body
  • ?Delete requests should return true if deleted or error message?
  • Continue to add endpoints
  • More configurable tests for testing live instead of the vcr cassettes.