Skip to content

Commit 3d612c8

Browse files
authored
Merge pull request #94 from companieshouse/BI-6633-add-alphabetical-search
add search service
2 parents ac96ba4 + b17109d commit 3d612c8

File tree

8 files changed

+149
-5
lines changed

8 files changed

+149
-5
lines changed

src/client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { BasketService, OrderService, CertificateService, CertifiedCopiesService
77
import { PaymentService } from "./services/payment/";
88
import CompanyFilingHistoryService from "./services/company-filing-history/service";
99
import { RefreshTokenService } from "./services/refresh-token";
10+
import AlphabeticalSearchService from "./services/search/alphabetical-search/service";
1011

1112
/**
1213
* ApiClient is the class that all service objects hang off.
@@ -24,6 +25,7 @@ export default class ApiClient {
2425
public readonly order: OrderService;
2526
public readonly mid : MidService;
2627
public readonly refreshToken: RefreshTokenService;
28+
public readonly alphabeticalSearch: AlphabeticalSearchService;
2729

2830
constructor (readonly apiClient: IHttpClient, readonly accountClient: IHttpClient) {
2931
// services on the api domain using the apiClient
@@ -38,6 +40,7 @@ export default class ApiClient {
3840
this.payment = new PaymentService(apiClient); // TODO split payments url/domain into a separate config item and http client
3941
this.order = new OrderService(apiClient);
4042
this.mid = new MidService(apiClient);
43+
this.alphabeticalSearch = new AlphabeticalSearchService(apiClient);
4144
// service on the account/identity domain using the accountClient
4245
// e.g. user profile service can be added here when required
4346
this.refreshToken = new RefreshTokenService(accountClient);

src/http/http-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export default interface IHttpClient {
6464
* @param url the url relative to the base url
6565
*/
6666
httpGet(url: string): Promise<HttpResponse>;
67-
httpPost(url: string, body?: any): Promise<HttpResponse>;
67+
httpPost(url: string, body?: any, headers?: Headers): Promise<HttpResponse>;
6868
httpPatch(url: string, body?: any, headers?: Headers): Promise<HttpResponse>;
6969
httpPut(url: string, body?: any, headers?: Headers): Promise<HttpResponse>;
7070
httpDelete(url: string): Promise<HttpResponse>;
@@ -124,7 +124,7 @@ export abstract class AbstractClient implements IHttpClient {
124124
*/
125125
public abstract httpGet(url: string): Promise<HttpResponse>;
126126

127-
public abstract httpPost(url: string, body?: any): Promise<HttpResponse>;
127+
public abstract httpPost(url: string, body?: any, headers?: Headers): Promise<HttpResponse>;
128128

129129
public abstract httpPatch(url: string, body?: any, headers?: Headers): Promise<HttpResponse>;
130130

src/http/request-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export default class RequestClient extends AbstractClient {
1010
return this.request({ method: "GET", url });
1111
}
1212

13-
public async httpPost (url: string, body?: any): Promise<HttpResponse> {
14-
return this.request({ method: "POST", url, body });
13+
public async httpPost (url: string, body?: any, headers?: Headers): Promise<HttpResponse> {
14+
return this.request({ method: "POST", url, body, headers });
1515
}
1616

1717
public async httpPatch (url: string, body?: any, headers?: Headers): Promise<HttpResponse> {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as AlphabeticalSearchService } from "./service";
2+
export * from "./types";
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { IHttpClient } from "../../../http";
2+
import { AlphabeticalSearchPostRequest, CompaniesResource } from "./types";
3+
import Resource from "../../resource";
4+
5+
export default class AlphabeticalSearchService {
6+
constructor (private readonly client: IHttpClient) { }
7+
public async getCompanies (companyName: AlphabeticalSearchPostRequest, requestId: string): Promise<Resource<CompaniesResource>> {
8+
const additionalHeaders = {
9+
"X-Request-ID": requestId,
10+
"Content-Type": "application/json"
11+
}
12+
13+
const resp = await this.client.httpPost("/alphabetical-search/corporate-name", companyName, additionalHeaders);
14+
15+
const resource: Resource<CompaniesResource> = {
16+
httpStatusCode: resp.status
17+
};
18+
19+
if (resp.error) {
20+
return resource;
21+
}
22+
23+
resource.resource = resp.body as CompaniesResource;
24+
25+
return resource;
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export interface CompaniesResource {
2+
searchType: string;
3+
topHit: string;
4+
results: Result[];
5+
}
6+
7+
export interface Result {
8+
ID: string;
9+
company_type: string;
10+
items: Items;
11+
links: Links;
12+
}
13+
14+
export interface Items {
15+
company_number: string;
16+
company_status: string;
17+
corporate_name: string;
18+
record_type: string;
19+
}
20+
21+
export interface Links {
22+
self: string;
23+
}
24+
25+
// AlphabeticalSearchPostRequest
26+
export interface AlphabeticalSearchPostRequest {
27+
company_name: string
28+
}

test/http/http-client.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AbstractClient, HttpResponse } from "../../src/http";
33
const expect = chai.expect;
44

55
class TestClient extends AbstractClient {
6-
public httpPost (url: string, body: any): Promise<HttpResponse> {
6+
public httpPost (url: string, body: any, headers: any): Promise<HttpResponse> {
77
throw new Error("Method not implemented.");
88
}
99

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import chai from "chai";
2+
import sinon from "sinon";
3+
4+
import { AlphabeticalSearchService } from "../../../../src/services/search/alphabetical-search";
5+
import { RequestClient } from "../../../../src/http";
6+
import { AlphabeticalSearchPostRequest, CompaniesResource } from "../../../../src/services/search/alphabetical-search/types";
7+
import Resource from "../../../../src/services/resource";
8+
const expect = chai.expect;
9+
10+
const requestClient = new RequestClient({ baseUrl: "URL-NOT-USED", oauthToken: "TOKEN-NOT-USED" });
11+
12+
const mockResponseBody : CompaniesResource = ({
13+
searchType: "",
14+
topHit: "TEST COMPANY",
15+
results: [
16+
{
17+
ID: "FC022000",
18+
company_type: "oversea-company",
19+
items: {
20+
company_number: "FC022000",
21+
company_status: "active",
22+
corporate_name: "corporate name",
23+
record_type: "record type"
24+
},
25+
links: {
26+
self: "/company/FC022000"
27+
}
28+
}
29+
]
30+
});
31+
32+
const mockRequestBody: AlphabeticalSearchPostRequest = ({
33+
company_name: "TEST"
34+
});
35+
36+
const mockRequestId = "fdskfhsdoifhsffsif";
37+
38+
describe("create a alphabetical search POST", () => {
39+
beforeEach(() => {
40+
sinon.reset();
41+
sinon.restore();
42+
});
43+
44+
afterEach(done => {
45+
sinon.reset();
46+
sinon.restore();
47+
done();
48+
});
49+
50+
it("returns an error response on failure", async () => {
51+
const mockPostRequest = {
52+
status: 401,
53+
error: "An error occurred"
54+
};
55+
56+
const mockRequest = sinon.stub(requestClient, "httpPost").resolves(mockPostRequest);
57+
const search: AlphabeticalSearchService = new AlphabeticalSearchService(requestClient);
58+
const data: Resource<CompaniesResource> = await search.getCompanies(mockRequestBody, mockRequestId);
59+
60+
expect(data.httpStatusCode).to.equal(401);
61+
expect(data.resource).to.be.undefined;
62+
});
63+
64+
it("returns alphabetical search results correctly", async () => {
65+
const mockPostRequest = {
66+
status: 200,
67+
body: mockResponseBody
68+
};
69+
70+
const mockRequest = sinon.stub(requestClient, "httpPost").resolves(mockPostRequest);
71+
const search: AlphabeticalSearchService = new AlphabeticalSearchService(requestClient);
72+
const data: Resource<CompaniesResource> = await search.getCompanies(mockRequestBody, mockRequestId);
73+
74+
expect(data.httpStatusCode).to.equal(200);
75+
expect(data.resource.topHit).to.equal(mockResponseBody.topHit);
76+
expect(data.resource.results[0].ID).to.equal(mockResponseBody.results[0].ID);
77+
expect(data.resource.results[0].company_type).to.equal(mockResponseBody.results[0].company_type)
78+
expect(data.resource.results[0].items.company_number).to.equal(mockResponseBody.results[0].items.company_number);
79+
expect(data.resource.results[0].items.company_status).to.equal(mockResponseBody.results[0].items.company_status);
80+
expect(data.resource.results[0].items.corporate_name).to.equal(mockResponseBody.results[0].items.corporate_name);
81+
expect(data.resource.results[0].items.record_type).to.equal(mockResponseBody.results[0].items.record_type);
82+
expect(data.resource.results[0].links).to.equal(mockResponseBody.results[0].links);
83+
});
84+
});

0 commit comments

Comments
 (0)