Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 52 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ An official Learnosity open-source project.</p>
* [Requirements](#requirements)
* [Installation](#installation)
* [Quick start guide](#quick-start-guide)
* [Data API Routing Layer](#data-api-routing-layer)
* [Next steps: additional documentation](#next-steps-additional-documentation)
* [Contributing to this project](#contributing-to-this-project)
* [License](#license)
Expand All @@ -29,7 +30,7 @@ The Learnosity Node.js SDK makes it simple to interact with Learnosity APIs.

It provides a number of convenience features for developers, that make it simple to do the following essential tasks:
* Creating signed security requests for API initialization, and
* Interacting with the Data API.
* Interacting with the Data API (now includes a routing layer for making HTTP requests).

For example, the SDK helps with creating a signed request for Learnosity:

Expand Down Expand Up @@ -133,20 +134,20 @@ Let's take a look at a simple example of the SDK in action. In this example, we'
### **Start up your web server and view the standalone assessment example**
To start up your Node.js web server, first find the following folder location under the SDK. Change directory ('cd') to this location on the command line.

.../learnosity-sdk-nodejs/docs/quickstart/assessment/
.../learnosity-sdk-nodejs/docs/quickstart/

To start, run this command from that folder:

```
npm run start-standalone-assessment
npm start

```

From this point on, we'll assume that your web server is available at this local address (it will report the port being used when you launch it, by default it is port 3000):
From this point on, we'll assume that your web server is available at this local address (it will report the port being used when you launch it, by default it is port 8000):

http://localhost:3000/
http://localhost:8000/

When you open this URL with your browser, the page will load. This is a basic example of an assessment loaded into a web page with Learnosity's assessment player. You can interact with this demo assessment to try out the various Question types.
When you open this URL with your browser, you'll see a menu of interactive examples demonstrating different Learnosity APIs. Click on "Items API" to view the standalone assessment example, which loads an assessment into a web page with Learnosity's assessment player. You can interact with this demo assessment to try out the various Question types.

<img width="50%" height="50%" src="docs/images/image-quickstart-examples-assessment.png">

Expand Down Expand Up @@ -292,6 +293,51 @@ Take a look at some more in-depth options and tutorials on using Learnosity asse

[(Back to top)](#table-of-contents)

## Data API Routing Layer

The SDK now includes a routing layer for the Data API, making it easy to interact with Learnosity's Data API without manually handling HTTP requests.

### Quick Example

```javascript
const DataApi = require('learnosity-sdk-nodejs/lib/DataApi');

const dataApi = new DataApi({
consumerKey: 'your_consumer_key',
consumerSecret: 'your_consumer_secret',
domain: 'yourdomain.com'
});

// Make a request
const response = await dataApi.request(
'https://data.learnosity.com/v2023.1.LTS/itembank/items',
{ consumer_key: 'xxx', domain: 'example.com' },
'secret',
{ limit: 10 },
'get'
);

const data = await response.json();
console.log(data);

// Or iterate through all pages automatically
for await (const page of dataApi.requestIter(endpoint, security, secret, request, 'get')) {
console.log(`Page has ${page.data.length} items`);
}
```

### Features

- ✅ Automatic request signing
- ✅ Built-in HTTP client
- ✅ Pagination support with iterators
- ✅ Routing metadata headers
- ✅ Custom HTTP adapter support

See the [Data API documentation](docs/DataApi.md) for complete details and examples.

[(Back to top)](#table-of-contents)

## Next steps: additional documentation

### **SDK reference**
Expand Down
192 changes: 192 additions & 0 deletions docs/DataApi.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏 Praise: Excellent documentation 🙌

Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# Data API Routing Layer

The Node.js SDK now includes a routing layer for the Data API, making it easier to interact with Learnosity's Data API without manually handling HTTP requests and signatures.

## Features

- ✅ **Automatic request signing** - No need to manually sign requests
- ✅ **Built-in HTTP client** - Makes actual HTTP requests to Data API
- ✅ **Pagination support** - Automatically handles paginated responses
- ✅ **Iterator methods** - Easy iteration through pages and individual results
- ✅ **Routing metadata** - Automatically adds ALB routing headers
- ✅ **Custom HTTP adapter** - Use your own HTTP library (axios, node-fetch, etc.)

## Installation

The DataApi class is included with the SDK:

```javascript
const LearnositySDK = require('learnosity-sdk-nodejs');
const DataApi = LearnositySDK.DataApi;
```

Or import directly:

```javascript
const DataApi = require('learnosity-sdk-nodejs/lib/DataApi');
```

## Basic Usage

### Simple Request

```javascript
const DataApi = require('learnosity-sdk-nodejs/lib/DataApi');

const dataApi = new DataApi({
consumerKey: 'your_consumer_key',
consumerSecret: 'your_consumer_secret',
domain: 'yourdomain.com'
});

// Make a request
const response = await dataApi.request(
'https://data.learnosity.com/v2023.1.LTS/itembank/items',
{
consumer_key: 'your_consumer_key',
domain: 'yourdomain.com'
},
'your_consumer_secret',
{
limit: 10,
references: ['item_1', 'item_2']
},
'get'
);

const data = await response.json();
console.log(data);
```

### Paginated Requests

Automatically iterate through all pages:

```javascript
for await (const page of dataApi.requestIter(
'https://data.learnosity.com/v2023.1.LTS/itembank/items',
{ consumer_key: 'xxx', domain: 'example.com' },
'secret',
{ limit: 100 },
'get'
)) {
console.log(`Page has ${page.data.length} items`);
console.log(`Total records: ${page.meta.records}`);
}
```

### Individual Results Iterator

Iterate through individual results across all pages:

```javascript
for await (const item of dataApi.resultsIter(
'https://data.learnosity.com/v2023.1.LTS/itembank/items',
{ consumer_key: 'xxx', domain: 'example.com' },
'secret',
{ limit: 100 },
'get'
)) {
console.log(`Item: ${item.reference}`);
}
```

## API Reference

### Constructor

```javascript
new DataApi(options)
```

**Options:**
- `consumerKey` (string, optional) - Your Learnosity consumer key
- `consumerSecret` (string, optional) - Your Learnosity consumer secret
- `domain` (string, optional) - Your domain for security packet
- `httpAdapter` (function, optional) - Custom HTTP adapter function

### Methods

#### `request(endpoint, securityPacket, secret, requestPacket, action)`

Makes a single HTTP request to the Data API.

**Parameters:**
- `endpoint` (string) - Full URL to the Data API endpoint
- `securityPacket` (object) - Security object with `consumer_key` and `domain`
- `secret` (string) - Consumer secret for signing
- `requestPacket` (object, optional) - Request parameters
- `action` (string, optional) - Action type: `'get'`, `'set'`, `'update'`, `'delete'` (default: `'get'`)

**Returns:** Promise<Response>

#### `requestIter(endpoint, securityPacket, secret, requestPacket, action)`

Async generator that yields pages of results, automatically handling pagination.

**Parameters:** Same as `request()`

**Yields:** Page objects with `meta` and `data` properties

#### `resultsIter(endpoint, securityPacket, secret, requestPacket, action)`

Async generator that yields individual results from the `data` array, automatically handling pagination.

**Parameters:** Same as `request()`

**Yields:** Individual result objects

## Advanced Usage

### Custom HTTP Adapter

Use your own HTTP library (e.g., axios):

```javascript
const axios = require('axios');

const dataApi = new DataApi({
consumerKey: 'xxx',
consumerSecret: 'secret',
domain: 'example.com',
httpAdapter: async (url, options) => {
const response = await axios({
method: options.method,
url: url,
headers: options.headers,
data: options.body
});

return {
ok: response.status >= 200 && response.status < 300,
status: response.status,
statusText: response.statusText,
json: async () => response.data,
text: async () => JSON.stringify(response.data)
};
}
});
```

## Routing Metadata

The DataApi automatically adds routing metadata headers to all requests:

- `X-Learnosity-Consumer` - Consumer key
- `X-Learnosity-Action` - Derived action (e.g., `get_/itembank/items`)
- `X-Learnosity-SDK` - SDK version (e.g., `Node.js:0.6.2`)

These headers are used by Learnosity's Application Load Balancer for routing.

## Examples

See the [examples/data-api-example.js](../examples/data-api-example.js) file for complete working examples.

## Comparison with Python SDK

This implementation mirrors the Python SDK's DataApi class, providing:

- `request()` - Single request (Python: `request()`)
- `requestIter()` - Page iterator (Python: `request_iter()`)
- `resultsIter()` - Results iterator (Python: `results_iter()`)

Loading