Implementing a Fail-Safe REST API

Maintained on

In kintone JavaScript customization, the most performance-impacting operations are often the execution of REST APIs or external APIs.

When considering REST API performance improvements, the first point to examine is minimizing the record retrieval conditions and fields.

However, many of you might have experienced errors by referencing fields you thought were retrieved but were not due to field restrictions.

If you use TypeScript, you can prevent this by defining strict types, but this has traditionally required redundant definitions.

With the satisfies operator implemented in TypeScript 4.9, you can now handle REST API record information safely with efficient type definitions.

This article introduces how to implement a fail-safe REST API using the satisfies operator.

Required Environment

  • TypeScript 4.9 or higher

Sample Code

/** _Type definitions for the app created with dts-gen_ */
type SavedFields = sample.SavedFields;

/** _Fields of the app retrieved by the REST API_ */
const FIELD_CODES = ['FieldCodeA', 'FieldCodeB'] as const satisfies Readonly<(keyof SavedFields)[]>;

/** _Fields of the app retrieved by the REST API_ */
type FieldCodes = (typeof FIELDS)[number];

/** _Record information limited to the retrieved fields_ */
type ReferencedFields = Pick<SavedFields, FieldCodes>;

const client = new KintoneRestAPIClient({
  /* ... */
});

const getRecords = async (): Promise<ReferencedFields[]> => {
  const app = 9999;
  const query = 'ID = 99999';

  const records = await client.record.getAllRecordsWithCursor<ReferencedFields>({
    app,
    query,
    fields: FIELD_CODES,
  });

  return records;
};

Explanation

The following part is what can be achieved with the satisfies operator.

const FIELD_CODES = ['FieldCodeA', 'FieldCodeB'] as const satisfies Readonly<(keyof SavedFields)[]>;

Previously, when defining the field codes to be used as constants, it was necessary to define them as follows.

const FIELD_CODES: (keyof SavedFields)[] = ['FieldCodeA', 'FieldCodeB'];

This allows you to check whether the specified field codes actually exist.

However, type inference does not work, and you cannot use this constant as the type of the record information to be retrieved.

const FIELD_CODES: (keyof SavedFields)[] = ['FieldCodeA', 'FieldCodeB'];

type FieldCodes = (typeof FIELD_CODES)[number]; // _Inferred as keyof SavedFields, not strict_

If you want to reflect the constants as REST API record information, you can use as const, but then you cannot check whether the specified field codes actually exist.

const FIELD_CODES = ['FieldCodeA', 'FieldCodeB'] as const;

type FieldCodes = (typeof FIELD_CODES)[number]; // _"FieldCodeA" | "FieldCodeB"_

By using the satisfies operator, you can define constants and types that meet both of the above conditions.

const FIELD_CODES = ['FieldCodeA', 'FieldCodeB'] as const satisfies Readonly<(keyof SavedFields)[]>;
#kintone #typescript