Skip to content

Instantly share code, notes, and snippets.

@mberman84
Created December 12, 2014 23:26
Show Gist options
  • Save mberman84/3e596fe37a0b6eaa42ff to your computer and use it in GitHub Desktop.
Save mberman84/3e596fe37a0b6eaa42ff to your computer and use it in GitHub Desktop.
# new api
class Api < Grape::API
version 'v1'
format :json
use Rack::Timeout
rescue_from Rack::Timeout::RequestTimeoutError do |e|
NewRelic::Agent.instance.error_collector.notice_error e,
uri: env["api.endpoint"].request.path,
referer: env["api.endpoint"].request.referer,
request_params: env["api.endpoint"].request.params
Airbrake.notify e
rack_response({ error: "Request Timed Out" }.to_json, 503)
end
before do
logger.info "received API request with #{printable_params}"
authenticate!
end
after do
record_api_history!
"Success"
end
after_validation do
logger.info "validated #{api_function} company_id: #{company.id}"
end
helpers do
def ability
@ability = ApiAbility.new(company)
end
def customer
nil
end
def printable_params
params.except(:route_info).merge(token: token, client: client)
end
def saveable_params
params.except(:route_info)
end
def logger
Rails.logger
end
def token
headers['Token']
end
def publishable_key
headers['Publishable_key']
end
def client
headers['Client']
end
def company
@company ||= Company.find_by_token(token)
end
def company_by_publishable_key
@company_by_publishable_key ||= Company.find_by_publishable_key(publishable_key)
end
def authenticate!
return error!('Bad Token', 401) unless company
return error!('Company inactive', 403) if company.inactive?
return error!('Company cancelled', 403) if company.cancelled?
return error!('No Active Subscription', 403) unless ability.company_is_paid_up?
return error!('Api Disabled For Company', 403) unless ability.can_access_api?
logger.info "authorized #{api_function} company_id: #{company.id} with token #{token}"
end
def record_api_history!
api_history = ApiHistory.new
api_history.params = saveable_params
api_history.api_function = api_function
api_history.company = company
api_history.customer = customer if customer.try(:persisted?)
api_history.client = client
api_history.save
logger.info "processed API #{api_function} company_id: #{company.id}, customer_id: #{customer.id if customer}"
end
def api_function
'not set'
end
end
# changes from /api_create_message
# send token in header 'Token: YOURTOKEN', instead of as a param
# do not base 64 encode properties
# example:
# curl http://localhost:3000/api/v1/customers -X POST \
# -H 'token:3Z9L8xFjeNmXL7Yn-pFJUBoxkVWBbl5o' -H "Content-Type: application/json" \
# -d '{"phone_number": "5555555555", "email": "user@example.com", "first_name": "john", "last_name": "doe", "properties": {"property1": "whateverthismeans"}}'
resource :customers do
helpers do
def customer_phone_number
@phone ||= Helper.format_phone_number(params[:phone_number])
end
def customer
return error!('Malformed Phone Number', 403) if customer_phone_number.nil?
@customer ||= company.customers.find_or_initialize_by(customer_phone_number: customer_phone_number)
end
def api_function
'v1/customers POST'
end
end
desc "Add a new customer. Or update the customer if one already exists with that phone number."
params do
requires :phone_number, type: String, desc: "The customer's phone number (format: 2345678901)"
optional :email, type: String, desc: "The customer's email address"
optional :first_name, type: String, desc: "The customer's first name"
optional :last_name, type: String, desc: "The customer's last name"
optional :properties, type: Hash, desc: "Arbitrary properties to record about the customer"
end
post do
return error!('Trial Customer Limit Reached', 403) if company.active_trial? && !TrialChecker.new(company).within_customer_limit?
return error!('Forbidden', 403) unless ability.can?(:create, customer)
options = {
automated_replies: params['automated_replies'],
properties: params['properties'],
customer_phone_number: customer_phone_number,
company_id: company.id
}
customer.first_name = params['first_name'] if params['first_name']
customer.last_name = params['last_name'] if params['last_name']
customer.email = params['email'] if params['email']
customer.via_api = true
if customer.valid?
UpdateCustomerWorker.perform_async(customer.attributes, options)
status 201
serializer = ApiCustomerSerializer.new(customer)
if properties = params['properties']
serializer.properties = properties
end
serializer
else
return error!('Customer invalid', 422)
end
end
end
resource :phone_numbers do
helpers do
def authenticate!
return error!('Bad Token', 401) unless company_by_publishable_key
return error!('Company inactive', 403) if company_by_publishable_key.inactive?
return error!('Company cancelled', 403) if company_by_publishable_key.cancelled?
return error!('No Active Subscription', 403) unless ability.company_is_paid_up?
return error!('Api Disabled For Company', 403) unless ability.can_access_api?
logger.info "authorized #{api_function} company_id: #{company_by_publishable_key.id} with publishable_key #{publishable_key}"
end
end
desc "Get an available phone number"
get :available do
company_by_publishable_key.open_phone_number_digits
end
end
# changes from /api_create_message
# send token in header 'Token: YOURTOKEN', instead of as a param
# example:
# curl http://localhost:3000/api/v1/messages -X POST \
# -H 'token:YOURTOKEN' -H "Content-Type: application/json" \
# -d '{"text": "hi there", "to": "5555555555"}'
resource :messages do
helpers do
def customer_phone_number
Helper.format_phone_number(params[:to])
end
def message_text
params['text']
end
def customer
return error!('Malformed Phone Number', 403) if customer_phone_number.nil?
begin
@customer ||= company.customers.find_or_create_by(customer_phone_number: customer_phone_number)
rescue ActiveRecord::RecordNotUnique => error
# Try again
@customer ||= company.customers.find_by(customer_phone_number: customer_phone_number)
end
end
def api_function
'v1/messages POST'
end
end
desc "Send a message"
params do
requires :text, type: String, desc: "The message to be sent"
requires :to, type: String,
desc: "The recipient's phone number. A customer will be created with this number if not found."
end
post do
return error!('Trial Message Limit Reached', 403) if company.active_trial? && !TrialChecker.new(company).within_message_limit?
return error!('Forbidden', 403) unless ability.can?(:create, Message)
if customer.subscribed
status 202
MessageService.save_and_send_from_api(
customer_id: customer.id,
full_text: message_text,
company_id: company.id,
user_id: company.admin.id
)
{ to: params[:to], text: message_text, status: 'queued' }
else
status 200
{ to: params[:to], text: message_text, status: 'unsubscribed' }
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment