Skip to content

Commit 0362ae1

Browse files
feat: add Fragment create, update, and delete methods [DX-928] (#3001)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent e9b189d commit 0362ae1

2 files changed

Lines changed: 123 additions & 1 deletion

File tree

lib/adapters/REST/endpoints/fragment.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import type { RawAxiosRequestHeaders } from 'axios'
22
import type { AxiosInstance } from 'contentful-sdk-core'
3+
import copy from 'fast-copy'
4+
import type { SetOptional } from 'type-fest'
35
import type {
46
CursorPaginatedCollectionProp,
57
GetFragmentParams,
68
GetSpaceEnvironmentParams,
79
} from '../../../common-types'
8-
import type { FragmentProps, FragmentQueryOptions } from '../../../entities/fragment'
10+
import type {
11+
CreateFragmentProps,
12+
FragmentProps,
13+
FragmentQueryOptions,
14+
UpdateFragmentProps,
15+
} from '../../../entities/fragment'
916
import type { RestEndpoint } from '../types'
1017
import * as raw from './raw'
1118

@@ -30,3 +37,38 @@ export const get: RestEndpoint<'Fragment', 'get'> = (
3037
) => {
3138
return raw.get<FragmentProps>(http, getBaseUrl(params) + `/${params.fragmentId}`, { headers })
3239
}
40+
41+
export const create: RestEndpoint<'Fragment', 'create'> = (
42+
http: AxiosInstance,
43+
params: GetSpaceEnvironmentParams,
44+
rawData: CreateFragmentProps,
45+
headers?: RawAxiosRequestHeaders,
46+
) => {
47+
const data = copy(rawData)
48+
return raw.post<FragmentProps>(http, getBaseUrl(params), data, { headers })
49+
}
50+
51+
export const update: RestEndpoint<'Fragment', 'update'> = (
52+
http: AxiosInstance,
53+
params: GetFragmentParams,
54+
rawData: UpdateFragmentProps,
55+
headers?: RawAxiosRequestHeaders,
56+
) => {
57+
const data: SetOptional<typeof rawData, 'sys'> = copy(rawData)
58+
delete data.sys
59+
return raw.put<FragmentProps>(http, getBaseUrl(params) + `/${params.fragmentId}`, data, {
60+
headers: {
61+
...(rawData.sys?.version !== undefined && {
62+
'X-Contentful-Version': rawData.sys.version,
63+
}),
64+
...headers,
65+
},
66+
})
67+
}
68+
69+
export const del: RestEndpoint<'Fragment', 'delete'> = (
70+
http: AxiosInstance,
71+
params: GetFragmentParams,
72+
) => {
73+
return raw.del(http, getBaseUrl(params) + `/${params.fragmentId}`)
74+
}

test/unit/adapters/REST/endpoints/fragment.test.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,84 @@ describe('Rest Fragment', { concurrent: true }, () => {
125125
)
126126
})
127127
})
128+
129+
test('create calls correct URL with POST', async () => {
130+
const mockResponse = {
131+
sys: { id: 'fragment123', type: 'Fragment' },
132+
name: 'New Fragment',
133+
}
134+
135+
const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: mockResponse }))
136+
137+
return adapterMock
138+
.makeRequest({
139+
entityType: 'Fragment',
140+
action: 'create',
141+
userAgent: 'mocked',
142+
params: {
143+
spaceId: 'space123',
144+
environmentId: 'master',
145+
},
146+
payload: { name: 'New Fragment' },
147+
})
148+
.then((r) => {
149+
expect(r).to.eql(mockResponse)
150+
expect(httpMock.post.mock.calls[0][0]).to.eql(
151+
'/spaces/space123/environments/master/fragments',
152+
)
153+
})
154+
})
155+
156+
test('update calls correct URL with PUT and X-Contentful-Version header', async () => {
157+
const mockResponse = {
158+
sys: { id: 'fragment123', type: 'Fragment', version: 2 },
159+
name: 'Updated Fragment',
160+
}
161+
162+
const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: mockResponse }))
163+
164+
return adapterMock
165+
.makeRequest({
166+
entityType: 'Fragment',
167+
action: 'update',
168+
userAgent: 'mocked',
169+
params: {
170+
spaceId: 'space123',
171+
environmentId: 'master',
172+
fragmentId: 'fragment123',
173+
},
174+
payload: {
175+
sys: { id: 'fragment123', type: 'Fragment', version: 1 },
176+
name: 'Updated Fragment',
177+
},
178+
})
179+
.then((r) => {
180+
expect(r).to.eql(mockResponse)
181+
expect(httpMock.put.mock.calls[0][0]).to.eql(
182+
'/spaces/space123/environments/master/fragments/fragment123',
183+
)
184+
expect(httpMock.put.mock.calls[0][2].headers['X-Contentful-Version']).to.eql(1)
185+
})
186+
})
187+
188+
test('delete calls correct URL', async () => {
189+
const { httpMock, adapterMock } = setupRestAdapter(Promise.resolve({ data: '' }))
190+
191+
return adapterMock
192+
.makeRequest({
193+
entityType: 'Fragment',
194+
action: 'delete',
195+
userAgent: 'mocked',
196+
params: {
197+
spaceId: 'space123',
198+
environmentId: 'master',
199+
fragmentId: 'fragment123',
200+
},
201+
})
202+
.then(() => {
203+
expect(httpMock.delete.mock.calls[0][0]).to.eql(
204+
'/spaces/space123/environments/master/fragments/fragment123',
205+
)
206+
})
207+
})
128208
})

0 commit comments

Comments
 (0)