Skip to content

Commit

Permalink
feat: add notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
adamcooke committed May 20, 2022
1 parent 1c7efcd commit af932dc
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
29 changes: 29 additions & 0 deletions lib/apia/notifications.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module Apia
class Notifications

class << self

def handlers
@handlers ||= []
end

def notify(event, args = {})
handlers.each do |handler|
handler.call(event, args)
end
end

def add_handler(&block)
handlers.push(block)
end

def clear_handlers
@handlers = nil
end

end

end
end
12 changes: 11 additions & 1 deletion lib/apia/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require 'apia/rack_error'
require 'apia/request'
require 'apia/response'
require 'apia/notifications'

module Apia
class Rack
Expand Down Expand Up @@ -91,19 +92,28 @@ def handle_request(env, api_path)
request.endpoint = route.endpoint
request.route = route

start_time = Time.now
response = request.endpoint.execute(request)
end_time = Time.now

Apia::Notifications.notify(:request, { request: request, response: response, time: (end_time - start_time).to_f })

response.rack_triplet
rescue ::StandardError => e
if e.is_a?(RackError) || e.is_a?(Apia::ManifestError)
return e.triplet
end

request_or_nil = defined?(request) ? request : nil

api.definition.exception_handlers.call(e, {
env: env,
api: api,
request: defined?(request) ? request : nil
request: request_or_nil
})

Apia::Notifications.notify(:request_error, { exception: e, request: request_or_nil, api: api, env: env })

if development?
return triplet_for_exception(e)
end
Expand Down
31 changes: 31 additions & 0 deletions spec/specs/apia/notifications_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

require 'spec_helper'
require 'apia/notifications'

RSpec.describe Apia::Notifications do
after do
described_class.clear_handlers
end

describe '.add_handler' do
it 'adds a handler' do
handler = proc {}
described_class.add_handler(&handler)
expect(described_class.handlers).to include handler
end
end

describe '.notify' do
it 'runs each registered handler' do
run = false
described_class.add_handler do |event, args|
run = true
expect(event).to eq :request
expect(args).to eq({ request: 1, response: 2 })
end
described_class.notify(:request, { request: 1, response: 2 })
expect(run).to be true
end
end
end
32 changes: 32 additions & 0 deletions spec/specs/apia/rack_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,24 @@ def call(_env)
expect(result[1]['x-demo']).to eq 'hello'
end

it 'should notify on all requests' do
controller = Apia::Controller.create('Controller') do
endpoint :test do
action do
response.add_header 'x-demo', 'hello'
end
end
end
api = Apia::API.create('MyAPI') do
routes do
get 'test', controller: controller, endpoint: :test
end
end
expect(Apia::Notifications).to receive(:notify).with(:request, { request: Apia::Request, response: Apia::Response, time: Float })
rack = described_class.new(app, api, 'api/v1')
rack.call(::Rack::MockRequest.env_for('/api/v1/test'))
end

it 'should catch rack errors and return an error triplet' do
api = Apia::API.create('MyAPI')
rack = described_class.new(app, api, 'api/v1', development: true)
Expand All @@ -193,6 +211,20 @@ def call(_env)
expect(result[2][0]).to include '{"class":"ZeroDivisionError"'
end

it 'should notify on errors' do
controller = Apia::Controller.create('Controller') do
endpoint :test do
action { 1 / 0 }
end
end
api = Apia::API.create('MyAPI') do
routes { get('test', controller: controller, endpoint: :test) }
end
expect(Apia::Notifications).to receive(:notify).with(:request_error, hash_including({ env: Hash, request: Apia::Request, exception: ZeroDivisionError }))
rack = described_class.new(app, api, 'api/v1', development: true)
rack.call(::Rack::MockRequest.env_for('/api/v1/test'))
end

it 'should catch other errors and return a basic error triplet in non-development mode' do
controller = Apia::Controller.create('Controller') do
endpoint :test do
Expand Down

0 comments on commit af932dc

Please sign in to comment.