I am developing a restAPI with nodejs, express and mysql. Now I have a app.js which is the starting point of the App.
Within app.js I initialize the UserController:
const router: express.Router = express.Router();
new UserController(router);
The UserController looks like this:
import { Request, Response, Router } from 'express';
import UserModel from '../model/user';
class UserController {
constructor(private router: Router) {
router.get('/users', async (req: Request, resp: Response) => {
try {
// const users = get Users with mysql
// resp.status(200).send(users);
} catch (error) {
resp.send({
msg: 'Not found',
status: 404
});
}
});
}
}
export default UserController;
Now I would like to have a DatabaseController which handels everything around the Database like providing a Connection, closing it and so on:
class DatabaseController {
constructor() {
}
}
export default DatabaseController;
How can I achieve that I open the connection in the DatabaseController and let the UserController simply access it? Is that even possible without initializing the DatabaseController and giving the UserController a parameter "dbConnection"?
Yes it's possible. I'm not entirely familiar with typescript so some psuedo code below. Untested.
Somewhere in another file, configure your database connection and the service:
import { MyConnection } from 'my-db-package';
class DatabaseService {
private connection: MyConnection
constructor(db: MyConnection) {
this.connection = db;
}
// Return the promise if any.
// Don't want to handle the error here.
// Let your controller handle the error
async openConnection() {
return this.connection.open()
}
async closeConnection() {
return this.connection.close()
}
async getAllUsers() {
return this.connection.query('SELECT * FROM USERS;')
}
}
export default DatabaseService;
import { Database } from 'my-db-driver'
import { DatabaseService } from 'my-db-service'
// Don't actually connect here
// Just create the object so it's ready for connection.
const connection = new Database({
// config
})
// Wire up the internal db connection
// Remember this is a singleton.
export default new DatabaseService(connection)
Next wire up your controller with the new database service:
import { Request, Response } from 'express';
import { DatabaseService } from './my-service'
class UserController {
private dbService: DatabaseService;
constructor(dbService: DatabaseService) {
this.dbService = dbService;
}
async connect() {
return this.dbService.openConnection()
}
async close() {
return this.dbService.closeConnection()
}
async getAllUsers(req: Request, res: Response) {
let users
try {
users = await this.dbService.getAllUsers();
} catch (error) {
// ...
}
res.json(users)
}
}
export default UserController;
Then hook up your routes:
import { express } from 'express'
import { UserController } from 'user-controller'
import { DatabaseService } from 'database-service'
const userController = new UserController(DatabaseService);
const router: express.Router = express.Router();
router.get('/users', userController.getAllUsers)
// ...
export default router
Finally, hook up your routes with the main Express app:
import { express } from 'express'
import { userRoutes } from 'user-routes'
const app = express()
app.use(userRoutes)
// ..
Again, the above code is untested and likely unusable. It is meant to give you an example of one approach. You may find a better way to do it, but that's the gist of it.
Related
I am very new to writing tests in Karma and Jasmine. In my case, I have a dynamic configuration file that loads before the app is initialized and that file is a JSON with a value.
configuration.json
{
"sampleConfigValue": "this is a sample value from config"
}
Configuration.ts
export interface Configuration {
sampleConfigValue: string;
}
ConfigurationService.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Configuration } from './configuration';
#Injectable({
providedIn: 'root'
})
export class ConfigurationService {
private configData: any | undefined;
private readonly configPath: string = '../assets/demo/data/config.json';
constructor(
private http: HttpClient
) { }
async loadConfiguration(): Promise<any> {
try {
const response = await this.http.get(`${this.configPath}`)
.toPromise().then(res => this.configData = res);
return this.configData;
} catch (err) {
return Promise.reject(err);
}
}
get config(): Configuration | undefined {
return this.configData;
}
}
Exporting the ConfigurationLoader in app.module.ts
export function configLoader(injector: Injector) : () => Promise<any>
{
return () => injector.get(ConfigurationService).loadConfiguration();
}
and Provider in app.module.ts
{provide: APP_INITIALIZER, useFactory: configLoader, deps: [Injector], multi: true},
configuration.service.spec.ts
import { TestBed } from '#angular/core/testing';
import { ConfigurationService } from './configuration.service';
describe('ConfigurationService', () => {
let service: ConfigurationService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ConfigurationService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
The configuration file is working but I am wondering how to write a test case for this dynamic configuration in my project?
Your time and help will really help me :)
Thanks :)
When unit testing, you're supposed to test a code unit and mock the rest.
So create a mock then test :
// Put this in the main describe
const returnValue = {};
let httpMock: { get: jasmine.Spy };
let service: ConfigurationService;
// Put this in the main beforeEach
httpMock = {
get: jasmine.createSpy().and.returnValue(of(returnValue)),
};
service = new ConfigurationService(<any>httpMock);
// Make a meaningful test
it('Should call the endpoint and retrieve the config', (done) => {
service.loadConfiguration().then(() => {
expect(httpMock.get)
.toHaveBeenCalledOnceWith(service['configPath']);
expect(service['configData']).toBe(returnValue);
done();
});
});
So I have my NestJs application connected to mongoDB/Mongoose. I'd like to get everything in the repository and save it locally on my computer as a json file. Could anyone advise how to go about that?
backup.service.ts
#Injectable()
export class BackupService {
constructor(private userService: UserService) {}
private async getUsers(): Promise<User[]> {
return await this.shiftService.getMany();
}
public async downloadUserData() {
const users = await this.getUsers();
// next step to download as json file to local computer?
}
}
Any advice would be greatly appreciated!
You'll need to write the data to a file using Node's fs module. You'll be able to do something like this:
import { writeFile } from 'fs/promises';
import { join } from 'path';
#Injectable()
export class BackupService {
constructor(private userService: UserService) {}
private async getUsers(): Promise<User[]> {
return await this.shiftService.getMany();
}
public async downloadUserData() {
const users = await this.getUsers();
await writeFile(join(process.cwd(), 'db', 'users.json'), JSON.stringify(users));
}
}
This should write the data to a JSON file at <projectRoot>/db/users.json. Keep in mind this is a direct write and not an append, so any data there will be overwritten.
I'm using FeathersJS with MondoDB via feathers-mongo
I want to somehow pass useUnifiedToplogy:true to the connector's settings, however it doesn't seem to be exposed in the generated service (feathers generate service)
This is my logging.class.ts
import { Db } from 'mongodb';
import { Service, MongoDBServiceOptions } from 'feathers-mongodb';
import { Application } from '../../declarations';
import {Paginated, Params} from "#feathersjs/feathers";
export class Logging extends Service {
constructor(options: Partial<MongoDBServiceOptions>, app: Application) {
super(options);
const client: Promise<Db> = app.get('mongoClient');
client.then(db => {
this.Model = db.collection('users');
});
}
};
There's a mongodb.ts at root
import { MongoClient } from 'mongodb';
import { Application } from './declarations';
export default function (app: Application) {
const connection = app.get('mongodb');
const database = connection.substr(connection.lastIndexOf('/') + 1);
const mongoClient = MongoClient.connect(connection, { useNewUrlParser: true, useUnifiedTopology: true })
.then(client => client.db(database));
app.set('mongoClient', mongoClient);
}
I want to fetch json data from a server in a basic angular-redux todo app.Also please do explain how the data flow happens from the store.If u can kindly refer any blogs on the matter,it would be great.I could not make a lot of sense from ng2-redux or ngrx.Thank you in advance.
You should make API calls in Middleware. Read this book, its free, it will clear most of your doubts, it did it for me when I started learning.
You should make API calles (as knowen as side effects) with a middleware like Epic.
Let's considere an example of todo app that you need to get the todos from the server:
const BASE_URL = "https://some-server/api/";
#Injectable()
export class TodoEpics implements EpicMiddleware {
constructor(private httpService: HttpClient) {
}
#dispatch()
startLoading() {
return changeTodoStatus("loading");
}
getTodosEpic = (action$: ActionsObservable<GetTodosAction>, state$: StateObservable<AppState>): Observable<Action> => {
return action$.pipe(
ofType(todoConstants.GET_TODOS),
tap((action) => this.startLoading()),
mergeMap(action => this.httpService.get<GetTodosResponse>(`${BASE_URL}/todos`).pipe(
map((response) => getTodosSucceeded(response.items)),
catchError(error => of(getTodosFailed(error)))
))
);
}
getEpics(): Epic[] {
return [
this.getTodosEpic
];
}
}
and in the main store module:
import { NgModule } from '#angular/core';
import { NgReduxModule, NgRedux, DevToolsExtension } from '#angular-redux/store';
import { createLogger } from 'redux-logger';
import { AppState } from './models';
import { rootReducer } from './reducers';
import { TodoEpics } from "../todo-list/todo-list-state-management/epics";
import { combineEpics, createEpicMiddleware } from "redux-observable";
import { environment } from "../../environments/environment";
const epicMiddleware = createEpicMiddleware();
#NgModule({
imports: [NgReduxModule],
providers: [
TodoEpics
]
})
export class StoreModule {
constructor(private store: NgRedux<AppState>, private todoEpics: TodoEpics) {
const rootEpic = combineEpics(
...this.todoEpics.getEpics()
);
const middelwares = [epicMiddleware]
const devMiddelwares = [...middelwares, createLogger()];
const prodMiddelwares = [...middelwares];
store.configureStore(
rootReducer,
environment.production ? prodMiddelwares : devMiddelwares);
epicMiddleware.run(rootEpic)
}
}
a complete example can be found here: Todo app using angular-redux, redux-observable and epics
I am creating an application in angular 2. I am trying to access the json data via http in a service. But i am getting an error saying that
**GET http://localhost:4200/data/products.json 404 (Not Found)**
I have the data in the specified folder but i am unable to access it.
My service code is as follows.
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';
import { Item } from './item';
#Injectable()
export class ItemService {
observableItems: Observable<Item[]>
allItems: Item[] = [];
selectedItems: Item[] = [];
errorMessage: string;
url = "http://localhost:4200/data/products.json";
constructor(private http:Http) {
this.observableItems = this.http.get(this.url).map((res: Response) => res.json());
this.observableItems.subscribe(
data => this.allItems = data,
error => this.errorMessage = <any>error);
}
getItems(): Observable<Item[]> {
return this.observableItems;
}
getSelectedItems(): Item[] {
return this.selectedItems;
}
addItem(id:number): void {
let item = this.allItems.find(ob => ob.id === id);
if (this.selectedItems.indexOf(item) < 0) {
this.selectedItems.push(item);
}
}
removeItem(id:number): void {
let item = this.selectedItems.find(ob => ob.id === id);
let itemIndex = this.selectedItems.indexOf(item);
this.selectedItems.splice(itemIndex, 1);
}
}
My html files are in
"Project/src/app/..."
So to access JSON File I need to come back from tabs folder and app folder to reach the base directory for both code and images. I used ../ to come back from a folder.
From this my url in the service will be as follows:
url = "../../assets/data/products.json";
Try using direct path to the file from the location of your service file. For example:
url = "data/products.json";
It will work.