Architecture / API

Overview

As of version 2015.1, Engine provides a RESTful API for interacting with core Engine functionality. The documentation for the API should have been provided along with your release here. Many programming languages already provide extensive support for interfacing with RESTful APIs, and so it is certainly possible that your application can generate API calls itself. For your convenience, however, we have also generated two API clients: one for .NET, and another for Java. The clients should have been included in your initial deliverable. The clients will allow you to work directly with the API from your application without having to create API bindings yourself.

Note that all API calls require choosing a "tenant". For more information on what tenants are and how to use them, consult the "Tenancy" section, below.

Note also that there are many other API resources and optional features that are not covered in the following documentation. This documentation provides only a brief overview. If you ever have further questions about how to do something specific, do not hesitate to inquire with your assigned integration engineer or to contact us.

API Authentication

API authentication is handled via HTTP Basic Auth (username and password). For each request, the supplied credentials will be checked against the set of accounts specified by your ApiBasicAccounts configuration setting.

In order to keep your credentials secure we strongly recommend using TLS (https) when accessing the API, and using long random strings for both the username and password components (these should not be real user accounts, no one should ever have to type these credentials!)

N.B. This API is designed to allow your application to integrate with Engine and does not provide the fine grained security control you'd want for an API available to users. Any API account can perform any operation. The ability to set up multiple accounts is only relevant for the purpose of having different sets of credentials that can be revoked separately.

Tenancy

"Tenancy" refers to the ability of a single instance of a running web application to serve multiple groups of users ("tenants") as if they were interacting with their own separate instance of the application, all while keeping the the data that belongs to these tenants separate.

For example, an LMS might have several organizations as customers, each of whom have their own set of users, packages, and registrations.

A multi-tenant architecture allows each of these organizations (tenants) to harness the full power of the LMS without the overhead of running a separate server with a separate instance of the LMS for each organization. Engine is designed to work with your application's tenancy model.

Whether your application separates different tenants into different databases or keeps all tenants together in the same database, Engine is capable of being configured to support it and to enforce secure separation of tenant data.

Implementation

The concept of tenancy is built in to Engine at a very low level; every single row in every single one of Engine's tables has a column that identifies the tenant to which the data belongs. Furthermore, run-time checks enforce data access rules for every single query, so you can be assured that one tenant will not be able to access another tenant's data. Among other things, this means you can use a single database instance to serve all of your tenants.

Engine identifies tenants by a case-insensitive name, consisting of 64 or fewer characters. (Internationalized characters are allowed, but you will have to take care to escape them when using the tenant names in URIs.) All API calls include (indeed, require) the tenant name as the first element of the API path. For example, to create a registration, you can POST to the registrations resource, /{tenant}/registrations. If you wish to create a registration for your "AcmeCo" tenant, you make POST calls to http://example.org/ScormEngineInterface/api/v1/acmeco/registrations, and if you want to create a registration for your "BusinessPlus" tenant, you make a POST call to http://example.org/ScormEngineInterface/api/v1/businessplus/registrations.

Tenants are created on demand; in order to create a new tenant, all you need to do is make a new API call that uses that tenant. You can restrict this behavior by specifying which tenant names are valid in your configuration file. You can use the AllowedTenantNames configuration setting to enumerate explicitly which tenants can be created, and you can use the AllowedTenantNameRegex configuration setting to specify a range of valid tenant names.

Note that the tenant name is required in all API calls. If you are not using tenancy, you will simply use "default" as the tenant name in all API calls.

xAPI Tenancy

Experience API (xAPI, formerly "Tin Can API") calls are formatted slightly different from Engine's API (as the xAPI structure is governed by a third-party standard). To use tenancy with xAPI, you must include the tenant name as part of the endpoint URL. By default, all you need to do is add the tenant name as the next path element between the base endpoint URL and the endpoint method. For example, the xAPI statements endpoint for "AcmeCo" might be http://example.org/ScormEngineInterface/TCAPI/acmeco/statements, while the xAPI activities endpoint for "BusinessPlus" might be http://example.org/ScormEngineInterface/TCAPI/businessplus/activities.

The tenant name is not required for xAPI calls, but if it is not included, the endpoint will always reference the default tenant. It is strongly recommended that customers using tenancy always specify the tenant when composing xAPI endpoint URLs!

All of the preceding works for Recipes as well, except instead of coming between TCAPI and the method name, the tenant name will come between the Recipes dispatch path and the method name. For example, the xAPI interactions data for the "MaximumProfit" tenant might be accessed at something like http://example.org/ScormEngineInterface/Recipes/interactions/maximumprofit/results. The default tenant can be accessed by using "default" as the tenant name or by leaving out the tenant name entirely.

Database Considerations

By default, Engine assumes that you are using one database. As discussed earlier, Engine's tenancy is built-in at a very low level; every database row will include information identifying the tenant to whom the data pertains.

Clearly, keeping all Engine's data together in the same place is the simplest way to set up Engine, and we strongly recommend it. But for technical reasons, some customers may want to use multiple databases to support tenancy. Engine supports this, but care must be taken in the initial set-up of Engine.

Engine requires the use of two database schemas. First, there is the system schema, which contains information that is shared between all of Engine's tenants. This includes the catalog of tenants themselves, as well as some tables related to configuration settings. There can never be more than one system schema (nor should there need to be). The connection string for system tables is governed by the SystemDatabaseConnectionString configuration setting.

Note: It is possible to run Engine without a System schema, with restrictions. See: SystemDatabaseEnabled

Second, there is the tenant schema, which contains all tenanted information. If your application needs to use different databases for different tenants, this is the schema that needs to be duplicated. The connection string for these tables is governed by the TenantDatabaseConnectionString configuration setting. (For information on how to change this setting on a per-tenant basis, see the "Configuration" section, below. If the setting is not given, SystemDatabaseConnectionString will be used instead.)

For single-database customers, it is possible (and encouraged!) to combine the system and tenant schemas into a single database (by just providing the same connection string for both the system and tenant schemas). For customers who are going to try to split tenant data accross multiple databases, however, the system and tenant schemas need to be kept separate.

The most common reason to split tenant data accross several databases is to reduce the size of the data contained on any particular database instance. Many modern DBMSes provide (either themselves, or with the help of third-party tools) mechanisms for sharding a database so a logically single database can be divided among smaller "shards". How this is accomplished is beyond the scope of this documentation. We pause here only to say that customers wishing to do this will need to base their sharding scheme on the tenant_id column, which is contained in every table on the tenant schema. Since your DBMS is handling sharding on your behalf, you will not need to use multiple configuration files.

Alternatively, it may be impossible to use sharding tools to automatically separate the data from different tenants into multiple shards for technical reasons. For example, your application may come bundled with other tables that need to be re-created on a per-tenant basis. In order to make Engine work, you will need to create the multiple instances of the tenant schema yourself. You will also need to use multiple configuration settings (see below) to specify the connection string for each tenant.

results matching ""

    No results matching ""