Chuck Remes
2008-Nov-20 10:53 UTC
[Eventmachine-talk] [Q] need guidance on wrapping an API
I have a socket-based API service I need to consume. I want to wrap
the API up in some nice ruby classes exposed via EM.
The way the API works is it takes an ASCII string of the following form:
RID FS FID FS value FS ... FIDn FS value_n RS
where
RID = record id (integer)
FS = field separator
FID = field id (integer)
value = field value (integer or string)
RS = record separator
The API service returns its results using the same format.
Let''s suppose the API exposes a way to add an item to inventory. I
have a C header file with a bunch of enumerators and it defines
INVENTORY_ADD_ITEM as the integer 7. Further, it takes two fields as
parameters which are also defined as enumerations which are PRODUCT_ID
35 and QUANTITY 54. Assume the field separator is a semi-colon
'';'' and
the record separator is a newline.
A response record will contain record INVENTORY_RESPONSE (44) with
fields PRODUCT_ID (35), QUANTITY (54), MINIMUM_LEVEL (72) and PRICE
(121).
I want to add the product Foo with product id 123456 and a quantity of
1000. The request to the API would look like:
7;35;123456;54;1000
and the response record would look like:
44;35;123456;54;1000;72;500;121;17.85
Over a year ago I wrote a Protocol class for EM that was a subclass of
EM::Connection for a different project. Is that what I should do here?
Ideally I would like to be able call methods on my Protocol that do
the right thing and provide a way to return classes (or Structs) that
expose the returned data.
Continuing the example above, my ruby Protocol class might look
something like this:
class Protocol < LineAndTextProtocol
# assume post_init and other necessary methods are overridden correctly
def initialize
super
@responses = Hash.new { |h, k| h[k] = [] }
end
# convenience method for adding to inventory
def add_to_inventory(product_id, quantity)
request "#{INVENTORY_ADD_ITEM
}#{FS}#{PRODUCT_ID}#{FS}#{product_id}#{FS}#{QUANTITY}#{FS}#{quantity}"
send_data request
end
# convenience method to get oldest inventory response
def inventory_response
@responses[INVENTORY_RESPONSE].unshift unless
@responses[INVENTORY_RESPONSE].empty?
end
def receive_data(data)
super # use LineAndTextProtocol''s method... added here for clarity
end
# override LineAndTextProtocol method
def receive_line(line)
fields = line.split(FS)
case rid = fields.first do
when INVENTORY_RESPONSE
obj = InventoryResponse.new
obj.product_id = fields[2]
obj.quantity = fields[4]
obj.minimum_level = fields[6]
obj.price = fields[8]
@responses[INVENTORY_RESPONSE] << obj
else
puts "do not recognize this record ID [#{fields.first}]"
end
end
end
Is this the right approach? If not, what do you suggest?
cr
take a look in the ''protocols'' directory there''s some example readers in there I believe, though I shouldn''t talk having never really looked at any of them or done anything similar, myself. -=R> Is this the right approach? If not, what do you suggest?If your approach works then go for it. Nobody''s wrong here :) -=R
Chuck Remes
2008-Nov-20 12:00 UTC
[Eventmachine-talk] [Q] need guidance on wrapping an API
On Nov 20, 2008, at 1:48 PM, Roger Pack wrote:> take a look in the ''protocols'' directory there''s some example readers > in there I believe, though I shouldn''t talk having never really looked > at any of them or done anything similar, myself. > -=R > > >> Is this the right approach? If not, what do you suggest? > > If your approach works then go for it. Nobody''s wrong here :)I''ve been going through the HttpClient code in the protocols directory for the last few hours (since I posted my original message). I like the use of Deferrables here but I''d like to see how HttpClient (and Deferrables) is handled in the context of an actual client (or server) program. It''s a little hard to wrap my head around right now since I only see the Protocol definition but I''ll keep banging on it. I''ll search around for some other code that uses EM to use as larger examples. Pointers welcome, of course. cr
Chuck Remes
2008-Nov-20 16:43 UTC
[Eventmachine-talk] [Q] need guidance on wrapping an API
On Nov 20, 2008, at 2:00 PM, Chuck Remes wrote:> > On Nov 20, 2008, at 1:48 PM, Roger Pack wrote: > >> take a look in the ''protocols'' directory there''s some example readers >> in there I believe, though I shouldn''t talk having never really >> looked >> at any of them or done anything similar, myself. >> -=R >> >> >>> Is this the right approach? If not, what do you suggest? >> >> If your approach works then go for it. Nobody''s wrong here :) > > I''ve been going through the HttpClient code in the protocols > directory for the last few hours (since I posted my original > message). I like the use of Deferrables here but I''d like to see how > HttpClient (and Deferrables) is handled in the context of an actual > client (or server) program. It''s a little hard to wrap my head > around right now since I only see the Protocol definition but I''ll > keep banging on it.I''ve decided to write some code and let that be my guide. I''ll report back what I find. cr