Skip to content

Commit 18f7dbe

Browse files
authored
Get report route (#6)
* feat: add arango connection Arango collection is established using central library * feat: add route for getting report by msgid * feat: add logging to the microservice * docs: add readme documentation and diagrams * refactor: fastify swagger docs This commit adds swagger to the fastify interface and attaches parameter schema for docs * fix: remove request method not used * feat: dockerzing the admin service * fix: add env variables to template * feat: add husky to admin service * style: fix prettier errors * test: adding unit test to admin service * docs: add license header
1 parent 33232a1 commit 18f7dbe

23 files changed

+2013
-113
lines changed

.env.template

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# SPDX-License-Identifier: Apache-2.0
2+
FUNCTION_NAME=admin-service
3+
NODE_ENV=dev
24

35
# Fastify
46
PORT=3100
57
HOST='0.0.0.0'
8+
9+
# ArangoDB
10+
TRANSACTION_DATABASE=evaluationResults
11+
TRANSACTION_DATABASE_URL=tcp://0.0.0.0:8529
12+
TRANSACTION_DATABASE_USER=root
13+
TRANSACTION_DATABASE_PASSWORD=
14+
TRANSACTION_DATABASE_CERT_PATH=

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
12
# Logs
23
logs
34
*.log

.husky/pre-commit

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
npx lint-staged

.husky/pre-push

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
npm test

Dockerfile

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
ARG BUILD_IMAGE=node:20-bullseye
3+
ARG RUN_IMAGE=gcr.io/distroless/nodejs20-debian11:nonroot
4+
5+
FROM ${BUILD_IMAGE} AS builder
6+
LABEL stage=build
7+
# TS -> JS stage
8+
9+
WORKDIR /home/app
10+
COPY ./src ./src
11+
COPY ./package*.json ./
12+
COPY ./tsconfig.json ./
13+
COPY .npmrc ./
14+
ARG GH_TOKEN
15+
16+
RUN npm ci --ignore-scripts
17+
RUN npm run build
18+
19+
FROM ${BUILD_IMAGE} AS dep-resolver
20+
LABEL stage=pre-prod
21+
# To filter out dev dependencies from final build
22+
23+
COPY package*.json ./
24+
COPY .npmrc ./
25+
ARG GH_TOKEN
26+
RUN npm ci --omit=dev --ignore-scripts
27+
28+
FROM ${RUN_IMAGE} AS run-env
29+
USER nonroot
30+
31+
WORKDIR /home/app
32+
COPY --from=dep-resolver /node_modules ./node_modules
33+
COPY --from=builder /home/app/build ./build
34+
COPY package.json ./
35+
36+
# Turn down the verbosity to default level.
37+
ENV NPM_CONFIG_LOGLEVEL warn
38+
39+
ENV mode="http"
40+
ENV upstream_url="http://127.0.0.1:3000"
41+
ENV exec_timeout="10s"
42+
ENV write_timeout="15s"
43+
ENV read_timeout="15s"
44+
ENV prefix_logs="false"
45+
46+
# Service Based variables
47+
ENV FUNCTION_NAME=admin-service
48+
ENV NODE_ENV=production
49+
ENV PORT=3000
50+
51+
# Database
52+
ENV TRANSACTION_DATABASE_CERT_PATH='/usr/local/share/ca-certificates/ca-certificates.crt'
53+
ENV TRANSACTION_DATABASE_URL=tcp://0.0.0.0:8529
54+
ENV TRANSACTION_DATABASE_USER=root
55+
ENV TRANSACTION_DATABASE_PASSWORD=
56+
ENV TRANSACTION_DATABASE=evaluationResults
57+
58+
HEALTHCHECK --interval=60s CMD [ -e /tmp/.lock ] || exit 1
59+
EXPOSE 4222
60+
61+
# Execute watchdog command
62+
CMD ["build/index.js"]

Images/Flowchart_GetReportByMsgid.PNG

23.4 KB
Loading
37.5 KB
Loading

README.md

+121
Original file line numberDiff line numberDiff line change
@@ -1 +1,122 @@
11
<!-- SPDX-License-Identifier: Apache-2.0 -->
2+
# Admin Service Documentation
3+
4+
## Overview
5+
6+
The **Admin service** is a Node.js-based API designed for administrative tasks, particularly focusing on report management. It leverages the **Fastify** framework to provide a high-performance and low-overhead API interface. This document provides an in-depth look at the API, including setup requirements, a detailed overview of the application, and specific route documentation.
7+
8+
## Pre-requisites
9+
10+
Before you start using the Admin API, ensure that you have the following items:
11+
12+
1. **Node.js**: Version 20.x or higher.
13+
- Download from [Node.js Official Website](https://nodejs.org/).
14+
- Verify installation using `node -v` and `npm -v`.
15+
16+
2. **NPM**: A package manager for Node.js packages.
17+
- NPM is installed with Node.js.
18+
19+
3. **Git**: Version control system for cloning the repository.
20+
- Download from [Git Official Website](https://git-scm.com/).
21+
22+
4. **Database**: Arango database setup.
23+
- Ensure the database is running and accessible from your Node.js environment.
24+
25+
5. **Environment Variables**: Set up environment variables required by the application, such as database connection strings. Typically stored in a `.env` file.
26+
27+
## Installation and Setup
28+
29+
1. **Clone the Repository**:
30+
```bash
31+
git clone https://github.com/@frmscoe/admin-service.git
32+
cd admin-service
33+
```
34+
35+
2. **Install Dependencies**:
36+
```bash
37+
npm install
38+
```
39+
40+
3. **Configure Environment Variables**:
41+
- Create a `.env` file in the root directory and add necessary configuration values
42+
43+
4. **Run the Server**:
44+
```bash
45+
npm start
46+
```
47+
48+
5. **Access the API**:
49+
- The server runs on `http://localhost:3000` by default. You can access the API via your browser or any HTTP client like Postman.
50+
51+
## API Endpoints
52+
53+
### 1. `/v1/admin/reports/getreportbymsgid`
54+
55+
#### Description
56+
This endpoint retrieves a report by the specified message ID (`msgid`). The message ID is provided as a query parameter.
57+
58+
#### Flow Diagram
59+
```mermaid
60+
sequenceDiagram
61+
participant Client as Client<br>System
62+
participant ADMIN as Admin-Service
63+
participant DB as ArangoDB
64+
65+
Client ->> ADMIN: 1. Fetch evaluationResult
66+
ADMIN->> DB: 2. Fetch evaluationResult
67+
DB->> ADMIN: 3. {evaluationResult} data
68+
ADMIN->> Client: 4. {evaluationResult} data
69+
```
70+
71+
#### URL
72+
```
73+
/v1/admin/reports/getreportbymsgid
74+
```
75+
76+
#### Method
77+
```
78+
GET
79+
```
80+
81+
#### Query Parameters
82+
83+
| Parameter | Type | Required | Description |
84+
|-----------|--------|----------|---------------------------------|
85+
| `msgid` | String | Yes | The message ID to get the report for. |
86+
87+
#### Headers
88+
No specific headers required apart from standard authentication headers if needed.
89+
90+
#### Request Example
91+
```http
92+
GET /v1/admin/reports/getreportbymsgid?msgid=1234567890 HTTP/1.1
93+
Host: localhost:3000
94+
```
95+
96+
#### Response
97+
98+
- **Status 400 Bad Request:** When `msgid` is missing or invalid.
99+
```json
100+
{
101+
"statusCode": 400,
102+
"code": "FST_ERR_VALIDATION",
103+
"error": "Bad Request",
104+
"message": "querystring must have required property 'msgid'"
105+
}
106+
```
107+
108+
- **Status 204 Not Found:** When no report is found for the given `msgid`.
109+
```json
110+
{
111+
"statusCode": 204,
112+
}
113+
```
114+
115+
- **Status 500 Internal Server Error:** For server-side errors.
116+
```json
117+
{
118+
"status": "error",
119+
"message": "Internal server error occurred."
120+
}
121+
```
122+

__tests__/__mocks__/arango.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
const arangojs = require('arangojs');
3+
4+
class MockDatabase {
5+
constructor(config) {
6+
return {
7+
exists() {
8+
return true;
9+
},
10+
isArangoDatabase: true,
11+
close() {},
12+
};
13+
}
14+
}
15+
16+
module.exports = { ...arangojs, Database: MockDatabase };

__tests__/__mocks__/ioredis.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Dependency hoisting so third party library uses mock
3+
module.exports = require('ioredis-mock');

__tests__/unit/app.test.ts

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
import { databaseManager, loggerService } from '../../src/';
3+
import { unwrap } from '@frmscoe/frms-coe-lib/lib/helpers/unwrap';
4+
import { handleGetReportRequestByMsgId } from '../../src/logic.service';
5+
6+
// Mock the module
7+
jest.mock('../../src/', () => ({
8+
databaseManager: {
9+
getReportByMessageId: jest.fn(), // Ensure the mock function is typed correctly
10+
},
11+
loggerService: {
12+
log: jest.fn(),
13+
},
14+
}));
15+
16+
jest.mock('@frmscoe/frms-coe-lib/lib/helpers/unwrap', () => ({
17+
unwrap: jest.fn(),
18+
}));
19+
20+
describe('handleGetReportRequestByMsgId', () => {
21+
beforeEach(() => {
22+
jest.clearAllMocks();
23+
});
24+
25+
it('should successfully retrieve and unwrap the report', async () => {
26+
const mockReport = [
27+
{
28+
/* mock report data */
29+
},
30+
];
31+
// Ensure getReportByMessageId is typed as a Jest mock function
32+
(databaseManager.getReportByMessageId as jest.Mock).mockResolvedValue(mockReport);
33+
(unwrap as jest.Mock).mockReturnValue(mockReport);
34+
35+
const msgid = 'test-msg-id';
36+
const result = await handleGetReportRequestByMsgId(msgid);
37+
38+
expect(databaseManager.getReportByMessageId).toHaveBeenCalledWith('transactions', msgid);
39+
expect(unwrap).toHaveBeenCalledWith(mockReport);
40+
expect(result).toBe(mockReport);
41+
expect(loggerService.log).toHaveBeenCalledWith(`Started handling get request by message id the message id is ${msgid}`);
42+
expect(loggerService.log).toHaveBeenCalledWith('Completed handling get report by message id');
43+
});
44+
45+
it('should log and throw an error if the database query fails', async () => {
46+
const errorMessage = 'Database error';
47+
(databaseManager.getReportByMessageId as jest.Mock).mockRejectedValue(new Error(errorMessage));
48+
49+
const msgid = 'test-msg-id';
50+
await expect(handleGetReportRequestByMsgId(msgid)).rejects.toThrow(errorMessage);
51+
52+
expect(databaseManager.getReportByMessageId).toHaveBeenCalledWith('transactions', msgid);
53+
expect(loggerService.log).toHaveBeenCalledWith(
54+
`Failed fetching report from database service with error message: ${errorMessage}`,
55+
'handleGetReportRequestByMsgId()',
56+
);
57+
expect(loggerService.log).toHaveBeenCalledWith('Completed handling get report by message id');
58+
});
59+
60+
it('should log "Completed handling get report by message id" when the operation is successful', async () => {
61+
const mockReport = [
62+
{
63+
/* mock report data */
64+
},
65+
];
66+
(databaseManager.getReportByMessageId as jest.Mock).mockResolvedValue(mockReport);
67+
(unwrap as jest.Mock).mockReturnValue(mockReport);
68+
69+
const msgid = 'test-msg-id';
70+
await handleGetReportRequestByMsgId(msgid);
71+
72+
expect(loggerService.log).toHaveBeenCalledWith('Completed handling get report by message id');
73+
});
74+
75+
it('should log "Completed handling get report by message id" even when an error occurs', async () => {
76+
const errorMessage = 'Database error';
77+
(databaseManager.getReportByMessageId as jest.Mock).mockRejectedValue(new Error(errorMessage));
78+
79+
const msgid = 'test-msg-id';
80+
try {
81+
await handleGetReportRequestByMsgId(msgid);
82+
} catch (e) {
83+
// Expected to throw an error
84+
}
85+
86+
expect(loggerService.log).toHaveBeenCalledWith('Completed handling get report by message id');
87+
});
88+
});

jest.config.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const config: Config.InitialOptions = {
6161
// An object that configures minimum threshold enforcement for coverage results
6262
coverageThreshold: {
6363
global: {
64-
branches: 95, //until elastic apm can be properly mocked
64+
branches: 66,
6565
functions: 95,
6666
lines: 95,
6767
statements: 95,
@@ -150,7 +150,7 @@ const config: Config.InitialOptions = {
150150
// runner: "jest-runner",
151151

152152
// The paths to modules that run some code to configure or set up the testing environment before each test
153-
setupFiles: ['dotenv/config', './cluster-setup.ts'],
153+
setupFiles: ['dotenv/config'],
154154

155155
// A list of paths to modules that run some code to configure or set up the testing framework before each test
156156
// setupFilesAfterEnv: [],

0 commit comments

Comments
 (0)