From 49d3660ea845672ccdeec4a854c0f8385a438a90 Mon Sep 17 00:00:00 2001 From: air1one <36802613+air1one@users.noreply.github.com> Date: Fri, 10 Jan 2020 08:27:17 +0400 Subject: [PATCH] refactor(core-api): do not include /api prefix in pagination (#3381) --- .../core-api/handlers/blocks.test.ts | 18 +++++ .../core-api/handlers/bridgechains.test.ts | 17 +++++ .../core-api/handlers/businesses.test.ts | 17 +++++ .../core-api/handlers/delegates.test.ts | 17 +++++ .../core-api/handlers/locks.test.ts | 25 ++++++- .../core-api/handlers/peers.test.ts | 18 +++++ .../core-api/handlers/transactions.test.ts | 18 +++++ .../core-api/handlers/votes.test.ts | 18 +++++ .../core-api/handlers/wallets.test.ts | 17 +++++ .../core-api/src/plugins/pagination/ext.ts | 65 ++++++++++--------- 10 files changed, 198 insertions(+), 32 deletions(-) diff --git a/__tests__/integration/core-api/handlers/blocks.test.ts b/__tests__/integration/core-api/handlers/blocks.test.ts index 8a7b2c78d9..daf48a38e0 100644 --- a/__tests__/integration/core-api/handlers/blocks.test.ts +++ b/__tests__/integration/core-api/handlers/blocks.test.ts @@ -35,6 +35,24 @@ describe("API 2.0 - Blocks", () => { transactions: genesisBlock.numberOfTransactions, }); }); + + it("should give correct meta data", async () => { + const response = await utils.request("GET", "blocks"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 1, + first: "/blocks?transform=true&page=1&limit=100", + last: "/blocks?transform=true&page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/blocks?transform=true&page=1&limit=100", + totalCount: 1, + totalCountIsEstimate: false, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); }); describe("GET /blocks?orderBy=height:desc", () => { diff --git a/__tests__/integration/core-api/handlers/bridgechains.test.ts b/__tests__/integration/core-api/handlers/bridgechains.test.ts index 80415b5908..92efa4dc01 100644 --- a/__tests__/integration/core-api/handlers/bridgechains.test.ts +++ b/__tests__/integration/core-api/handlers/bridgechains.test.ts @@ -56,6 +56,23 @@ describe("API 2.0 - Bridgechains", () => { expect(response.data.data[0].bridgechainRepository).toEqual(bridgechainAsset.bridgechainRepository); expect(response.data.data[0].ports).toEqual(bridgechainAsset.ports); }); + + it("should give correct meta data", async () => { + const response = await utils.request("GET", "bridgechains"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 1, + first: "/bridgechains?page=1&limit=100", + last: "/bridgechains?page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/bridgechains?page=1&limit=100", + totalCount: 1, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); }); describe("GET /bridgechains/:id", () => { diff --git a/__tests__/integration/core-api/handlers/businesses.test.ts b/__tests__/integration/core-api/handlers/businesses.test.ts index 4bead5187f..d75d32cf43 100644 --- a/__tests__/integration/core-api/handlers/businesses.test.ts +++ b/__tests__/integration/core-api/handlers/businesses.test.ts @@ -56,6 +56,23 @@ describe("API 2.0 - Businesses", () => { expect(response.data.data[0].name).toEqual(businessAttribute.businessAsset.name); expect(response.data.data[0].website).toEqual(businessAttribute.businessAsset.website); }); + + it("should give correct meta data", async () => { + const response = await utils.request("GET", "businesses"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 1, + first: "/businesses?transform=true&page=1&limit=100", + last: "/businesses?transform=true&page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/businesses?transform=true&page=1&limit=100", + totalCount: 1, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); }); describe("GET /businesses/:id", () => { diff --git a/__tests__/integration/core-api/handlers/delegates.test.ts b/__tests__/integration/core-api/handlers/delegates.test.ts index cbe0aa634e..9fd122d38f 100644 --- a/__tests__/integration/core-api/handlers/delegates.test.ts +++ b/__tests__/integration/core-api/handlers/delegates.test.ts @@ -65,6 +65,23 @@ describe("API 2.0 - Delegates", () => { expect(response.data.data.sort((a, b) => a.rank < b.rank)).toEqual(response.data.data); }); + it("should give correct meta data", async () => { + const response = await utils.request("GET", "delegates"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 51, + first: "/delegates?page=1&limit=100", + last: "/delegates?page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/delegates?page=1&limit=100", + totalCount: 51, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); + it("should GET all the delegates sorted by votes,asc", async () => { const wm: State.IWalletManager = app.resolvePlugin("database").walletManager; const wallet: State.IWallet = wm.findByUsername("genesis_51"); diff --git a/__tests__/integration/core-api/handlers/locks.test.ts b/__tests__/integration/core-api/handlers/locks.test.ts index a619ffa228..830a6abf0c 100644 --- a/__tests__/integration/core-api/handlers/locks.test.ts +++ b/__tests__/integration/core-api/handlers/locks.test.ts @@ -1,7 +1,7 @@ import "../../../utils"; import { app } from "@arkecosystem/core-container"; -import { Database } from "@arkecosystem/core-interfaces"; +import { Database, State } from "@arkecosystem/core-interfaces"; import { Crypto, Identities, Interfaces, Utils } from "@arkecosystem/crypto"; import { TransactionFactory } from "../../../helpers"; import { genesisBlock } from "../../../utils/fixtures/testnet/block-model"; @@ -12,7 +12,7 @@ beforeAll(async () => await setUp()); afterAll(async () => await tearDown()); describe("API 2.0 - Locks", () => { - let wallets; + let wallets: State.IWallet[]; let lockIds; let walletManager; @@ -67,6 +67,27 @@ describe("API 2.0 - Locks", () => { utils.expectLock(response.data.data[0]); }); + it("should give correct meta data", async () => { + const response = await utils.request("GET", "locks"); + expect(response).toBeSuccessfulResponse(); + + const numberOfLocks = wallets.reduce( + (acc, curr) => acc + Object.keys(curr.getAttribute("htlc.locks")).length, + 0, + ); + const expectedMeta = { + count: numberOfLocks, + first: "/locks?page=1&limit=100", + last: "/locks?page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/locks?page=1&limit=100", + totalCount: numberOfLocks, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); + it("should GET all the locks sorted by expirationValue,asc", async () => { const response = await utils.request("GET", "locks", { orderBy: "expirationValue:asc" }); expect(response).toBeSuccessfulResponse(); diff --git a/__tests__/integration/core-api/handlers/peers.test.ts b/__tests__/integration/core-api/handlers/peers.test.ts index 482cec2063..a282884352 100644 --- a/__tests__/integration/core-api/handlers/peers.test.ts +++ b/__tests__/integration/core-api/handlers/peers.test.ts @@ -56,6 +56,24 @@ describe("API 2.0 - Peers", () => { expect(response.data.data[0]).toBeObject(); }); + it("should give correct meta data", async () => { + const response = await utils.request("GET", "peers"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 2, + first: "/peers?page=1&limit=100", + last: "/peers?page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/peers?page=1&limit=100", + totalCount: 2, + totalCountIsEstimate: undefined, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); + it("should GET all the peers sorted by version,asc", async () => { const response = await utils.request("GET", "peers", { orderBy: "version:asc" }); expect(response).toBeSuccessfulResponse(); diff --git a/__tests__/integration/core-api/handlers/transactions.test.ts b/__tests__/integration/core-api/handlers/transactions.test.ts index d5a42ee4e3..6baadeaed7 100644 --- a/__tests__/integration/core-api/handlers/transactions.test.ts +++ b/__tests__/integration/core-api/handlers/transactions.test.ts @@ -68,6 +68,24 @@ describe("API 2.0 - Transactions", () => { utils.expectTransaction(response.data.data[0]); }); + + it("should give correct meta data", async () => { + const response = await utils.request("GET", "transactions"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 100, + first: "/transactions?transform=true&page=1&limit=100", + last: "/transactions?transform=true&page=2&limit=100", + next: "/transactions?transform=true&page=2&limit=100", + pageCount: 2, + previous: null, + self: "/transactions?transform=true&page=1&limit=100", + totalCount: 110, + totalCountIsEstimate: true, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); }); describe("GET /transactions/:id", () => { diff --git a/__tests__/integration/core-api/handlers/votes.test.ts b/__tests__/integration/core-api/handlers/votes.test.ts index 2d179a8c71..2ffc65f4ab 100644 --- a/__tests__/integration/core-api/handlers/votes.test.ts +++ b/__tests__/integration/core-api/handlers/votes.test.ts @@ -18,6 +18,24 @@ describe("API 2.0 - Votes", () => { expect(response.data.data[0]).toBeObject(); expect(response.data.meta.count).toBeNumber(); }); + + it("should give correct meta data", async () => { + const response = await utils.request("GET", "votes"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 51, + first: "/votes?transform=true&page=1&limit=100", + last: "/votes?transform=true&page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/votes?transform=true&page=1&limit=100", + totalCount: 51, + totalCountIsEstimate: false, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); }); describe("GET /votes/:id", () => { diff --git a/__tests__/integration/core-api/handlers/wallets.test.ts b/__tests__/integration/core-api/handlers/wallets.test.ts index 23b4a60c39..b32a3448fa 100644 --- a/__tests__/integration/core-api/handlers/wallets.test.ts +++ b/__tests__/integration/core-api/handlers/wallets.test.ts @@ -61,6 +61,23 @@ describe("API 2.0 - Wallets", () => { expect(response.data.data[0].address).toBe("ANBkoGqWeTSiaEVgVzSKZd3jS7UWzv9PSo"); expect(response.data.data[0].balance).toBe("245100000000000"); }); + + it("should give correct meta data", async () => { + const response = await utils.request("GET", "wallets"); + expect(response).toBeSuccessfulResponse(); + + const expectedMeta = { + count: 53, + first: "/wallets?page=1&limit=100", + last: "/wallets?page=1&limit=100", + next: null, + pageCount: 1, + previous: null, + self: "/wallets?page=1&limit=100", + totalCount: 53, + }; + expect(response.data.meta).toEqual(expectedMeta); + }); }); describe("GET /wallets/top", () => { diff --git a/packages/core-api/src/plugins/pagination/ext.ts b/packages/core-api/src/plugins/pagination/ext.ts index 33aa1aa5d9..0ddf7c968d 100644 --- a/packages/core-api/src/plugins/pagination/ext.ts +++ b/packages/core-api/src/plugins/pagination/ext.ts @@ -10,35 +10,36 @@ interface IRoute { } export class Ext { + private readonly routePathPrefix = "/api"; private readonly routes: IRoute[] = [ - { method: "get", path: "/api/blocks" }, - { method: "get", path: "/api/blocks/{id}/transactions" }, - { method: "post", path: "/api/blocks/search" }, - { method: "get", path: "/api/bridgechains" }, - { method: "post", path: "/api/bridgechains/search" }, - { method: "get", path: "/api/businesses" }, - { method: "get", path: "/api/businesses/{id}/bridgechains" }, - { method: "post", path: "/api/businesses/search" }, - { method: "get", path: "/api/delegates" }, - { method: "get", path: "/api/delegates/{id}/blocks" }, - { method: "get", path: "/api/delegates/{id}/voters" }, - { method: "post", path: "/api/delegates/search" }, - { method: "get", path: "/api/locks" }, - { method: "post", path: "/api/locks/search" }, - { method: "post", path: "/api/locks/unlocked" }, - { method: "get", path: "/api/peers" }, - { method: "get", path: "/api/transactions" }, - { method: "post", path: "/api/transactions/search" }, - { method: "get", path: "/api/transactions/unconfirmed" }, - { method: "get", path: "/api/votes" }, - { method: "get", path: "/api/wallets" }, - { method: "get", path: "/api/wallets/top" }, - { method: "get", path: "/api/wallets/{id}/locks" }, - { method: "get", path: "/api/wallets/{id}/transactions" }, - { method: "get", path: "/api/wallets/{id}/transactions/received" }, - { method: "get", path: "/api/wallets/{id}/transactions/sent" }, - { method: "get", path: "/api/wallets/{id}/votes" }, - { method: "post", path: "/api/wallets/search" }, + { method: "get", path: "/blocks" }, + { method: "get", path: "/blocks/{id}/transactions" }, + { method: "post", path: "/blocks/search" }, + { method: "get", path: "/bridgechains" }, + { method: "post", path: "/bridgechains/search" }, + { method: "get", path: "/businesses" }, + { method: "get", path: "/businesses/{id}/bridgechains" }, + { method: "post", path: "/businesses/search" }, + { method: "get", path: "/delegates" }, + { method: "get", path: "/delegates/{id}/blocks" }, + { method: "get", path: "/delegates/{id}/voters" }, + { method: "post", path: "/delegates/search" }, + { method: "get", path: "/locks" }, + { method: "post", path: "/locks/search" }, + { method: "post", path: "/locks/unlocked" }, + { method: "get", path: "/peers" }, + { method: "get", path: "/transactions" }, + { method: "post", path: "/transactions/search" }, + { method: "get", path: "/transactions/unconfirmed" }, + { method: "get", path: "/votes" }, + { method: "get", path: "/wallets" }, + { method: "get", path: "/wallets/top" }, + { method: "get", path: "/wallets/{id}/locks" }, + { method: "get", path: "/wallets/{id}/transactions" }, + { method: "get", path: "/wallets/{id}/transactions/received" }, + { method: "get", path: "/wallets/{id}/transactions/sent" }, + { method: "get", path: "/wallets/{id}/votes" }, + { method: "post", path: "/wallets/search" }, ]; constructor(private readonly config) {} @@ -50,7 +51,10 @@ export class Ext { const { method, path } = request.route; - return this.routes.find(route => route.method === method && route.path === path) !== undefined; + return ( + this.routes.find(route => route.method === method && path === `${this.routePathPrefix}${route.path}`) !== + undefined + ); } public onPreHandler(request, h) { @@ -92,7 +96,8 @@ export class Ext { Hoek.assert(Array.isArray(results), "The results must be an array"); - const baseUri = request.url.pathname + "?"; + // strip prefix in baseUri, we want a "clean" relative path + const baseUri = request.url.pathname.slice(this.routePathPrefix.length) + "?"; const { query } = request; const currentPage = query.page; const currentLimit = query.limit;