Skip to content

Commit 621dab7

Browse files
authored
Merge pull request #130 from contentstack/feat/MKT-6394-sdk-support
feat:support for management-sdk and axios adapter
2 parents 634a04c + 8ec7400 commit 621dab7

File tree

8 files changed

+94
-145
lines changed

8 files changed

+94
-145
lines changed

__test__/uiLocation.test.ts

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import {
1212
LocationType,
1313
Region,
1414
} from "../src/types";
15-
import { ApiRequestProps } from '../src/types/stack.types';
16-
import { dispatchPostRobotRequest } from '../src/utils/adapter';
17-
import { onData, onError } from '../src/utils/utils';
15+
import { RequestOption } from '../src/types/common.types';
16+
import { ApiRequestParams } from '../src/types/api.type';
1817

1918
jest.mock("post-robot");
2019
jest.mock("wolfy87-eventemitter");
@@ -136,41 +135,35 @@ describe("UI Location", () => {
136135

137136
describe('dispatchPostRobotRequest', () => {
138137
let mockPostRobot: typeof postRobot;
139-
let opts: ApiRequestProps;
138+
let opts: RequestOption;
140139
let uiLocationInstance: UiLocation;
141140
let onError: jest.Mock;
142141

143142
beforeEach(() => {
144143
mockPostRobot = postRobot;
145-
opts = { method: 'GET', url: '/test' };
144+
opts = { method: 'GET' };
146145
uiLocationInstance = new UiLocation(initData);
147146
onError = jest.fn();
148147
uiLocationInstance.api = jest.fn().mockResolvedValue({
149148
method: 'GET',
150-
url: '/test?limit=10&skip=0',
151-
body: {}
149+
url: "https://test.com/test?limit=10&skip=0"
152150
});
153151
});
154152

155153
it('should call sendToParent with the correct arguments and resolve with data', async () => {
156154
const mockData = { success: true };
157155
// Call the method that uses uiLocationInstance.api
158-
const result = await uiLocationInstance.api({
159-
method: 'GET',
160-
url: '/test?limit=10&skip=0',
161-
body: {}
156+
const result = await uiLocationInstance.api("https://test.com/test?limit=10&skip=0",{
157+
method: 'GET'
162158
});
163159

164160
// Assertions
165-
expect(uiLocationInstance.api).toHaveBeenCalledWith({
166-
method: 'GET',
167-
url: '/test?limit=10&skip=0',
168-
body: {}
161+
expect(uiLocationInstance.api).toHaveBeenCalledWith('https://test.com/test?limit=10&skip=0',{
162+
method: 'GET'
169163
});
170164
expect(result).toEqual({
171165
method: 'GET',
172-
url: '/test?limit=10&skip=0',
173-
body: {}
166+
url: 'https://test.com/test?limit=10&skip=0',
174167
});
175168

176169
});
@@ -187,28 +180,27 @@ describe("UI Location", () => {
187180
});
188181

189182
// Call the method that uses uiLocationInstance.api and expect it to throw an error
190-
await expect(uiLocationInstance.api({
191-
method: 'GET',
192-
url: '/test?limit=10&skip=0',
193-
body: {}
183+
await expect(uiLocationInstance.api("https://test.com/test?limit=10&skip=0",{
184+
method: 'GET'
194185
})).rejects.toThrow('Test error');
195186
});
196187
});
197188

198189

199190
describe("createSDKAdapter", () => {
200191
let mockPostRobot: typeof postRobot;
201-
let opts: ApiRequestProps;
192+
let opts: ApiRequestParams;
202193
let uiLocationInstance: UiLocation;
203194
let onError: jest.Mock;
204195
beforeEach(() => {
205196
mockPostRobot = postRobot;
206-
opts = { method: 'GET', url: '/test' };
197+
opts = { method: 'GET', baseURL:"https://test.com", url:"/test?limit10&skip=0" };
207198
uiLocationInstance = new UiLocation(initData);
208199
onError = jest.fn();
209200
uiLocationInstance.createAdapter = jest.fn().mockResolvedValue({
210201
method: 'GET',
211202
url: '/test?limit=10&skip=0',
203+
baseURL: 'https://test.com',
212204
data: {}
213205
});
214206
});
@@ -228,18 +220,21 @@ describe("UI Location", () => {
228220
const result = await uiLocationInstance.createAdapter({
229221
method: 'GET',
230222
url: '/test?limit=10&skip=0',
223+
baseURL: 'https://test.com',
231224
data: {}
232225
});
233226

234227
// Assertions
235228
expect(uiLocationInstance.createAdapter).toHaveBeenCalledWith({
236229
method: 'GET',
237230
url: '/test?limit=10&skip=0',
231+
baseURL: 'https://test.com',
238232
data: {}
239233
});
240234
expect(result).toEqual({
241235
method: 'GET',
242236
url: '/test?limit=10&skip=0',
237+
baseURL: 'https://test.com',
243238
data: {}
244239
});
245240
})
@@ -259,6 +254,7 @@ describe("UI Location", () => {
259254
await expect(uiLocationInstance.createAdapter({
260255
method: 'GET',
261256
url: '/test?limit=10&skip=0',
257+
baseURL: 'https://test.com',
262258
data: {}
263259
})).rejects.toThrow('Test error');
264260
})

src/stack/api/base.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import Query from './query';
33
import { transform, addParam } from '../utils';
44
import { dispatchPostRobotRequest } from "../../utils/adapter.ts";
5-
import { ApiRequestProps } from '../../types/stack.types';
65

76

87
function onData(data: { data: any; }) {

src/types/api.type.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { HTTPMethods } from './common.types';
2+
3+
export interface ApiRequestParams {
4+
url: string;
5+
method: HTTPMethods;
6+
baseURL?: string;
7+
headers?: Record<string, string>;
8+
data?: unknown;
9+
[key: string]: any;
10+
}
11+
12+
export interface ApiResponse<T = any> {
13+
data: T;
14+
status: number;
15+
statusText: string;
16+
headers: Record<string, string>;
17+
request?: any;
18+
}

src/types/axios.type.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/types/common.types.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,12 @@ type _HTTPMethods = 'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'OPTI
1212

1313
export type HTTPMethods = Uppercase<_HTTPMethods> | Lowercase<_HTTPMethods>
1414

15-
export type ApiRequestProps = {
15+
export type RequestOption = {
1616
method: HTTPMethods,
17-
url: string,
1817
headers?: GenericObjectType,
1918
body?: unknown,
20-
params?:GenericObjectType
21-
multipart_data?: {
22-
[key:string]: {
23-
"type": string,
24-
"value": any
25-
}
26-
}
27-
}
19+
[key:string]: any
20+
}
21+
export type RequestHandler = {
22+
url: string,
23+
} & RequestOption

src/types/stack.types.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Entry from "../entry";
2-
import { AnyProperty, GenericObjectType } from "./common.types";
2+
import { AnyProperty, GenericObjectType, HTTPMethods } from "./common.types";
33

44
export declare interface StackDetail {
55
created_at: string;
@@ -150,20 +150,4 @@ export interface PublishDetails extends AnyProperty {
150150
locales: Array<String>;
151151
publish_with_reference: boolean;
152152
rules: GenericObjectType;
153-
}
154-
155-
export type RequestMethods = "GET" | "POST" | "PUT" | "DELETE";
156-
157-
export type ApiRequestProps = {
158-
method: RequestMethods,
159-
url: string,
160-
headers?: GenericObjectType,
161-
body?: unknown,
162-
params?:GenericObjectType
163-
multipart_data?: {
164-
[key:string]: {
165-
"type": string,
166-
"value": any
167-
}
168-
}
169-
}
153+
}

src/uiLocation.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@ import {
2727
Manifest,
2828
Region,
2929
} from "./types";
30-
import { GenericObjectType } from "./types/common.types";
30+
import { GenericObjectType, RequestOption } from "./types/common.types";
3131
import { User } from "./types/user.types";
3232
import { formatAppRegion, onData, onError } from "./utils/utils";
3333
import Window from "./window";
34-
import { ApiRequestProps } from './types/stack.types';
3534
import { createSDKAdapter, dispatchPostRobotRequest } from './utils/adapter';
36-
import { AxiosRequestConfig, AxiosResponse } from './types/axios.type';
35+
import {ApiRequestParams, ApiResponse } from './types/api.type';
3736

3837
const emitter = new EventEmitter();
3938

@@ -78,13 +77,6 @@ class UiLocation {
7877
*/
7978
stack: Stack;
8079

81-
api: (payload:ApiRequestProps)=> Promise<GenericObjectType>;
82-
83-
/**
84-
* This holds the instance of the createAdapter method that provides ability to app-sdk to integrate javascript management sdk.
85-
*/
86-
createAdapter: (config: AxiosRequestConfig) => Promise<AxiosResponse<GenericObjectType>>;
87-
8880
/**
8981
* Store to persist data for the app.
9082
* Note: Data is stored in the browser's {@link external:localStorage} and will be lost if the {@link external:localStorage} is cleared in the browser.
@@ -157,10 +149,6 @@ class UiLocation {
157149
currentBranch: initializationData.currentBranch,
158150
});
159151

160-
this.api = (payload:ApiRequestProps)=> dispatchPostRobotRequest(postRobot, payload);
161-
162-
this.createAdapter = createSDKAdapter(postRobot);
163-
164152
this.metadata = new Metadata(postRobot);
165153

166154
this.config = initializationData.config ?? {};
@@ -455,6 +443,18 @@ class UiLocation {
455443
return this.region;
456444
};
457445

446+
/**
447+
* Method used to make an API request to the Contentstack's CMA APIs.
448+
*/
449+
450+
api = (url: string, option?: RequestOption) => dispatchPostRobotRequest(this.postRobot)(url, option );
451+
452+
/**
453+
* Method used to create an adapter for management sdk.
454+
*/
455+
456+
createAdapter = <T>(config: unknown) => createSDKAdapter(this.postRobot)(config as unknown as ApiRequestParams) as Promise<ApiResponse<T>>;
457+
458458
/**
459459
* Method used to initialize the App SDK.
460460
* @param version - Version of the app SDK in use.

src/utils/adapter.ts

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,37 @@
1-
import PostRobot from "post-robot";
2-
import { onData, onError } from "./utils";import { AxiosRequestConfig, AxiosResponse } from '../types/axios.type';
3-
import { ApiRequestProps, GenericObjectType } from '../types/common.types';
1+
import PostRobot from 'post-robot';
2+
import { onData, onError } from './utils';
3+
import { ApiRequestParams } from '../types/api.type';
4+
import { RequestOption, GenericObjectType } from '../types/common.types';
45

5-
export function createSDKAdapter(postRobot: typeof PostRobot): (config: AxiosRequestConfig) => Promise<AxiosResponse<GenericObjectType>> {
6-
return async (config: AxiosRequestConfig): Promise<AxiosResponse<GenericObjectType>> => {
7-
const req: ApiRequestProps = {
8-
url: config?.url,
9-
method: config?.method,
10-
headers: config?.headers,
11-
body: config?.data,
12-
params: config?.params,
13-
};
14-
15-
try {
16-
const data = await dispatchPostRobotRequest(postRobot, req) as GenericObjectType;
17-
return {
18-
data,
19-
status: data.status || 200,
20-
statusText: 'OK',
21-
headers: config.headers || {},
22-
config,
23-
request: req,
24-
};
25-
} catch (error) {
26-
const typedError = error as GenericObjectType & { status?: number; statusText?: string; headers?: Record<string, string> };
27-
return {
28-
data: typedError,
29-
status: typedError.status || 500,
30-
statusText: typedError.statusText || 'Internal Server Error',
31-
headers: typedError.headers || {},
32-
config,
33-
request: req,
34-
};
35-
}
36-
};
37-
}
6+
export const dispatchPostRobotRequest = (postRobot: typeof PostRobot) => (url:string ,opts?: RequestOption): Promise<GenericObjectType> => {
7+
return postRobot
8+
.sendToParent("apiAdapter", {url, option:opts})
9+
.then(onData)
10+
.catch(onError);
11+
};
3812

39-
export function dispatchPostRobotRequest(postRobot: typeof PostRobot, opts:ApiRequestProps):Promise<any> {
40-
return postRobot
41-
.sendToParent("apiAdapter", opts)
42-
.then(onData)
43-
.then((data) => data)
44-
.catch(onError);
45-
}
13+
export const createSDKAdapter = (postRobot: typeof PostRobot) => async (config: ApiRequestParams) => {
14+
try {
15+
const data = await dispatchPostRobotRequest(postRobot)(config.url, {
16+
baseURL: config.baseURL,
17+
url: config.url,
18+
method: config.method,
19+
headers: config.headers,
20+
body: config.data as BodyInit,
21+
});
22+
return {
23+
data,
24+
status: data?.status || 200,
25+
statusText: 'OK',
26+
headers: config.headers || {},
27+
};
28+
} catch (error) {
29+
const typedError = error as GenericObjectType & { status?: number; statusText?: string; headers?: Record<string, string>; body?: any; message?: string };
30+
return {
31+
data: typedError.body || typedError.message || typedError.data,
32+
status: typedError.status || 500,
33+
statusText: typedError.statusText || 'Internal Server Error',
34+
headers: typedError.headers || {},
35+
};
36+
}
37+
};

0 commit comments

Comments
 (0)