Skip to content

Commit be8d9d7

Browse files
committed
feat(#9835): implement postResource for creation
1 parent e0ecefe commit be8d9d7

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

shared-libs/cht-datasource/src/remote/libs/data-context.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,28 @@ export const getResources = (context: RemoteDataContext, path: string) => async
8383
throw error;
8484
}
8585
};
86+
87+
/** @internal */
88+
export const postResource = (context: RemoteDataContext, path: string) => async <T>(
89+
body: Record<string, unknown>,
90+
): Promise<T> => {
91+
try {
92+
const response = await fetch(`${context.url}/${path}`, {
93+
method: 'POST',
94+
headers: {
95+
'Content-Type': 'application/json',
96+
},
97+
body: JSON.stringify(body)});
98+
if (response.status === 400) {
99+
const errorMessage = await response.text();
100+
throw new InvalidArgumentError(errorMessage);
101+
} else if (!response.ok) {
102+
throw new Error(response.statusText);
103+
}
104+
105+
return (await response.json()) as T;
106+
} catch (error) {
107+
logger.error(`Failed to post ${JSON.stringify(body)} to ${context.url}/${path}.`, error);
108+
throw error;
109+
}
110+
};

shared-libs/cht-datasource/test/remote/libs/data-context.spec.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
getResources,
88
getRemoteDataContext,
99
isRemoteDataContext,
10-
RemoteDataContext
10+
RemoteDataContext,
11+
postResource
1112
} from '../../../src/remote/libs/data-context';
1213
import { DataContext, InvalidArgumentError } from '../../../src';
1314

@@ -173,6 +174,70 @@ describe('remote context lib', () => {
173174
});
174175
});
175176

177+
describe('postResource', () => {
178+
it('throws InvalidArgumentError if the Bad Request - 400 status is returned', async () => {
179+
const path = 'path';
180+
const qualifier = {
181+
name: 'user-1',
182+
contact: {
183+
_id: '1',
184+
parent: {
185+
_id: '2'
186+
}
187+
}
188+
};
189+
const errorMsg = `Missing or empty required fields [${JSON.stringify(qualifier)}].`;
190+
fetchResponse.ok = false;
191+
fetchResponse.status = 400;
192+
fetchResponse.statusText = errorMsg;
193+
194+
fetchResponse.text.resolves(errorMsg);
195+
const expectedError = new InvalidArgumentError(errorMsg);
196+
await expect(postResource(context, path)(qualifier)).to.be.rejectedWith(errorMsg);
197+
198+
expect(fetchStub.calledOnceWithExactly(`${context.url}/${path}`,
199+
{
200+
method: 'POST',
201+
headers: {
202+
'Content-Type': 'application/json',
203+
},
204+
body: JSON.stringify(qualifier)})).to.be.true;
205+
206+
expect(fetchResponse.text.called).to.be.true;
207+
expect(fetchResponse.json.notCalled).to.be.true;
208+
expect(loggerError.args[0]).to.deep.equal([
209+
`Failed to post ${JSON.stringify(qualifier)} to ${context.url}/${path}.`,
210+
expectedError
211+
]);
212+
});
213+
214+
it('creates a resource for valid req body and path', async () => {
215+
const path = 'path';
216+
const qualifier = {
217+
name: 'city-1',
218+
type: 'place'
219+
};
220+
221+
const expoected_response = {...qualifier, _id: '1', _rev: '1', _reported_date: 123123123 };
222+
fetchResponse.ok = true;
223+
fetchResponse.status = 200;
224+
fetchResponse.json.resolves(expoected_response);
225+
226+
const response = await postResource(context, path)(qualifier);
227+
228+
expect(response).to.deep.equal(expoected_response);
229+
expect(fetchStub.calledOnceWithExactly(`${context.url}/${path}`,
230+
{
231+
method: 'POST',
232+
headers: {
233+
'Content-Type': 'application/json',
234+
},
235+
body: JSON.stringify(qualifier)})).to.be.true;
236+
237+
expect(fetchResponse.json.calledOnceWithExactly()).to.be.true;
238+
});
239+
});
240+
176241
describe('getResources', () => {
177242
const params = {abc: 'xyz'};
178243
const stringifiedParams = new URLSearchParams(params).toString();

0 commit comments

Comments
 (0)