Skip to content

Commit

Permalink
refactor: add getById, improve payload type check and db schema
Browse files Browse the repository at this point in the history
  • Loading branch information
manekenpix committed Mar 21, 2024
1 parent 85e6045 commit e8ef194
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 39 deletions.
28 changes: 24 additions & 4 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"mongoose": "^7.4.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0"
"rxjs": "^7.2.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@nestjs/class-validator": "^0.13.4",
Expand All @@ -43,6 +44,7 @@
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@types/uuid": "^9.0.8",
"eslint": "^8.2.0",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-typescript": "^3.5.5",
Expand Down
7 changes: 3 additions & 4 deletions api/src/database/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { ArgumentsHost, Catch, HttpStatus, Logger } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Response } from 'express';
import { MongoError } from 'mongodb';
import { MongooseError } from 'mongoose';

@Catch(MongoError)
@Catch(MongooseError)
export class MongoExceptionFilter extends BaseExceptionFilter {
private readonly logger = new Logger(MongoExceptionFilter.name);

catch(exception: MongoError, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
this.logger.error(exception.message);
console.log('am I here');
this.logger.error(exception.name);

let status;
switch (exception.name) {
Expand All @@ -24,7 +24,6 @@ export class MongoExceptionFilter extends BaseExceptionFilter {

break;
}
case 'MongooseError':
case 'CastError':
case 'DisconnectedError':
case 'DivergentArrayError':
Expand Down
16 changes: 12 additions & 4 deletions api/src/flag/flag.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {
Param,
Delete,
HttpCode,
ParseUUIDPipe,
} from '@nestjs/common';
import FlagService from './flag.service';
import FlagDto from './flag.dts';
import FlagGuard from './flag.guard';
import EnableGuard from './enable.guard';

@Controller('flags')
class FlagController {
Expand All @@ -24,26 +24,34 @@ class FlagController {
return this.flagsService.get();
}

@Get('/:id')
@HttpCode(200)
async getFlag(
@Param('id', new ParseUUIDPipe({ version: '4' })) id: string,
): Promise<FlagDto> {
console.log({ id });
return this.flagsService.getById(id);
}

@UseGuards(FlagGuard)
@HttpCode(201)
@Post('/')
async saveFlag(@Body() flagRequest: FlagDto): Promise<FlagDto> {
return this.flagsService.create(flagRequest);
}

@UseGuards(EnableGuard)
@HttpCode(200)
@Patch('/:id')
async toggleEnabled(
@Param('id') id: string,
@Param('id', ParseUUIDPipe) id: string,
@Body() { isEnabled }: { isEnabled: boolean },
): Promise<FlagDto | null> {
return this.flagsService.toggleEnabled(id, isEnabled);
}

@Delete('/:id')
@HttpCode(204)
delete(@Param('id') id: string): void {
delete(@Param('id', ParseUUIDPipe) id: string): void {
this.flagsService.delete(id);
}
}
Expand Down
18 changes: 9 additions & 9 deletions api/src/flag/flag.repository.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Injectable, Logger } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Flag, FlagDocument } from './schemas/flag.schema';
import { Model, Types } from 'mongoose';
import FlagDto from './flag.dts';

@Injectable()
class FlagRepository {
private readonly logger = new Logger(FlagRepository.name);

constructor(
@InjectModel(Flag.name)
private db: Model<FlagDocument>,
Expand Down Expand Up @@ -40,20 +38,22 @@ class FlagRepository {
return this.formatFlags(fs);
}

async getById(id: string): Promise<FlagDto> {
const fs: FlagDocument = await this.db.findById(id).orFail();

return this.formatFlags([fs])[0];
}

async toggleEnabled(id: string, isEnabled: boolean): Promise<FlagDto> {
const f = await this.db
.findByIdAndUpdate(
{ _id: new Types.ObjectId(id) },
{ isEnabled },
{ new: true },
)
.findByIdAndUpdate({ _id: id }, { isEnabled }, { new: true })
.orFail();

return this.formatFlags([f])[0];
}

async delete(id: string): Promise<void> {
await this.db.findByIdAndRemove({ _id: new Types.ObjectId(id) }).orFail();
await this.db.findByIdAndRemove(id).orFail();
}
}

Expand Down
12 changes: 5 additions & 7 deletions api/src/flag/flag.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@ class FlagService {
constructor(private repository: FlagRepository) {}

async get(): Promise<FlagDto[]> {
const flags = await this.repository.get();
this.logger.log({ flags });
return await this.repository.get();
}

return flags;
async getById(id: string): Promise<FlagDto> {
return await this.repository.getById(id);
}

async create(flag: FlagDto): Promise<FlagDto | never> {
const f = await this.repository.create(flag);
this.logger.log({ flag: f });

return f;
return await this.repository.create(flag);
}

toggleEnabled(id: string, isEnabled: boolean): Promise<FlagDto> {
Expand Down
24 changes: 14 additions & 10 deletions api/src/flag/schemas/flag.schema.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { v4 as uuidv4 } from 'uuid';

export type FlagType = 'boolean' | 'string' | 'number';
export type FlagValueType = string | number | boolean;
export type FlagEnv = 'staging' | 'production';

@Schema()
export class Flag {
@Prop({ type: String })
name!: string;
@Prop({ type: String, default: () => uuidv4() })
_id: string;

@Prop({ type: String })
type!: FlagType;
@Prop({ type: String, required: true })
name: string;

@Prop({ type: String || Number || Boolean })
value!: FlagValueType;
@Prop({ type: String, required: true })
type: FlagType;

@Prop({ type: String })
environment!: FlagEnv;
@Prop({ type: String || Number || Boolean, required: true })
value: FlagValueType;

@Prop({ type: String })
project!: string;
@Prop({ type: String, required: true })
environment: FlagEnv;

@Prop({ type: String, required: true })
project: string;

@Prop({ type: Boolean, default: true })
isEnabled: boolean;
Expand Down

0 comments on commit e8ef194

Please sign in to comment.