Creating a custom adapter
An adapter is used to allow your system to interface programmatically with Canvas. This section includes information on how to build and install a custom adapter.
Example Adapter
An example adapter is provided along with the Canvas source code and can be used as a starting point. Please see the readme included in the source code to understand the functionality enabled in the example adapter and how to install and use it. The example adapter is meant to be a kernel of an implementation, not necessarily production ready (depending on your requirements). For example, additional optimizations would be necessary to enable larger scale implementations (i.e. dozens of VENs and/or hundreds of resources).
Creating and installing an adapter
Create gem
In this document, custom text chosen by the implementor is placed in brackets: <replace-with-your-text>
, where the brackets are also replaced along with the text.
Helpful Commands
rvm list
- list installed ruby versions and display which is being usedrvm use <ruby-version>
- select version of ruby to uservm gemset list
- list gemsets and which is being usedrvm use gemset <gemset-name-here>
- select which gemset to use
Install Ruby
A gem is started like you start a new rails project.
Install the desired version of ruby using rvm:
rvm install ruby-version
Prepare gemset
Create a gemset for the gem, and select the gemset for use using rvm:
rvm gemset create <gemset-name-here>
rvm gemset use <gemset-name-here>
Install the desired version of rails into the gemset:
gem install rails -v <version-#>
Generate And Setup gem
Generate the gem using rails:
rails plugin new <gem_name_here> --full
Modify
module <GemNameHere>
class Engine < ::Rails::Engine
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.eager_load_paths += Dir["#{config.root}/lib/**/"]
initializer :append_migrations do |app|
unless app.root.to_s.match root.to_s
config.paths["db/migrate"].expanded.each do |expanded_path|
app.config.paths["db/migrate"] << expanded_path
end
end
end
end
end
Create custom api file
module Api
module <GemNameHere>
SCHEMA = {
custom_function1: { validate: false },
custom_function2: { validate: false }
}
def self.custom_function1(payload)
# custom implementation
end
def self.custom_function2(payload)
# custom implementation
end
end
end
Modify
require "<gem_name_here>/engine"
module <GemNameHere>
if defined?(Rails)
require "<gem_name_here>/engine"
else
require "api/<custom_file_name_here>"
end
end
Note that the extension is not needed on
Edit gemspec
The "TODO" values in
Install gem In Vtn
The vtn looks in vtn-root/../local_oadr_gems for local gems. Create this directory if it does not exist. The most flexible way to add gems to the directory is by creating symlinks to each desired gem on the filesystem. This way, a gem can be removed by removing the symink and not needing to move or delete the real gem. If you create a symlink to a gem, make sure the name of the symlink is the same name as the root directory of the gem.
For example, the file structure should look as follow:
canvas-oadr-vtn
local_oadr_gems
|
--> canvas_adapter
When a gem has been added to the vtn-root/../local_oadr_gems directory, install it as you would install other gems in vtn. From vtn-root, run:
bundle install
NOTE: If you are developing the gem and then installing in the vtn, keep in mind which gemset is currently being used. If switching to the vtn, you can cd out of the vtn root, and then back in, to allow rvm to select the correct gemset. If you switch back to developing the gem, you will need to use rvm use <gemset-name-here>
to select the correct gemset.
Authentication & API
Authentication is available via the API Controller built into Canvas.
API Access must be enabled for a user, or the requests will be rejected. On the users account page in the Canvas UI, there is a check box to enable API access for that account.
In addition, requests may only be made for the namespace that the account, or they will be rejected. The namespace is specified in the API request path.
The VTN's built in API Controller supports two types of Authentication, Basic and JWT. The example adapter uses this for authentication - see the example adapter source code and readme file for more information on how these are implemented and how to use them.
Identifiers
Remote IDs
Targets, VENs and Events all have a remote_id field that can be use to link records in the external system. It is a string field limited to 255 characters. Remote IDs can be updated in the UI.
Finding VEN targets by name
VEN targets (to add a VEN to an Event) are given IDs that aren't exposed for modification through the UI, but is field is synced with associated VEN and available to query in the following format: VEN:
For example, given a ven named TH_VEN
, the VEN ID target can be retrieved with
target = Target.find_by_name("VEN:TH_VEN")
The example adapter provides an endpoint to convert between different types of IDs (e.g. for VENs, ids, names and remote IDs)