@financial-times/content-curation-client 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Content Curation API Client
2
2
 
3
- A TypeScript client library for interacting with the Content Curation API.
3
+ TypeScript client library for interacting with the Content Curation API.
4
4
 
5
5
  ## Features
6
6
 
7
- - Fully typed API using Zod schemas for validation
8
- - Simple promise-based API for fetching and updating homepage and page structures
9
- - Comprehensive error handling
10
- - TypeScript-friendly with exported types
7
+ - Zod-validated request and response types
8
+ - Promise-based clients for homepage and page endpoints
9
+ - Typed transport, gateway, and service error handling
10
+ - Support for custom `fetch` implementations
11
11
 
12
12
  ## Installation
13
13
 
@@ -15,11 +15,12 @@ A TypeScript client library for interacting with the Content Curation API.
15
15
  npm install @financial-times/content-curation-client
16
16
  ```
17
17
 
18
- ## Usage
18
+ ## API access
19
19
 
20
- ### API Key
20
+ If you do not already have one, you can request an API Gateway key by completing the
21
+ [API Key Request Form](https://apigateway.in.ft.com/key-form).
21
22
 
22
- If you don’t already have one, you can request an API Gateway key by completing the [API Key Request Form](https://apigateway.in.ft.com/key-form).
23
+ ## Usage
23
24
 
24
25
  ### Initialize the client
25
26
 
@@ -35,38 +36,34 @@ const client = new ApiClient({
35
36
  ### Get homepage structure
36
37
 
37
38
  ```typescript
38
- // Fetch a homepage structure by pageId
39
39
  const pageId = "123e4567-e89b-12d3-a456-426614174000";
40
40
  const homepage = await client.homepage.getStructure(pageId);
41
41
 
42
- // Fetch available homepage structures by homepageListId
43
- const homepageListId = "123e4567-e89b-12d3-a456-426614174000";
44
- const structures = await client.homepage.getStructuresByHomepageListId(homepageListId);
45
-
46
- console.log(homepage.data.properties.title);
42
+ console.log(homepage.properties.title);
47
43
  ```
48
44
 
49
45
  ### Get page structure
50
46
 
51
47
  ```typescript
52
- // Fetch a page structure by pageId
53
48
  const pageId = "123e4567-e89b-12d3-a456-426614174999";
54
49
  const page = await client.page.getStructure(pageId);
55
50
 
56
- console.log(page.data.properties.title);
51
+ console.log(page.properties.title);
57
52
  ```
58
53
 
59
54
  ### Update homepage structure
60
55
 
61
56
  ```typescript
62
- import { HomepageDataApi } from "@financial-times/content-curation-client";
57
+ import { HomepageStructureInput } from "@financial-times/content-curation-client";
63
58
 
64
- // Create or update homepage structure
65
- const homepageStructure: Omit<HomepageDataApi, "type"> = {
59
+ const pageId = "58de2dc7-980b-4d51-8e45-9798f0c6b6bf";
60
+
61
+ const homepageStructure: Omit<HomepageStructureInput, "type"> = {
66
62
  properties: {
67
- pageId: "58de2dc7-980b-4d51-8e45-9798f0c6b6bf",
63
+ pageId,
68
64
  homepageListId: "123e4567-e89b-12d3-a456-426614174000",
69
65
  title: "My Updated Homepage",
66
+ publicationId: "homepage-publication-id",
70
67
  },
71
68
  children: [
72
69
  {
@@ -77,20 +74,10 @@ const homepageStructure: Omit<HomepageDataApi, "type"> = {
77
74
  },
78
75
  },
79
76
  },
80
- {
81
- type: "FlourishGraphic",
82
- properties: {
83
- heading: {
84
- text: "Interactive Chart",
85
- },
86
- flourishId: "visualisation-123",
87
- displayBehaviour: "standalone",
88
- },
89
- },
90
77
  ],
91
78
  };
92
79
 
93
- const result = await client.homepage.upsertStructure(pageId, homepageStructure);
80
+ const homepage = await client.homepage.upsertStructure(pageId, homepageStructure);
94
81
  ```
95
82
 
96
83
  ### Update page structure
@@ -98,11 +85,13 @@ const result = await client.homepage.upsertStructure(pageId, homepageStructure);
98
85
  ```typescript
99
86
  import { PageStructureInput } from "@financial-times/content-curation-client";
100
87
 
101
- // Create or update page structure
88
+ const pageId = "123e4567-e89b-12d3-a456-426614174999";
89
+
102
90
  const pageStructure: Omit<PageStructureInput, "type"> = {
103
91
  properties: {
104
- pageId: "123e4567-e89b-12d3-a456-426614174999",
92
+ pageId,
105
93
  title: "My Updated Page",
94
+ publicationId: "page-publication-id",
106
95
  },
107
96
  children: [
108
97
  {
@@ -116,58 +105,80 @@ const pageStructure: Omit<PageStructureInput, "type"> = {
116
105
  ],
117
106
  };
118
107
 
119
- const result = await client.page.upsertStructure(pageId, pageStructure);
108
+ const page = await client.page.upsertStructure(pageId, pageStructure);
120
109
  ```
121
110
 
122
- ### Error handling
111
+ ## Error handling
112
+
113
+ Client methods throw `ApiClientError` for any client-generated failure. You can narrow that
114
+ base class into transport, gateway, and service errors when you need more specific handling.
123
115
 
124
116
  ```typescript
125
- import { ApiError } from "@financial-times/content-curation-client";
117
+ import {
118
+ ApiClientError,
119
+ ApiGatewayError,
120
+ ApiServiceError,
121
+ ApiTransportError,
122
+ } from "@financial-times/content-curation-client";
126
123
 
127
124
  try {
128
- const homepageStructure = await client.homepage.getStructure("invalid-id");
125
+ await client.page.getStructure("123e4567-e89b-12d3-a456-426614174999");
129
126
  } catch (error) {
130
- if (error instanceof ApiError) {
131
- console.error(`API Error (${error.status}): ${error.message}`);
132
-
133
- if (error.errors) {
134
- console.error("Validation errors:", error.errors);
135
- }
127
+ if (error instanceof ApiTransportError) {
128
+ console.error(error.transportKind, error.message, error.cause);
129
+ } else if (error instanceof ApiGatewayError) {
130
+ console.error(error.statusCode, error.contentType, error.bodyText);
131
+ } else if (error instanceof ApiServiceError) {
132
+ console.error(error.code, error.message, error.details);
133
+ } else if (error instanceof ApiClientError) {
134
+ console.error(error.origin, error.message);
136
135
  } else {
137
- console.error("Unknown error:", error);
136
+ throw error;
138
137
  }
139
138
  }
140
139
  ```
141
140
 
141
+ ### Error metadata
142
+
143
+ All `ApiClientError` instances expose:
144
+
145
+ - `origin`: `"transport" | "gateway" | "service"`
146
+ - `statusCode`: `0` for transport failures, otherwise the HTTP status code
147
+ - `requestId`: the upstream request identifier when available
148
+ - `url`: the request URL when available
149
+ - `contentType`: the response `content-type` when a response was received
150
+ - `bodyText`: truncated raw response text when the client captured it
151
+ - `cause`: the original thrown error for wrapped failures
152
+
153
+ `ApiTransportError` also exposes `transportKind`, and `ApiServiceError` is the subtype whose
154
+ `payload` is guaranteed to match the server-side `ApiErrorPayload` schema.
155
+
142
156
  ## Advanced usage
143
157
 
144
158
  ### Custom fetch implementation
145
159
 
146
- You can provide your own fetch implementation, which is useful for caching, testing, and adding other custom behavior:
160
+ You can provide your own `fetch` implementation for testing or integration with your own
161
+ runtime concerns:
147
162
 
148
163
  ```typescript
149
164
  import { ApiClient } from "@financial-times/content-curation-client";
150
165
 
151
166
  const client = new ApiClient({
152
- baseUrl: "https://your-api-url.com/api",
167
+ baseUrl: "https://api-t.ft.com/content-curation",
153
168
  apiKey: "your-api-key",
154
169
  fetch: customFetchFunction,
155
170
  });
156
171
  ```
157
172
 
158
- ## Types
173
+ ## Useful exported types
159
174
 
160
175
  ```typescript
161
- import {
162
- HomepageDataApi,
163
- HomepageStructureApiResponse,
164
- HomepageSliceApiResponse,
176
+ import type {
177
+ ApiErrorPayload,
178
+ HomepageStructureInput,
179
+ HomepageStructureOutput,
180
+ PageDraft,
165
181
  PageStructureInput,
166
182
  PageStructureOutput,
167
183
  } from "@financial-times/content-curation-client";
168
-
169
- // Use types in your code
170
- const myPageStructureResponse: PageStructureOutput = {
171
- /* ... */
172
- };
173
184
  ```