Skip to content

Commit

Permalink
update README
Browse files Browse the repository at this point in the history
  • Loading branch information
Seth Battis committed Dec 25, 2024
1 parent 55427b2 commit 40dafc8
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
31 changes: 31 additions & 0 deletions packages/datadirect-puppeteer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,34 @@
![NPM Version](https://img.shields.io/npm/v/datadirect-puppeteer)

An implementation of scraping Blackbaud's front-end APIs using Puppeteer

## Install

```sh
npm install datadirect-puppeteer datadirect puppeteer
```

Realistically, you'll want access to the `datadirect` types and will need to configure `puppeteer`, so they are peer dependencies.

## Usage

```ts
import { api } from 'datadirect-puppeteer';
import { api as types } from 'datadirect';
import { Page } from 'puppeteer';

let page: Page;
// create an authorized Blackbaud LMS web session (https://example.myschoolapp.com) that page refers to

// optional to explicitly type `groups`, as the `datadirect-puppeteer` method maps types correctly!
const groups: types.datadirect.groupFinderByYear.Response = await api.datadirect.groupFinderByYear(page, {
schoolYearLabel: '2024 - 2025'
});
const topics = await api.datadirect.sectiontopicsget(page, {
format: 'json';
active: true;
future: false;
expired: false;
sharedTopics: true;
}, { Id: 12345678 });
```
46 changes: 46 additions & 0 deletions packages/datadirect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,49 @@
![NPM Version](https://img.shields.io/npm/v/datadirect)

Types for working with Blackbaud's front-end APIs

An idiosyncratic collection of TypeScript types for the front-end APIs of Blackbaud's LMS. This functionally serves as my notes for scripting interactions with the LMS.

## Install

```sh
npm install datadirect
```

## Usage

```ts
import { api } from 'datadirect';

const payload: api.datadirect.groupFinderByYear.Payload = {
schoolYearLabel: '2024 - 2025'
};
const { input, init } = api.datadirect.groupFinderByYear.prepare(payload);
const response: api.datadirect.groupFinderByYear.Response = await fetch(
input,
init
);
```

Each endpoint has a `Payload` and a `Response` type, as well as a method to `prepare()` the `fetch()` parameters. Given that the endpoint needs to be called with suitable authentication (e.g. with authorized session cookies), these are not immediately actionable. [`datadirect-puppeteer`](../datadirect-puppeteer) tackles one approach to this, by assuming an authenticated browser session in a Puppeteer-controlled browser, through which the fetch requests can be passed.

In the case of endpoints that include path parameters, some additional preparation is required.

```ts
const payload: api.datadirect.sectiontopicsget.Payload = {
format: 'json';
active: true;
future: false;
expired: false;
sharedTopics: true;
}
let {input, init} = api.datadirect.sectiontopicsget.prepare(payload);
input = api.Endpoint.preparePath(input, {Id: 12345678})
// ...
```

## Notes

- Capitalization is "as-found" in the Blackbaud LMS, without corrections. Where multiple sources differ, I have tended towards what seems to be the most common approach.
- Payloads for 'GET' and 'POST' requests are treated identically (at the moment), with the `prepare()` method determining the proper encoding and REST method to use for each endpoint. Should I encounter a situation where that doesn't work, things will change.
- There are no types for path parameters right now, but aspirationally there will be soon!
10 changes: 7 additions & 3 deletions packages/datadirect/src/api/Endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,13 @@ export function preparePath(
`${pathParams[p]}$2`
);
}
const match = actual.match(/:([a-z_0-9]+)/);
if (match) {
throw new Error(`No values passed for path parameter ${match[1]}`);
const match = Array.from(actual.matchAll(/:([a-z_0-9]+)/g)).map(
(group) => group[1]
);
if (match.length) {
throw new Error(
`No values passed for path parameter${match.length > 1 ? 's' : ''} ${match.join(', ')}`
);
}
return actual;
}
Expand Down

0 comments on commit 40dafc8

Please sign in to comment.