I'm developing a web service (in Ruby) which needs to do a number of different things for each message it receives.
Before my web service can process a message it must do different things:
I'm thinking about implementing a filter/composite filter architecture where each step/phase is a filter. For instance, I could have these filters
Each filter should be possible to reject a message, so I'm considering that a filter should raise/throw exceptions.
This will give a lot of flexibility and hopefully a codebase that are easy to understand.
How would you did this? And what are pros and cons of above design?
I would leave Exceptions for the cases when the filter itself actually broke down (e.g blacklist not available etc) and indicate the valid/invalid state either by true/false
return values or, as you also suggested, throwing a tag.
If you don't want to stop at first failure, but execute all filters anyway, you should choose the boolean return type and conjunct them together (success &= next_filter(msg)
)
If I understood your situation correctly, the filter can both modify the message or check some other source for validity (e.g blacklist).
So I would do it like this:
module MessageFilters
EmailValidator = ->(msg) do
throw :failure unless msg.txt =~ /@/
end
HTMLSanitizer = ->(msg) do
# this filter only modifies message, doesn't throw anything
# msg.text.remove_all_html!
end
end
class Message
attr_accessor :filters
def initialize
@filters = []
end
def execute_filters!
begin
catch(:failure) do
filters.each{|f| f.call self}
true # if all filters pass, this is returned, else nil
end
rescue => e
# Handle filter errors
end
end
end
message = Message.new
message.filters << MessageFilters::EmailValidator
message.filters << MessageFilters::HTMLSanitizer
success = message.execute_filters! # returns either true or nil