Разделение методов создания и обновления элементов, добавление полей author, description, service_name. Исправление бага при котором не удалялось апи. Удаление из ответа лишних полей __v и _id

This commit is contained in:
vigdorov
2020-07-10 15:55:10 +03:00
parent 2a671f30d0
commit 89cf9d0c84
6 changed files with 148 additions and 59 deletions

View File

@ -1,24 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'prettier/@typescript-eslint',
],
root: true,
env: {
node: true,
jest: true,
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

25
.eslintrc.json Normal file
View File

@ -0,0 +1,25 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": ["@typescript-eslint/eslint-plugin"],
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"root": true,
"env": {
"node": true,
"jest": true
},
"rules": {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off"
}
}

View File

@ -1,9 +1,15 @@
import { Controller, Get, Post, Body, Param, Options, Header, Delete, HttpCode } from '@nestjs/common'; import { Controller, Get, Post, Body, Param, Options, Header, Delete, HttpCode, Put } from '@nestjs/common';
import {StoreService} from './store.service'; import {StoreService} from './store.service';
import {Store, StoreResponse, StoreRequest} from './store.schema'; import {Store, StoreRequest} from './store.schema';
import {ApiResponse} from '@nestjs/swagger'; import {ApiResponse} from '@nestjs/swagger';
import {ALLOW_ORIGIN_ALL, ALLOW_METHOD, ALLOW_CREDENTIALS, CONTENT_LENGTH, ALLOW_HEADERS} from 'src/consts'; import {ALLOW_ORIGIN_ALL, ALLOW_METHOD, ALLOW_CREDENTIALS, CONTENT_LENGTH, ALLOW_HEADERS} from 'src/consts';
const prepareStoreToStoreRequest = ({
key, value, description, service_name, author
}: Store): StoreRequest => ({
key, value, description, service_name, author,
});
@Controller('store') @Controller('store')
export class StoreController { export class StoreController {
constructor( constructor(
@ -15,10 +21,11 @@ export class StoreController {
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'Список всех пар ключ-значение', description: 'Список всех пар ключ-значение',
type: [StoreResponse], type: [StoreRequest],
}) })
async findAll(): Promise<Store[]> { async findAll(): Promise<StoreRequest[]> {
return this.storeService.findAll(); const storeList = await this.storeService.findAll();
return storeList.map(prepareStoreToStoreRequest);
} }
@Get(':key') @Get(':key')
@ -26,21 +33,35 @@ export class StoreController {
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'Возвращает пару ключ-значение по ключу', description: 'Возвращает пару ключ-значение по ключу',
type: StoreResponse, type: StoreRequest,
}) })
async findOne(@Param() {key}: {key: string}): Promise<Store> { async findOne(@Param() {key}: {key: string}): Promise<StoreRequest> {
return this.storeService.findOne(key); const store = await this.storeService.findOne(key);
return prepareStoreToStoreRequest(store);
} }
@Post() @Post()
@Header(...ALLOW_ORIGIN_ALL) @Header(...ALLOW_ORIGIN_ALL)
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'Создает новую пару ключ-значение или заменяет существующую по ключу', description: 'Создает новую пару ключ-значение',
type: StoreResponse, type: StoreRequest,
}) })
async create(@Body() createStoreClass: StoreRequest): Promise<Store> { async create(@Body() createStoreClass: StoreRequest): Promise<StoreRequest> {
return this.storeService.create(createStoreClass); const store = await this.storeService.create(createStoreClass);
return prepareStoreToStoreRequest(store);
}
@Put()
@Header(...ALLOW_ORIGIN_ALL)
@ApiResponse({
status: 200,
description: 'Обновляет по ключу объект и мета-поля, кроме author',
type: StoreRequest,
})
async update(@Body() updateStoreClass: StoreRequest): Promise<StoreRequest> {
const store = await this.storeService.update(updateStoreClass);
return prepareStoreToStoreRequest(store);
} }
@Delete(':key') @Delete(':key')
@ -48,10 +69,11 @@ export class StoreController {
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'Удаляет пару ключ-значение по ключу', description: 'Удаляет пару ключ-значение по ключу',
type: String, type: StoreRequest,
}) })
async removeOne(@Param() {key}: {key: string}): Promise<string> { async removeOne(@Param() {key}: {key: string}): Promise<StoreRequest> {
return this.storeService.removeOne(key); const store = await this.storeService.removeOne(key);
return prepareStoreToStoreRequest(store);
} }
@Options() @Options()

View File

@ -8,19 +8,15 @@ export class StoreRequest {
@ApiProperty() @ApiProperty()
value: any; value: any;
}
export class StoreResponse {
@ApiProperty()
key: string;
@ApiProperty() @ApiProperty()
value: any; description: string;
@ApiProperty() @ApiProperty()
_id: string; service_name: string;
@ApiProperty() @ApiProperty()
__v: number; author: string;
} }
@Schema() @Schema()
@ -37,6 +33,24 @@ export class Store extends Document {
type: {} type: {}
}) })
value: any; value: any;
@Prop({
required: true,
type: String,
})
description: string;
@Prop({
required: true,
type: String,
})
service_name: string;
@Prop({
required: true,
type: String,
})
author: string;
} }
export const StoreSchema = SchemaFactory.createForClass(Store); export const StoreSchema = SchemaFactory.createForClass(Store);

View File

@ -1,8 +1,15 @@
import {Model} from 'mongoose'; import {Model} from 'mongoose';
import {Injectable, NotFoundException} from '@nestjs/common'; import {Injectable, NotFoundException, BadGatewayException} from '@nestjs/common';
import {InjectModel} from '@nestjs/mongoose'; import {InjectModel} from '@nestjs/mongoose';
import {Store, StoreRequest} from './store.schema'; import {Store, StoreRequest} from './store.schema';
const validateModel = async (store: Store) => {
try {
await store.validate();
} catch (e) {
throw new BadGatewayException(e);
}
};
@Injectable() @Injectable()
export class StoreService { export class StoreService {
@ -16,23 +23,49 @@ export class StoreService {
const searchStore = await this.findOne(store.key); const searchStore = await this.findOne(store.key);
if (searchStore) { if (searchStore) {
return searchStore.updateOne(store); throw new NotFoundException(`Api key ${store.key} is already taken`);
} else {
const createdStore = new this.storeModel(store);
return createdStore.save();
} }
const createdStore = new this.storeModel(store);
await validateModel(createdStore);
return createdStore.save();
}
async update({author, ...omitProps}: StoreRequest): Promise<Store> {
const searchStore = await this.findOne(omitProps.key);
if (searchStore) {
const store = {
...omitProps,
author: searchStore.author,
};
const updateStore = new this.storeModel(store);
await validateModel(updateStore);
await searchStore.updateOne({
...store,
author: searchStore.author,
});
return updateStore;
}
throw new NotFoundException(`Not Found api key - ${omitProps.key}`);
} }
async findOne(key: string): Promise<Store> { async findOne(key: string): Promise<Store> {
return this.storeModel.findOne({key}); return this.storeModel.findOne({key})
} }
async removeOne(key: string): Promise<string> { async removeOne(key: string): Promise<Store> {
const searchStore = await this.findOne(key); const searchStore = await this.findOne(key);
if (searchStore) { if (searchStore) {
await searchStore.remove(); await this.storeModel.deleteOne({key});
return 'ok';
return searchStore;
} }
throw new NotFoundException(`Not Found key - ${key}`); throw new NotFoundException(`Not Found key - ${key}`);

View File

@ -6,15 +6,34 @@ GET http://localhost:4001/store/testApi HTTP/1.1
### ###
POST http://vigdorov.ru:4001/store HTTP/1.1 POST http://localhost:4001/store HTTP/1.1
content-type: application/json content-type: application/json
{ {
"key": "testApi", "key": "testApi",
"value": { "value": {
"name": "ivan", "name": "ivan",
"age": 15 "age": 16
} },
"description": "тестовое апи",
"service_name": "test-api",
"author": "vigdorov"
}
### Update Request
PUT http://localhost:4001/store HTTP/1.1
content-type: application/json
{
"key": "testApi",
"value": {
"name": "ivan23",
"age": 22
},
"description": "тестовое апи",
"service_name": "test-api",
"author": "vigdorov23422"
} }
### ###