Documentation

BYU OIT SDK

Blazingly fast API development for BYU OIT

Requirements:

  • Node.js 18+
    • or Node.js 10+ with fetch and crypto polyfills
  • npm v9+

Note that while Node.js 10 (with crypto/fetch polyfills) is supported, you should probably be using at least the LTS version of node (v18 at time of writing) except in cases where a lower version is absolutely necessary.

Quick-start

Below are code examples for basic use cases of making HTTP requests using the byu-oit-sdk. These examples show how to use the client-byu package, one of the more commonly used packages in the SDK. To learn about the other packages and for more details, you can find the full documentation at the link below.

Make Authenticated Tyk API Calls

These examples demonstrate how to call the Echo v1 API in order to demonstrate how to call BYU APIs using the byu-oit-sdk.

Configuration through Environment Variables

This example initializes the client by setting the discovery endpoint, client id, and client secret through environment variables. For this code to work, all you have to do is run the npm install command below, copy the code, and then set the process.env.BYU_OIT_CLIENT_ID, process.env.BYU_OIT_CLIENT_SECRET, and process.env.BYU_OIT_DISCOVERY_ENDPOINT.

The discovery endpoint for Tyk will be https://api-sandbox.byu.edu/.well-known/openid-configuration. Remove the -sandbox if using production credentials.

npm i @byu-oit-sdk/client-byu
ESM (and Typescript)
import { Client, Command } from '@byu-oit-sdk/client-byu'

/**
* You should change these hardcoded environment names and url prefixes
* to match your projects environments and deployment strategy
*/
const production = process.env.ENVIRONMENT_NAME === 'prd'
const host = production ? 'api.byu.edu' : 'api-sandbox.byu.edu'

/**
* Given an empty constructor, config and credentials will be fetched
* from `BYU_OIT_`-prefixed environment variables.
*/
const client = new Client()

const uri = new URL(`https://${host}/echo/v1/echo/test`)
const command = new Command(uri/**, Addtional fetch options */)

/** Send the command */
const response = await client.send(command)
console.log(await response.json())
CommonJS
const { Client, Command } = require('@byu-oit-sdk/client-byu')

/**
* You should change these hardcoded environment names and url prefixes
* to match your projects environments and deployment strategy
*/
const production = process.env.ENVIRONMENT_NAME === 'prd'
const host = production ? 'api.byu.edu' : 'api-sandbox.byu.edu'

;(async () => {
/**
* Given an empty constructor, config and credentials will be fetched
* from `BYU_OIT_`-prefixed environment variables.
*/
const client = new Client()

const uri = new URL(`https://${host}/echo/v1/echo/test`)
const command = new Command(uri/**, Addtional fetch options */)

/** Send the command */
const response = await client.send(command)
console.log(await response.json())
})()

Configuration in Constructor

This example initializes the client by setting the discovery endpoint, client id, and client secret in the code itself. For this code to work, all you have to do is run the npm install command below, copy the code, and then replace myClientId and myClientSecret with your actual Tyk credentials.

npm i @byu-oit-sdk/client-byu @byu-oit-sdk/credential-provider
ESM (and Typescript)
import { Client, Command } from '@byu-oit-sdk/client-byu'
import { ClientCredentialsProvider } from '@byu-oit-sdk/credential-provider'

/**
* You should change these hardcoded environment names and url prefixes
* to match your projects environments and deployment strategy
*/
const production = process.env.ENVIRONMENT_NAME === 'prd'
const host = production ? 'api.byu.edu' : 'api-sandbox.byu.edu'

const client = new Client({
credentials: new ClientCredentialsProvider({
/* DO NOT commit any files with hardcoded credentials */
clientId: 'myClientId',
clientSecret: 'myClientSecret',
discoveryEndpoint: `https://${host}/.well-known/openid-configuration`
})
})

const uri = new URL(`https://${host}/echo/v1/echo/test`) // i.e. https://api.byu.edu/echo/v1/echo/test
const command = new Command(uri/**, Addtional fetch options */)

/** Send the command */
const response = await client.send(command)
console.log(await response.json())
CommonJS
const { Client, Command } = require('@byu-oit-sdk/client-byu')
const { ClientCredentialsProvider } = require('@byu-oit-sdk/credential-provider')

/**
* You should change these hardcoded environment names and url prefixes
* to match your projects environments and deployment strategy
*/
const production = process.env.ENVIRONMENT_NAME === 'prd'
const host = production ? 'api.byu.edu' : 'api-sandbox.byu.edu'

;(async () => {
const client = new Client({
credentials: new ClientCredentialsProvider({
/* DO NOT commit any files with hardcoded credentials */
clientId: 'myClientId',
clientSecret: 'myClientSecret',
discoveryEndpoint: `https://${host}/.well-known/openid-configuration`
})
})

const uri = new URL(`https://${host}/echo/v1/echo/test`)
console.log(uri)
const command = new Command(uri/**, Addtional fetch options */)

/** Send the command */
const response = await client.send(command)
console.log(await response.json())
})()

SDK Deep Dive

Clients

There are a number client packages to facilitate calling APIs with or without authentication. All clients will work in the browser and in NodeJS (ESM or CJS).

  1. The BYU Client essentially wraps the Fetch API and adds a retry middleware and an optional authentication middleware.

  2. A list of domain specific clients can be found here:

    Domain Specific Clients
    Name Domain
    IdentitiesClient https://api.byu.edu/byuapi/identities
    PersonsClient https://api.byu.edu/byuapi/persons

Client Development

To start developing a new or existing client, please refer to the Client Development documentation

Servers

Currently, the BYU OIT SDK supports Authorization Code Provider implementations for Fastify and Express.

Authorization Code Implementation:

Credential Provider

OAuth Credential Providers facilitate interactions with an OAuth 2.0-compliant authorization server. Please see the [documentation on credential] providers(https://byu-oit-sdk.github.io/javascript/modules/Credential_Provider.html) for more information.

The supported credential providers are:

Contributing

The BYU OIT SDK uses Lerna with Nx to build, test, and lint the source code. Please consult their documentation when making modifications to the maintenance process of this project.

There are a few commands that most of the packages share:

  • build: Compile the distribution code
  • lint: Lint the source code
  • test: Test the source code with Ava

If you notice a problem, please submit an issue or create a PR with the fix!

Committing

Commit messages must adhere to the angular conventional commit standard. commitlint will enforce commit messages to follow this standard. Following a commit standard enables our distribution pipeline to publish new versions of each package automatically.

Building

This library exposes files in both CJS and ESM syntax in order to accommodate browser environments and legacy NodeJS applications. CJS support may be dropped in the future but is supported for the time being.

There are two ways that we know of to support both CJS and ESM syntax:

  1. Create a localized package.json file in each packages' cjs directory with the contents { type: 'commonjs' }. This effectively overwrites the package's own package.json which is set to module.

    Node Resolution Algorithm: See ESM_FILE_FORMAT

    ESM & CommonJS Module Tutorial: https://www.sensedeep.com/blog/posts/2021/how-to-create-single-source-npm-module.html

  2. Use a tool such as unbuild which outputs files with the .cjs and .mjs extensions.

    Example of Using unbuild: https://github.com/unjs/radix3/blob/main/package.json

    MDN Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules

This library uses the first method for two reasons:

  1. Some tools may never support the .mjs extension
  2. (package.json).type is more deterministic since the resolution algorithm is built into node and bundlers.

Testing

The choice to use Ava was made because it

  1. supports TypeScript and ESM out of the box
  2. parallelizes tests in separate environments making it typically faster
  3. does not mutate nodejs globals like Jest
  4. follows a similar convention as the node test runner which we may adopt eventually

Running tests requires building the source code first, which should be handled for you by lerna.

From the root of the project you can run:

npm test

Or you can run the following from anywhere within the project.

# use npx if you don't want to install lerna globally
lerna run test

Note There is a bug in NodeJS Worker threads which requires us to use the --no-worker-threads flag when running tests. Even with that flag enabled, some tests run into this bug. There isn't a bug report for the issue yet (See this discussion). Currently, this seems to only affect the @byu-oit-sdk/client-byu package.

Publishing

Merging changes into the main branch will automatically update the version of each package, publish the package, and publish the changelog according to the commit messages.

Merging changes into the beta branch will trigger the same GitHub workflow but the beta prefix will be prepended to the new pre-release versions published.

The publish workflow was heavily inspired by the article "Automatic versioning in a Lerna monorepo using Github actions" by Xavier Canchal :clap:.

Documentation & Linting

Writing SDKs with TypeScript and TSDocs provides consumers with the code and documentation all from their development environments. To that end, running the linter without documenting code with TSDocs style documentation (similar to JSDocs or JavaDocs), will return a non-zero exit code.

Generated using TypeDoc