new action built-in functions: callAPI

did committed Dec 21, 2016
commit 5d06483c3484b8d79e5d567d983e26d4c566f82f
Showing 5 changed files with 93 additions and 27 deletions
locomotive/steam/services.rb b/lib/locomotive/steam/services.rb +1 -1
@@ @@ -63,7 +63,7 @@ module Locomotive
end
register :action do
- Steam::ActionService.new(current_site, email, content_entry)
+ Steam::ActionService.new(current_site, email, content_entry, external_api)
end
register :content_entry do
locomotive/steam/services/action_service.rb b/lib/locomotive/steam/services/action_service.rb +7 -2
@@ @@ -20,9 +20,10 @@ module Locomotive
allEntries
findEntry
createEntry
- updateEntry)
+ updateEntry
+ callAPI)
- attr_accessor_initialize :site, :email, :content_entry_service
+ attr_accessor_initialize :site, :email, :content_entry_service, :api_service
def run(script, params = {}, liquid_context)
context = Duktape::Context.new
@@ @@ -86,6 +87,10 @@ module Locomotive
-> (type, id_or_slug, attributes) { content_entry_service.update(type, id_or_slug, attributes, true) }
end
+ def call_api_lambda(liquid_context)
+ -> (method, url, options) { api_service.consume(url, (options || {}).with_indifferent_access.merge(method: method)) }
+ end
+
end
end
locomotive/steam/services/external_api_service.rb b/lib/locomotive/steam/services/external_api_service.rb +42 -23
@@ @@ -7,52 +7,71 @@ module Locomotive
include ::HTTParty
+ # Available option keys:
+ # - method
+ # - data
+ # - format
+ # - username / password (basic auth)
+ # - headers
+ # - header_auth
+ # - with_user_agent
+ #
def consume(url, options = {})
- options[:base_uri], path = extract_base_uri_and_path(url)
+ base_uri, path = extract_base_uri_and_path(url)
- options.delete(:format) if options[:format] == 'default'
+ method = (options[:method] || 'GET').to_s.downcase
- # auth ?
- username, password = options.delete(:username), options.delete(:password)
- options[:basic_auth] = { username: username, password: password } if username
+ _options = build_httpparty_options(options, method)
+ _options[:base_uri] = base_uri
- # authorization header ?
- header_auth = options.delete(:header_auth)
- options[:headers] = { 'Authorization' => header_auth } if header_auth
-
- perform_request_to(path, options)
+ perform_request_to(method, path, _options)
end
private
+ def build_httpparty_options(options, method)
+ _options = {}
+
+ # data: body (POST/PUT/PATCH) or query (GET)
+ _options[method == 'get' ? :query : :body] = options[:data] if options[:data]
+
+ # basic auth?
+ username, password = options[:username], options[:password]
+ _options[:basic_auth] = { username: username, password: password } if username
+
+ # headers
+ _options[:headers] = options[:headers] || {}
+ _options[:headers]['Authorization'] = options[:header_auth] if options[:header_auth]
+ _options[:headers]['User-Agent'] = 'LocomotiveCMS' if options[:with_user_agent]
+ _options.delete(:headers) if _options[:headers].blank?
+
+ # format
+ if options.has_key?(:format) && options[:format] != 'default'
+ _options[:format] = options[:format].gsub(/[\'\"]/, '').to_sym
+ end
+
+ _options
+ end
+
def extract_base_uri_and_path(url)
url = HTTParty.normalize_base_uri(url)
uri = URI.parse(url)
path = uri.request_uri || '/'
base_uri = "#{uri.scheme}://#{uri.host}"
- base_uri += ":#{uri.port}" if uri.port != 80
+ base_uri += ":#{uri.port}" if (uri.port != 80 && uri.port != 443)
[base_uri, path]
end
- def perform_request_to(path, options)
- # [DEBUG] puts "[WebService] consuming #{path}, #{options.inspect}"
-
- # sanitize the options
- options[:format] = options[:format].gsub(/[\'\"]/, '').to_sym if options.has_key?(:format)
- if options[:with_user_agent]
- user_agent = { 'User-Agent' => 'LocomotiveCMS' }
- options[:headers] ? options[:headers].merge!(user_agent) : options[:headers] = user_agent
- end
-
- response = self.class.get(path, options)
+ def perform_request_to(method, path, options)
+ response = self.class.send(method.to_sym, path, options)
parsed_response = response.parsed_response
if response.code == 200
HashConverter.to_underscore(parsed_response)
else
- Locomotive::Common::Logger.error "[WebService] consumed #{path}, #{options.inspect}, response = #{response.inspect}"
+ Locomotive::Common::Logger.error "[WebService] consumed [#{method.to_s.upcase}] #{path}, #{options.inspect}, response = #{response.inspect}"
nil
end
end
spec/unit/services/action_service_spec.rb +21 -1
@@ @@ -6,7 +6,8 @@ describe Locomotive::Steam::ActionService do
let(:site) { instance_double('Site', as_json: site_hash ) }
let(:email_service) { instance_double('EmailService') }
let(:entry_service) { instance_double('ContentService') }
- let(:service) { described_class.new(site, email_service, entry_service) }
+ let(:api_service) { instance_double('ExternalAPIService') }
+ let(:service) { described_class.new(site, email_service, entry_service, api_service) }
describe '#run' do
@@ @@ -166,6 +167,25 @@ describe Locomotive::Steam::ActionService do
end
+ describe 'callAPI' do
+
+ let(:script) { "callAPI('POST', 'https://api.stripe.com/v1/charges', { username: 'abcdefghij', data: { token: '123456789' } })" }
+
+ it 'forwards the action to the external api service' do
+ expect(api_service).to receive(:consume).with(
+ 'https://api.stripe.com/v1/charges', {
+ method: 'POST',
+ username: 'abcdefghij',
+ data: {
+ token: '123456789'
+ }
+ }
+ )
+ subject
+ end
+
+ end
+
end
end
spec/unit/services/external_api_service_spec.rb +22 -0
@@ @@ -85,6 +85,28 @@ describe Locomotive::Steam::ExternalAPIService do
end
end
+ describe 'calls an API' do
+
+ let(:url) { 'https://api.stripe.com/v1/charges' }
+ let(:options) {
+ {
+ method: 'POST',
+ data: { email: 'John Doe', source: '1234567', plan: 'monthly' },
+ username: 'abcdefghijkl'
+ }
+ }
+
+ it do
+ expect(service.class).to receive(:post).with('/v1/charges', {
+ base_uri: 'https://api.stripe.com',
+ body: { email: 'John Doe', source: '1234567', plan: 'monthly' },
+ basic_auth: { username: 'abcdefghijkl', password: nil }
+ }).and_return(response)
+ subject
+ end
+
+ end
+
end
end