Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion lib/adapters/REST/endpoints/template.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import type { RawAxiosRequestHeaders } from 'axios'
import type { AxiosInstance } from 'contentful-sdk-core'
import copy from 'fast-copy'
import type { SetOptional } from 'type-fest'
import type {
CursorPaginatedCollectionProp,
GetSpaceEnvironmentParams,
GetTemplateParams,
} from '../../../common-types'
import type { TemplateProps, TemplateQueryOptions } from '../../../entities/template'
import type {
CreateTemplateProps,
TemplateProps,
TemplateQueryOptions,
UpdateTemplateProps,
} from '../../../entities/template'
import type { RestEndpoint } from '../types'
import * as raw from './raw'

Expand All @@ -30,3 +37,38 @@ export const get: RestEndpoint<'Template', 'get'> = (
) => {
return raw.get<TemplateProps>(http, getBaseUrl(params) + `/${params.templateId}`, { headers })
}

export const create: RestEndpoint<'Template', 'create'> = (
http: AxiosInstance,
params: GetSpaceEnvironmentParams,
rawData: CreateTemplateProps,
headers?: RawAxiosRequestHeaders,
) => {
const data = copy(rawData)
return raw.post<TemplateProps>(http, getBaseUrl(params), data, { headers })
}

export const update: RestEndpoint<'Template', 'update'> = (
http: AxiosInstance,
params: GetTemplateParams,
rawData: UpdateTemplateProps,
headers?: RawAxiosRequestHeaders,
) => {
const data: SetOptional<typeof rawData, 'sys'> = copy(rawData)
delete data.sys
return raw.put<TemplateProps>(http, getBaseUrl(params) + `/${params.templateId}`, data, {
headers: {
...(rawData.sys?.version !== undefined && {
'X-Contentful-Version': rawData.sys.version,
}),
...headers,
},
})
}

export const del: RestEndpoint<'Template', 'delete'> = (
http: AxiosInstance,
params: GetTemplateParams,
) => {
return raw.del(http, getBaseUrl(params) + `/${params.templateId}`)
}
24 changes: 23 additions & 1 deletion lib/common-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@
CreateComponentTypeProps,
UpdateComponentTypeProps,
} from './entities/component-type'
import type { TemplateProps, TemplateQueryOptions } from './entities/template'
import type {
CreateTemplateProps,
TemplateProps,
TemplateQueryOptions,
UpdateTemplateProps,
} from './entities/template'
import type {
CreateViewProps,
UpdateViewProps,
Expand Down Expand Up @@ -303,7 +308,7 @@
select?: string
links_to_entry?: string

[key: string]: any

Check warning on line 311 in lib/common-types.ts

View workflow job for this annotation

GitHub Actions / check / lint

Unexpected any. Specify a different type

Check warning on line 311 in lib/common-types.ts

View workflow job for this annotation

GitHub Actions / check / lint

Unexpected any. Specify a different type
}

/** @internal */
Expand Down Expand Up @@ -935,6 +940,9 @@

(opts: MROpts<'Template', 'getMany', UA>): MRReturn<'Template', 'getMany'>
(opts: MROpts<'Template', 'get', UA>): MRReturn<'Template', 'get'>
(opts: MROpts<'Template', 'create', UA>): MRReturn<'Template', 'create'>
(opts: MROpts<'Template', 'update', UA>): MRReturn<'Template', 'update'>
(opts: MROpts<'Template', 'delete', UA>): MRReturn<'Template', 'delete'>

(opts: MROpts<'UIConfig', 'get', UA>): MRReturn<'UIConfig', 'get'>
(opts: MROpts<'UIConfig', 'update', UA>): MRReturn<'UIConfig', 'update'>
Expand Down Expand Up @@ -2625,6 +2633,20 @@
params: GetTemplateParams
return: TemplateProps
}
create: {
params: GetSpaceEnvironmentParams
payload: CreateTemplateProps
return: TemplateProps
}
update: {
params: GetTemplateParams
payload: UpdateTemplateProps
return: TemplateProps
}
delete: {
params: GetTemplateParams
return: void
}
}
UIConfig: {
get: { params: GetUIConfigParams; return: UIConfigProps }
Expand Down
41 changes: 40 additions & 1 deletion lib/plain/entities/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import type {
GetSpaceEnvironmentParams,
GetTemplateParams,
} from '../../common-types'
import type { TemplateProps, TemplateQueryOptions } from '../../entities/template'
import type {
CreateTemplateProps,
TemplateProps,
TemplateQueryOptions,
UpdateTemplateProps,
} from '../../entities/template'
import type { OptionalDefaults } from '../wrappers/wrap'

export type TemplatePlainClientAPI = {
Expand Down Expand Up @@ -44,4 +49,38 @@ export type TemplatePlainClientAPI = {
* ```
*/
get(params: OptionalDefaults<GetTemplateParams>): Promise<TemplateProps>

/**
* Creates a new template
* @param params the space and environment IDs
* @param data the template data
* @returns the created template
* @throws if the request fails, or the space or environment is not found
* @internal - Experimental endpoint, subject to breaking changes without notice
*/
create(
params: OptionalDefaults<GetSpaceEnvironmentParams>,
data: CreateTemplateProps,
): Promise<TemplateProps>

/**
* Updates a template (upsert)
* @param params the space, environment, and template IDs
* @param data the template data (including sys.version for optimistic locking)
* @returns the updated template
* @throws if the request fails, or the space, environment, or template is not found
* @internal - Experimental endpoint, subject to breaking changes without notice
*/
update(
params: OptionalDefaults<GetTemplateParams>,
data: UpdateTemplateProps,
): Promise<TemplateProps>

/**
* Deletes a template
* @param params the space, environment, and template IDs
* @throws if the request fails, or the space, environment, or template is not found
* @internal - Experimental endpoint, subject to breaking changes without notice
*/
delete(params: OptionalDefaults<GetTemplateParams>): Promise<void>
}
3 changes: 3 additions & 0 deletions lib/plain/plain-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,9 @@ export const createPlainClient = (
template: {
getMany: wrap(wrapParams, 'Template', 'getMany'),
get: wrap(wrapParams, 'Template', 'get'),
create: wrap(wrapParams, 'Template', 'create'),
update: wrap(wrapParams, 'Template', 'update'),
delete: wrap(wrapParams, 'Template', 'delete'),
},
uiConfig: {
get: wrap(wrapParams, 'UIConfig', 'get'),
Expand Down
80 changes: 80 additions & 0 deletions test/unit/adapters/REST/endpoints/template.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,84 @@ describe('Rest Template', { concurrent: true }, () => {
)
})
})

test('create calls correct URL with POST', async () => {
const mockResponse = {
sys: { id: 'template123', type: 'Template' },
name: 'New Template',
}

const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: mockResponse }))

return adapterMock
.makeRequest({
entityType: 'Template',
action: 'create',
userAgent: 'mocked',
params: {
spaceId: 'space123',
environmentId: 'master',
},
payload: { name: 'New Template' },
})
.then((r) => {
expect(r).to.eql(mockResponse)
expect(httpMock.post.mock.calls[0][0]).to.eql(
'/spaces/space123/environments/master/templates',
)
})
})

test('update calls correct URL with PUT and X-Contentful-Version header', async () => {
const mockResponse = {
sys: { id: 'template123', type: 'Template', version: 2 },
name: 'Updated Template',
}

const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: mockResponse }))

return adapterMock
.makeRequest({
entityType: 'Template',
action: 'update',
userAgent: 'mocked',
params: {
spaceId: 'space123',
environmentId: 'master',
templateId: 'template123',
},
payload: {
sys: { id: 'template123', type: 'Template', version: 1 },
name: 'Updated Template',
},
})
.then((r) => {
expect(r).to.eql(mockResponse)
expect(httpMock.put.mock.calls[0][0]).to.eql(
'/spaces/space123/environments/master/templates/template123',
)
expect(httpMock.put.mock.calls[0][2].headers['X-Contentful-Version']).to.eql(1)
})
})

test('delete calls correct URL', async () => {
const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: '' }))

return adapterMock
.makeRequest({
entityType: 'Template',
action: 'delete',
userAgent: 'mocked',
params: {
spaceId: 'space123',
environmentId: 'master',
templateId: 'template123',
},
})
.then(() => {
expect(httpMock.delete.mock.calls[0][0]).to.eql(
'/spaces/space123/environments/master/templates/template123',
)
})
})
})
Loading