bb = require "bluebird"
_ = require('lodash')
Bam = require('./bam')bluebird is the promises librarylodash is used as a general purpose utility libraryBam is the error library used to generate errors if a method is not implementedbb = require "bluebird"
_ = require('lodash')
Bam = require('./bam')Resource is the class to override to implement a resource to be deployed Each resource has:
name of the resource used for logging and authenticationpath of the resource used for service discovery and routingshow, create, update and delete methods, meant to be overridden by the resource implementations.start and stop lifecycle methods to control its connectionsclass ResourceRabbitMQ topic exchanges
route a message using a routing key to queues bound with a binding key.
Alchemy Resource binds resources to the topic exchange resources.exchange
and converts URL paths into routing keys
to route messages to the right resources without knowing their specific location or queue.
For example, the *users resource has the path of /v1/users.
By binding this resource to the resources.exchange with the binding_key v1.users.#
(the .# means zero-to-many additional words),
messages with paths /v1/users and /v1/users/1,
and routing keys v1.users and v1.users.1 respectively,
would be routed to the users resource.
Note: path conflicts will occur if you have resource that has a parent path of another.
For example, if two resources had paths /v1/users and /v1/users/registered
messages sent to /v1/users/registered will be send to both resources,
unless the resources are in the same service then it will make it to only one.
So, don’t have resources that have parent paths.
path_to_routing_key is the class method that takes a path and converts it into a RabbitMQ routing key.
The path is converted to a routing key by:
'/' characters to '.' except the first and last characters'/' charactersFor Example, path_to_routing_key('/v1/users') return 'v1.users'.
@path_to_routing_key = (path) ->
new_path = ""
for c,i in path
if c == '/' and i != 0 and i != path.length-1
new_path += '.'
else if c != '/'
new_path += c
new_pathmatches_path checks to see if a path should be routed to this resource.
It first normalises the incoming path and check to see if it starts with the same string as the resources path.
matches_path: (path) ->
path = path.replace(/(^\/)|(\/$)/g, "") # normalise path by remove trailing and leading /
return _.startsWith(path, @path)constructor(name, path) takes a name string and a url path.
The path is normalised to make string matching easier,
then a binding_key is created by using path_to_routing_key and adding the wild card .#
constructor: (@name, @path) ->
@path = @path.replace(/(^\/)|(\/$)/g, "") # normalise path by remove trailing and leading /
@binding_key = "#{Resource.path_to_routing_key(@path)}.#"Allowing a resource to override start and stop methods lets a resource:
start returns and empty promise by default
start: () ->
bb.try( -> )stop returns and empty promise by default
stop: () ->
bb.try( -> )A resource implementation can override these methods to implement its processing functions
show method will be called on a GET
show: (context) ->
throw Bam.method_not_allowed(context)create method will be called on a POST
create: (context) ->
throw Bam.method_not_allowed(context)update method will be called on a PATCH
update: (context) ->
throw Bam.method_not_allowed(context)delete method will be called on a DELETE
delete: (context) ->
throw Bam.method_not_allowed(context)
module.exports = Resource