I have been honing my TypeScript skills and encountered an issue. I am working with a class called Manager
which oversees multiple 'sub' managers. In the index file, I instantiate the Manager class and invoke the load function. During loading, all 'sub' managers receive a reference to the main/only Manager
instance, enabling them to interact with each other.
However, I now need to retrieve information from the 'sub' managers through a REST API endpoint. These endpoints are defined in routes:
index.ts
import "reflect-metadata";
import { createConnection } from "typeorm";
import { Request, Response } from "express";
import * as express from "express";
import * as bodyParser from "body-parser";
import { AppRoutes } from "./routes";
import { Manager } from "./manager";
createConnection().then(async (typeORMConnection) => {
const manager = new Manager();
manager.load().then(() => {
console.log("Manager has loaded all managers");
const expressApp = express();
expressApp.use(bodyParser.json());
expressApp.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "*");
res.header("Access-Control-Allow-Headers", "*");
next();
});
// Loop over every route
AppRoutes.forEach((singleRoute) => {
// Generate Express route
expressApp[singleRoute.method](singleRoute.path, (request: Request, response: Response, next: Function) => {
singleRoute.action(request, response)
.then(() => next())
.catch((error) => next(error));
});
});
// Start Express app
expressApp.listen(3000);
console.log("Express application is up and running on port 3000");
});
}).catch((error) => console.log(`TypeORM connection error: ${error}`));
A typical route file includes:
routes.ts
import { getSpeakerById, getSpeakerAll } from "./controller/get";
import { enableSpeakerById, disableSpeakerById } from "./controller/put";
export const AppRoutes = [
{
path: "/speaker",
method: "get",
action: getSpeakerAll
},
{
path: "/speaker/:id",
method: "get",
action: getSpeakerById
},
{
path: "/speaker/:id/disable",
method: "put",
action: disableSpeakerById
},
{
path: "/speaker/:id/enable",
method: "put",
action: enableSpeakerById
},
];
The following Express endpoint file contains the actual logic:
controller/get.ts
import { Request, Response } from "express";
import { getManager } from "typeorm";
import { Speaker } from "../entity/Speaker";
const ping = require("ping");
export async function getSpeakerById(request: Request, response: Response) {
const speakerRepository = getManager().getRepository(Speaker);
const speakerObject = await speakerRepository.findOne(request.params.id);
if (!speakerObject) {
response.status(404);
response.send("Speaker doesn't exist");
response.end();
return;
}
speakerObject.time = await ping.promise.probe(speakerObject.host);
response.send(speakerObject);
}
export async function getSpeakerAll(request: Request, response: Response) {
const speakerRepository = getManager().getRepository(Speaker);
const speakerObjects = await speakerRepository.find();
const speakerPromise = [];
speakerObjects.forEach((speakerObject) => speakerPromise.push(ping.promise.probe(speakerObject.host)));
const speakerResults = await Promise.all(speakerPromise);
speakerResults.forEach((speakerResult, speakerIndex) => speakerObjects[speakerIndex].time = speakerResult.time);
response.send(speakerObjects);
}
Now, the challenge lies in accessing the main Manager instance within the controller/get.ts
without passing it as a parameter. Simply importing the Manager class and creating a new instance isn't viable since I only want to initiate the Manager once due to its internal logic involving intervals and instances from the Sonos package. If further clarification is required, feel free to request additional details.