npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@financial-times/biz-ops-client

v2.0.0

Published

Safely send and retrieve data from the FT Biz Ops API.

Downloads

735

Readme

@financial-times/biz-ops-client

CircleCI NPM version

Safely send and retrieve data from the FT Biz Ops API.

const { BizOpsClient } = require('@financial-times/biz-ops-client');

const bizOps = new BizOpsClient(options);

const query = `{
	systems(where: { code: "my-system" }) {
		name
		supportedBy {
			slack
		}
	}
}`;

const result = await bizOps.graphQL.get(query);

Installation

This is a package for Node.js and is available through the npm registry. Using Node 20 or higher is recommended.

Installation is done using the npm install command:

npm install -S @financial-times/biz-ops-client

Features

  • Full coverage for the Biz Ops API
  • Stop writing boilerplate, write your requests and get on with your day!
  • Respects rate limits and sets required headers automatically
  • Detailed error codes and messages when things don't go to plan

Usage

This module provides a single BizOpsClient class which must initialised and configured using options.

const { BizOpsClient } = require('@financial-times/biz-ops-client');

const client = new BizOpsClient({
	apiKey: 'xxxx-xxxx-xxxx',
	systemCode: 'my-great-app',
});

Once initialised the Biz Ops client provides methods to send and retrieve data from the Biz Ops API.

Options

The BizOpsClient class accepts the following parameters:

| Option | Type | Required | Description | | ----------------- | ------ | -------- | --------------------------------------------------------------------------------------------------- | | apiKey | String | Yes | API key for the FT API Gateway | | systemCode | String | Yes* | A Biz Ops system code which identifies the service making requests. | | userID | String | Yes* | A user ID which identifies who is making a request | | host | String | | URL for the Biz Ops API, defaults to "https://api.ft.com/biz-ops". | | nodeEndpoint | String | ** | URL for the Biz Ops API node requests, defaults to /v2/node. | | graphqlEndpoint | String | ** | URL for the Biz Ops API graphql requests, defaults to /graphql. | | timeout | Number | | Maximum time in milliseconds to wait for a response, defaults to 15000 | | rps | Number | | Maximum number of API requests per second, defaults to 18 - highly recommended not to change this |

* you must configure at least one of systemCode or userID.

** once in a while when we carry out a migration/upgrade we may ask you to use a versioned endpoint during the transition period. e.g. graphqlEndpoint='/v3/graphql'

API

All methods return a promise. If the API responds with an unsuccessful (non-20x) status code then the promise will be rejected with a corresponding HTTP error. Please note that requests are rate limited by this client to match the Biz Ops API which accepts a maximum of 20 requests per second.

graphQL.get(query: string, variables?: object, strict?: boolean)

Fetches data from the Biz Ops GraphQL API using a GET request. You should use this if data does not need to be up-to-date. Resolves to the data returned. If the server responds with a http error then this method rejects with the equivalent error provided by the http-errors library. When "strict mode" is enabled the promise will also be rejected with a GraphQLError if a successful response includes any errors.

graphQL.post(query: string, variables?: object, strict?: boolean)

Fetches data from the Biz Ops GraphQL API using a POST request. You should use this if data must always be up-to-date. Resolves to the data returned. If the server responds with a http error then this method rejects with the equivalent error provided by the http-errors library. When "strict mode" is enabled the promise will also be rejected with a GraphQLError if a successful response includes any errors.

Note that GraphQL error handling may not align with your expectations if you're used to working with REST. Our server complies with the draft GraphQL over Http spec, and here you can see examples of types of errors and responses

node.head(type: string, code: string)

Verifies if a record exists. Resolves to true if the request is successful. Rejects with a NotFound error if the requested record cannot be found.

node.post(type: string, code: string, body: object, params?: object)

Creates a new record. Resolves with the updated record if the request is successful. Rejects with a BadRequest error if the data does not match the schema.

This method also accepts additional URL parameters to be set:

  • upsert a boolean which allows the creation of any new nodes needed to create relationships.
  • lockFields a list of fields to prevent any other system writing these fields, see field locking for more information.
  • unlockFields a list of fields to enable any system to write these fields, see field locking for more information.

node.patch(type: string, code: string, body: object, params?: object)

Updates an existing record (or creates if it doesn't already exist). Resolves with the updated record if the request is successful. Rejects with a BadRequest error if the data does not match the schema.

This method also accepts additional URL parameters to be set:

  • upsert a boolean which allows the creation of any new nodes needed to create relationships.
  • lockFields a list of fields to prevent any other system writing these fields, see field locking for more information.
  • unlockFields a list of fields to enable any system to write these fields, see field locking for more information.
  • relationshipAction either "merge" or "replace" which specifies the behaviour when modifying relationships.

node.delete(type: string, code: string, params?: object)

Deletes an existing record. Resolves to true if the request is successful. Rejects with a NotFound error if the requested record cannot be found or a Conflict error if the record cannot be deleted.

This method also accepts additional URL parameters to be set:

  • force a boolean which allows the deletion of a node even if it has relationships

nodeAbsorb.post(type: string, targetCode: string, sourceCode: string)

Merges two records by copying properties from the source node to the target node and deletes the original source node when complete. Resolves with the updated target record if the request is successful. Rejects with a NotFound error if either of the requested records cannot be found.

batch.patch(type: string, body: object[], params?: object)

Creates or modifies a batch of records of a given record type.

  • Requires its payload(records) to be sent as a JSON array
  • Resolves with a success message and total number of records created or modified.
  • Rejects with a HTTPError error if there is any payload validation error(s).

This method also accepts additional URL parameter to be set:

  • dryRun a boolean (defaults to false) which when enabled allows you to validate the request and the batch payload without performing the actual creation or modification of records.

batch.delete(type: string, codes: object[], params?: object)

Deletes a batch of records of a given record type.

  • Requires its payload(valid Biz ops codes) to be sent as a JSON array
  • Resolves with a success message and total number of records deleted.
  • Rejects with a HTTPError error if there is any payload validation error(s).

This method also accepts additional URL parameter to be set:

  • dryRun a boolean (defaults to false) which when enabled allows you to validate the request and the batch payload without performing the actual deletion of records.

child(options?: object)

Sometimes you may need multiple instances of the client. You can do that by calling new Client() multiple times but you will lose the benefits of using one single client, such as the long lived connections and rate limiting. This method returns a new client instance that shares these internals with the parent client. You can override the parent client options by providing additional options.

Errors

HTTPError

All non-20x responses will throw a corresponding error created by the http-errors package. This includes BadRequest, NotFound, and InternalServerError errors. If the API returns a detailed error then this will be used as the error message. The raw response may be appended to the error as the details property for further inspection.

ConfigurationError

Will be thrown when initialising the BizOpsClient class with incomplete configuration or when calling methods with incorrect arguments.

GraphQLError

Thrown when responses from the GraphQL API include any errors. This includes a details property which can be inspected to find out more.

Examples

Catching and logging errors

This example demonstrates how to catch and log an error when a GraphQL query fails. Note that this example uses return await to ensure that exceptions are caught by the catch block defined in the function below.

const { BizOpsClient } = require('@financial-times/biz-ops-client');

const client = new BizOpsClient({
	systemCode: 'my-service-name',
	apiKey: process.env.BIZ_OPS_API_KEY,
	host: process.env.BIZ_OPS_API_URL,
});

async function bizOpsQuery(query) {
	try {
		return await client.graphQL.post(query);
	} catch (error) {
		console.error(error, {
			event: 'BIZ_OPS_QUERY_FAILED',
		});

		return Promise.reject(error);
	}
}

module.exports = { bizOpsQuery };

Creating a child client

This example demonstrates how to create a child client for each of your application users. It shows how to override the parent client's options to associated a username with requests.

const { BizOpsClient } = require('./');

const client = new BizOpsClient({
	systemCode: 'my-service-name',
	apiKey: process.env.BIZ_OPS_API_KEY,
	host: process.env.BIZ_OPS_API_URL,
});

async function appRoute(request, response, next) {
	const child = client.child({
		userId: request.locals.username,
	});

	try {
		const data = await child.node.get(
			request.params.type,
			request.params.code,
		);

		response.json(data);
	} catch (error) {
		response.status(error.code || 500);
		next(error);
	}
}