Skip to content

Commit 34f102d

Browse files
committed
chore: experimental support for taxonomy concepts/schemes
1 parent 062a744 commit 34f102d

File tree

5 files changed

+153
-0
lines changed

5 files changed

+153
-0
lines changed

lib/create-contentful-api.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
validateResolveLinksParam,
3939
} from './utils/validate-params.js'
4040
import validateSearchParameters from './utils/validate-search-parameters.js'
41+
import { ConceptCollection } from './types/taxonomy.js'
4142

4243
const ASSET_KEY_MAX_LIFETIME = 48 * 60 * 60
4344

@@ -467,6 +468,26 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
467468
})
468469
}
469470

471+
function getConcepts<Locales extends LocaleCode>(
472+
query: Record<string, any> = {},
473+
): Promise<ConceptCollection<Locales>> {
474+
return internalGetConcepts<ConceptCollection<Locales>>(query)
475+
}
476+
477+
async function internalGetConcepts<T>(query: Record<string, any> = {}): Promise<T> {
478+
try {
479+
return get({
480+
context: 'environment',
481+
path: 'taxonomy/concepts',
482+
config: createRequestConfig({
483+
query: normalizeSearchParameters(normalizeSelect(query)),
484+
}),
485+
})
486+
} catch (error) {
487+
errorHandler(error)
488+
}
489+
}
490+
470491
/*
471492
* Switches BaseURL to use /environments path
472493
* */
@@ -496,5 +517,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
496517
getEntries,
497518

498519
createAssetKey,
520+
521+
getConcepts,
499522
} as unknown as ContentfulClientApi<undefined>
500523
}

lib/types/client.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { LocaleCode, LocaleCollection } from './locale.js'
44
import {
55
AssetQueries,
66
AssetsQueries,
7+
ConceptQueries,
78
EntriesQueries,
89
EntryQueries,
910
EntrySkeletonType,
@@ -14,6 +15,7 @@ import { Tag, TagCollection } from './tag.js'
1415
import { AssetKey } from './asset-key.js'
1516
import { Entry, EntryCollection } from './entry.js'
1617
import { Asset, AssetCollection, AssetFields } from './asset.js'
18+
import { ConceptCollection } from './taxonomy.js'
1719

1820
/**
1921
* Client chain modifiers used in all types that depend on the client configuration.
@@ -364,6 +366,25 @@ export interface ContentfulClientApi<Modifiers extends ChainModifiers> {
364366
query?: AssetsQueries<AssetFields, Modifiers>,
365367
): Promise<AssetCollection<Modifiers, Locales>>
366368

369+
/**
370+
* Fetches a collection of Taxonomy Concepts
371+
* @param query - Query object for filtering and ordering
372+
* @returns Promise for a collection of concepts
373+
* @example
374+
* const contentful = require('contentful')
375+
*
376+
* const client = contentful.createClient({
377+
* space: '<space_id>',
378+
* accessToken: '<content_delivery_api_key>'
379+
* })
380+
*
381+
* const response = await client.getConcepts()
382+
* console.log(response.items)
383+
*/
384+
getConcepts<Locales extends LocaleCode = LocaleCode>(
385+
query?: ConceptQueries,
386+
): Promise<ConceptCollection<Locales>>
387+
367388
/**
368389
* A client that will fetch assets and entries with all locales. Only available if not already enabled.
369390
*/

lib/types/query/query.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { EntrySys } from '../entry.js'
44
import { TagLink, TaxonomyConceptLink } from '../link.js'
55
import { Metadata } from '../metadata.js'
66
import { TagSys } from '../tag.js'
7+
import { ConceptSys } from '../taxonomy.js'
78
import {
89
EntryFieldsEqualityFilter,
910
EntryFieldsInequalityFilter,
@@ -219,3 +220,9 @@ export type TagQueries = TagNameFilters &
219220
SysQueries<Pick<TagSys, 'createdAt' | 'updatedAt' | 'visibility' | 'id' | 'type'>> &
220221
TagOrderFilter &
221222
FixedPagedOptions
223+
224+
/**
225+
* Search parameters for taxonomy methods
226+
*/
227+
228+
export type ConceptQueries = SysQueries<Pick<ConceptSys, 'id'>>

lib/types/taxonomy.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ContentfulCollection } from './collection'
2+
import { Link } from './link'
3+
4+
type ISODateString = string
5+
6+
export type ConceptSys = {
7+
id: string
8+
type: 'TaxonomyConcept'
9+
createdAt: ISODateString
10+
updatedAt: ISODateString
11+
version: number
12+
}
13+
14+
export interface Concept<Locales extends string = string> {
15+
sys: ConceptSys
16+
prefLabel?: {
17+
[locale in Locales]: string
18+
}
19+
altLabels?: {
20+
[locale in Locales]: string
21+
}
22+
hiddenLabels?: {
23+
[locale in Locales]: string
24+
}
25+
note?: {
26+
[locale in Locales]: string
27+
}
28+
notations?: string[]
29+
broader?: Link<'TaxonomyConcept'>[]
30+
related?: Link<'TaxonomyConcept'>[]
31+
}
32+
33+
export interface ConceptScheme {}
34+
35+
export type ConceptCollection<Locale extends string> = ContentfulCollection<Concept<Locale>>
36+
export type ConceptSchemeCollection = ContentfulCollection<ConceptScheme>

test/integration/getConcepts.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as contentful from '../../lib/contentful'
2+
// import { ValidationError } from '../../lib/utils/validation-error'
3+
import {
4+
// assetMappings,
5+
// localisedAssetMappings,
6+
params,
7+
// previewParamsWithCSM,
8+
// testEncodingDecoding,
9+
} from './utils'
10+
11+
if (process.env.API_INTEGRATION_TESTS) {
12+
params.host = '127.0.0.1:5000'
13+
params.insecure = true
14+
}
15+
16+
const client = contentful.createClient(params)
17+
// const invalidClient = contentful.createClient({
18+
// ...params,
19+
// includeContentSourceMaps: true,
20+
// })
21+
// const previewClient = contentful.createClient(previewParamsWithCSM)
22+
23+
describe.only('getConcepts', () => {
24+
test('default client', async () => {
25+
const response = await client.getConcepts()
26+
27+
expect(response.items).toBeDefined()
28+
expect(typeof response.items[0].sys.id).toBe('string')
29+
})
30+
31+
// test('client has withAllLocales modifier', async () => {
32+
// const response = await client.withAllLocales.getAsset(asset)
33+
34+
// expect(response.fields).toBeDefined()
35+
// expect(typeof response.fields.title).toBe('object')
36+
// })
37+
38+
// describe('has includeContentSourceMaps enabled', () => {
39+
// test('cdn client', async () => {
40+
// await expect(invalidClient.getAsset(asset)).rejects.toThrow(
41+
// `The 'includeContentSourceMaps' parameter can only be used with the CPA. Please set host to 'preview.contentful.com' to include Content Source Maps.`,
42+
// )
43+
// await expect(invalidClient.getAsset(asset)).rejects.toThrow(ValidationError)
44+
// })
45+
46+
// test('preview client', async () => {
47+
// const response = await previewClient.getAsset(asset)
48+
49+
// expect(response.fields).toBeDefined()
50+
// expect(typeof response.fields.title).toBe('string')
51+
// expect(response.sys.contentSourceMaps).toBeDefined()
52+
// expect(response.sys?.contentSourceMapsLookup).toBeDefined()
53+
// testEncodingDecoding(response, assetMappings)
54+
// })
55+
56+
// test('preview client withAllLocales modifier', async () => {
57+
// const response = await previewClient.withAllLocales.getAsset(asset)
58+
59+
// expect(response.fields).toBeDefined()
60+
// expect(typeof response.fields.title).toBe('object')
61+
// expect(response.sys.contentSourceMaps).toBeDefined()
62+
// expect(response.sys?.contentSourceMapsLookup).toBeDefined()
63+
// testEncodingDecoding(response, localisedAssetMappings)
64+
// })
65+
// })
66+
})

0 commit comments

Comments
 (0)