Skip to content

Commit

Permalink
feat: StreamApi
Browse files Browse the repository at this point in the history
add package that integrates stream API
  • Loading branch information
sogunshola committed Sep 8, 2022
1 parent 0708f49 commit 7fffd1e
Show file tree
Hide file tree
Showing 39 changed files with 1,039 additions and 2 deletions.
1 change: 1 addition & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"moralis",
"@moralisweb3/core",
"@moralisweb3/auth",
"@moralisweb3/streams",
"@moralisweb3/api-utils",
"@moralisweb3/evm-utils",
"@moralisweb3/sol-utils",
Expand Down
8 changes: 8 additions & 0 deletions .changeset/quiet-peas-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@moralisweb3/api-utils': minor
'@moralisweb3/core': minor
'moralis': minor
'@moralisweb3/streams': minor
---

Intergrating stream API in code base, creating a new package @moralisweb3/streams
2 changes: 1 addition & 1 deletion packages/apiUtils/src/resolvers/Endpoint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MoralisCore } from '@moralisweb3/core';

export type EndpointMethod = 'get' | 'post' | 'put';
export type EndpointMethod = 'get' | 'post' | 'put' | 'delete';

export enum EndpointBodyType {
PROPERTY = 'property',
Expand Down
15 changes: 15 additions & 0 deletions packages/apiUtils/src/resolvers/EndpointResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ export class EndpointResolver<ApiParams, Params, ApiResult, AdaptedResult, JSONR
return new ApiResultAdapter(result, this.endpoint.apiToResult, this.endpoint.resultToJson, params);
};

private delete = async (params: Params) => {
const url = this.createUrl(params);
const apiParams = this.endpoint.parseParams(params);

const searchParams = this.paramsReader.getSearchParams(apiParams);

const result = await this.requestController.delete<ApiResult>(url, searchParams, {
headers: this.createHeaders(),
});

return new ApiResultAdapter(result, this.endpoint.apiToResult, this.endpoint.resultToJson, params);
};

private createUrl(params: Params): string {
return this.baseUrl + this.endpoint.getUrl(params);
}
Expand Down Expand Up @@ -97,6 +110,8 @@ export class EndpointResolver<ApiParams, Params, ApiResult, AdaptedResult, JSONR
return this.post(params);
case 'put':
return this.put(params);
case 'delete':
return this.delete(params);
default:
return this.get(params);
}
Expand Down
1 change: 1 addition & 0 deletions packages/apiUtils/src/resolvers/PaginatedEndpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface PaginatedResult<ApiResult> {
page_size: number;
cursor: string;
result: ApiResult;
data: ApiResult;
}

export interface PaginatedEndpoint<ApiParams, Params extends PaginatedParams, ApiResult, AdaptedResult, JSONResult>
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/controllers/RequestController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,19 @@ export class RequestController {
signal: abortSignal,
});
}

public async delete<Response>(
url: string,
searchParams?: Record<string, unknown>,
options?: RequestOptions,
abortSignal?: AbortController['signal'],
): Promise<Response> {
return this.request<unknown, Response>({
url,
params: searchParams,
method: 'DELETE',
headers: options?.headers,
signal: abortSignal,
});
}
}
1 change: 1 addition & 0 deletions packages/integration/mockRequests/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const MOCK_API_KEY = 'test-api-key';
export const EVM_API_ROOT = 'https://deep-index.moralis.io/api/v2';
export const SOL_API_ROOT = 'https://solana-gateway.moralis.io';
export const STREAM_API_ROOT = 'https://streams-api.aws-prod-streams-master-1.moralis.io';
19 changes: 19 additions & 0 deletions packages/integration/mockRequests/mockRequestsStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { setupServer } from 'msw/node';

import { mockCreateStream } from './streamApi/createStream';
import { mockDeleteStream } from './streamApi/deleteStream';
import { mockGetStreams } from './streamApi/getStreams';
import { mockUpdateStream } from './streamApi/updateStream';
import { mockSetSettings } from './streamApi/setSettings';
import { mockGetSettings } from './streamApi/getSettings';

const handlers = [
mockCreateStream,
mockGetStreams,
mockUpdateStream,
mockDeleteStream,
mockSetSettings,
mockGetSettings,
];

export const mockServer = setupServer(...handlers);
23 changes: 23 additions & 0 deletions packages/integration/mockRequests/streamApi/createStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { rest } from 'msw';
import { STREAM_API_ROOT, MOCK_API_KEY } from '../config';

export const mockCreateStreamOutput: Record<string, string> = {
address: '0x992eCcC191D6F74E8Be187ed6B6AC196b08314f7',
chainId: '0x3',
};

export const mockCreateStream = rest.put(`${STREAM_API_ROOT}/streams`, (req, res, ctx) => {
const apiKey = req.headers.get('x-api-key');

if (apiKey !== MOCK_API_KEY) {
return res(ctx.status(401));
}

const value = mockCreateStreamOutput;

if (!value) {
return res(ctx.status(404));
}

return res(ctx.status(200), ctx.json(value));
});
28 changes: 28 additions & 0 deletions packages/integration/mockRequests/streamApi/deleteStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { rest } from 'msw';
import { STREAM_API_ROOT, MOCK_API_KEY } from '../config';

export const mockDeleteStreamOutput: Record<string, string> = {
'3fa85f64-5717-4562-b3fc-2c963f66afa6': '0x3',
};

export const mockDeleteStream = rest.delete(`${STREAM_API_ROOT}/streams/:id`, (req, res, ctx) => {
const id = req.params.id as string;
const apiKey = req.headers.get('x-api-key');

if (apiKey !== MOCK_API_KEY) {
return res(ctx.status(401));
}

const value = mockDeleteStreamOutput[id];

if (!value) {
return res(ctx.status(404));
}

return res(
ctx.status(200),
ctx.json({
chainId: value,
}),
);
});
23 changes: 23 additions & 0 deletions packages/integration/mockRequests/streamApi/getSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { rest } from 'msw';
import { STREAM_API_ROOT, MOCK_API_KEY } from '../config';

export const mockGetSettingsOutput: Record<string, string> = {
secretKey: 'top_secret',
region: 'us-east-1',
};

export const mockGetSettings = rest.get(`${STREAM_API_ROOT}/settings`, (req, res, ctx) => {
const apiKey = req.headers.get('x-api-key');

if (apiKey !== MOCK_API_KEY) {
return res(ctx.status(401));
}

const value = mockGetSettingsOutput;

if (!value) {
return res(ctx.status(404));
}

return res(ctx.status(200), ctx.json(value));
});
25 changes: 25 additions & 0 deletions packages/integration/mockRequests/streamApi/getStreams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { rest } from 'msw';
import { STREAM_API_ROOT, MOCK_API_KEY } from '../config';

export const mockGetStreamsOutput = 20;

export const mockGetStreams = rest.get(`${STREAM_API_ROOT}/streams`, (req, res, ctx) => {
const apiKey = req.headers.get('x-api-key');

if (apiKey !== MOCK_API_KEY) {
return res(ctx.status(401));
}

const value = mockGetStreamsOutput;

if (!value) {
return res(ctx.status(404));
}

return res(
ctx.status(200),
ctx.json({
total: value,
}),
);
});
20 changes: 20 additions & 0 deletions packages/integration/mockRequests/streamApi/setSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { rest } from 'msw';
import { STREAM_API_ROOT, MOCK_API_KEY } from '../config';

export const mockSetSettingsOutput: Record<string, string> = {};

export const mockSetSettings = rest.post(`${STREAM_API_ROOT}/settings`, (req, res, ctx) => {
const apiKey = req.headers.get('x-api-key');

if (apiKey !== MOCK_API_KEY) {
return res(ctx.status(401));
}

const value = mockSetSettingsOutput;

if (!value) {
return res(ctx.status(404));
}

return res(ctx.status(200), ctx.json(value));
});
28 changes: 28 additions & 0 deletions packages/integration/mockRequests/streamApi/updateStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { rest } from 'msw';
import { STREAM_API_ROOT, MOCK_API_KEY } from '../config';

export const mockUpdateStreamOutput: Record<string, string> = {
'3fa85f64-5717-4562-b3fc-2c963f66afa6': '0x3',
};

export const mockUpdateStream = rest.post(`${STREAM_API_ROOT}/streams/:id`, (req, res, ctx) => {
const id = req.params.id as string;
const apiKey = req.headers.get('x-api-key');

if (apiKey !== MOCK_API_KEY) {
return res(ctx.status(401));
}

const value = mockUpdateStreamOutput[id];

if (!value) {
return res(ctx.status(404));
}

return res(
ctx.status(200),
ctx.json({
chainId: value,
}),
);
});
1 change: 1 addition & 0 deletions packages/integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@moralisweb3/core": "^2.2.0",
"@moralisweb3/evm-api": "^2.2.0",
"@moralisweb3/streams": "^2.2.0",
"@moralisweb3/evm-utils": "^2.2.0",
"eventemitter3": "^4.0.7"
}
Expand Down
58 changes: 58 additions & 0 deletions packages/integration/test/streamApi/createStream.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { MoralisStreams } from '@moralisweb3/streams';
import { cleanStreamsApi, setupStreamApi } from './setup';

describe('Create stream', () => {
let StreamApi: MoralisStreams;

beforeAll(() => {
StreamApi = setupStreamApi();
});

afterAll(() => {
cleanStreamsApi();
});

it('should create a stream ', async () => {
const result = await StreamApi.add({
chainId: '0x3',
address: '0x992eCcC191D6F74E8Be187ed6B6AC196b08314f7',
tag: 'test',
description: 'test',
type: 'tx',
webhookUrl: 'https://webhook.site/4f1b1b1b-1b1b-4f1b-1b1b-1b1b1b1b1b1b',
});

expect(result).toBeDefined();
expect(result).toEqual(expect.objectContaining({}));
expect(result.result.chainId).toEqual('0x3');
});

it('should not create stream', async () => {
const failedResult = await StreamApi.add({
chainId: 'invalid_chain',
address: '0x992eCcC191D6F74E8Be187ed6B6AC196b08314f7',
tag: 'test',
description: 'test',
type: 'tx',
webhookUrl: 'https://webhook.site/4f1b1b1b-1b1b-4f1b-1b1b-1b1b1b1b1b1b',
})
.then()
.catch((err: any) => {
return err;
});

expect(failedResult).toBeDefined();
expect(
StreamApi.add({
chainId: 'invalid_chain',
address: '0x992eCcC191D6F74E8Be187ed6B6AC196b08314f7',
tag: 'test',
description: 'test',
type: 'tx',
webhookUrl: 'https://webhook.site/4f1b1b1b-1b1b-4f1b-1b1b-1b1b1b1b1b1b',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"[C0005] Invalid provided chain, value must be a positive number, or a hex-string starting with '0x'"`,
);
});
});
24 changes: 24 additions & 0 deletions packages/integration/test/streamApi/deleteStream.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MoralisStreams } from '@moralisweb3/streams';
import { cleanStreamsApi, setupStreamApi } from './setup';

describe('Delete stream', () => {
let StreamApi: MoralisStreams;

beforeAll(() => {
StreamApi = setupStreamApi();
});

afterAll(() => {
cleanStreamsApi();
});

it('should delete a stream ', async () => {
const result = await StreamApi.delete({
id: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
});

expect(result).toBeDefined();
expect(result).toEqual(expect.objectContaining({}));
expect(result.result.chainId).toEqual('0x3');
});
});
22 changes: 22 additions & 0 deletions packages/integration/test/streamApi/getSettings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { MoralisStreams } from '@moralisweb3/streams';
import { cleanStreamsApi, setupStreamApi } from './setup';

describe('Get settings', () => {
let StreamApi: MoralisStreams;

beforeAll(() => {
StreamApi = setupStreamApi();
});

afterAll(() => {
cleanStreamsApi();
});

it('should get stream settings ', async () => {
const result = await StreamApi.readSettings();

expect(result).toBeDefined();
expect(result).toEqual(expect.objectContaining({}));
expect(result.result.region).toEqual('us-east-1');
});
});
24 changes: 24 additions & 0 deletions packages/integration/test/streamApi/getStreams.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MoralisStreams } from '@moralisweb3/streams';
import { cleanStreamsApi, setupStreamApi } from './setup';

describe('Get stream', () => {
let StreamApi: MoralisStreams;

beforeAll(() => {
StreamApi = setupStreamApi();
});

afterAll(() => {
cleanStreamsApi();
});

it('should get all streams', async () => {
const result = await StreamApi.getAll({
limit: 20,
});

expect(result).toBeDefined();
expect(result.result).toBeDefined();
expect(result.pagination.total).toEqual(20);
});
});
Loading

0 comments on commit 7fffd1e

Please sign in to comment.