├── .prettierrc ├── src ├── favicon.ico ├── common │ └── error-message.interface.ts ├── heroes │ ├── dto │ │ ├── find-one.dto.ts │ │ ├── heroes.args.ts │ │ ├── create-hero.dto.ts │ │ └── update-hero.dto.ts │ ├── models │ │ └── hero.model.ts │ ├── schemas │ │ └── hero.schema.ts │ ├── interfaces │ │ └── hero.interface.ts │ ├── heroes.providers.ts │ ├── heroes.module.ts │ ├── controllers │ │ ├── hero.controller.spec.ts │ │ └── hero.controller.ts │ └── heroes.service.ts ├── app.constants.ts ├── app.module.ts ├── database │ ├── database.module.ts │ └── database.providers.ts ├── main.ts └── exceptions │ └── http-exception.filter.ts ├── assets └── favicon.ico ├── nest-cli.json ├── tsconfig.build.json ├── test ├── jest-e2e.json └── app.e2e-spec.ts ├── .gitignore ├── tsconfig.json ├── .eslintrc.js ├── package.json ├── README.md └── heroes_db.json /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2018/heroes-api/master/src/favicon.ico -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2018/heroes-api/master/assets/favicon.ico -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/common/error-message.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IErrorMessage { 2 | message: string; 3 | } -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /src/heroes/dto/find-one.dto.ts: -------------------------------------------------------------------------------- 1 | import {IsMongoId} from 'class-validator'; 2 | 3 | export class FindOneParams { 4 | @IsMongoId() 5 | id: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/heroes/dto/heroes.args.ts: -------------------------------------------------------------------------------- 1 | import { Max, Min } from 'class-validator'; 2 | 3 | export class HeroesArgs { 4 | @Min(0) 5 | skip = 0; 6 | 7 | @Min(1) 8 | @Max(50) 9 | take = 25; 10 | } -------------------------------------------------------------------------------- /src/heroes/models/hero.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Hero { 3 | id: string; 4 | name: string; 5 | full_name: string; 6 | thumb: string; 7 | photo: string; 8 | description: string; 9 | text: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/app.constants.ts: -------------------------------------------------------------------------------- 1 | export const HERO_MODEL = 'Hero'; 2 | export const DATABASE_CONNECTION = 'mongodb'; 3 | export const DATABASE_URL = 'mongodb://localhost/heroes_api'; 4 | export const DATABASE_TABLE = 'heroes'; 5 | export const API_PORT = 3000; -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import {Module} from '@nestjs/common'; 2 | import {HeroesModule} from './heroes/heroes.module'; 3 | 4 | @Module({ 5 | imports: [ 6 | HeroesModule 7 | ], 8 | }) 9 | export class AppModule { 10 | } 11 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/database/database.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import {databaseProviders} from './database.providers'; 3 | 4 | @Module({ 5 | providers: [...databaseProviders], 6 | exports: [...databaseProviders], 7 | }) 8 | export class DatabaseModule {} 9 | -------------------------------------------------------------------------------- /src/heroes/schemas/hero.schema.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from 'mongoose'; 2 | 3 | export const HeroSchema = new mongoose.Schema({ 4 | name: String, 5 | full_name: String, 6 | thumb: String, 7 | photo: String, 8 | description: String, 9 | text: String 10 | }); 11 | -------------------------------------------------------------------------------- /src/heroes/interfaces/hero.interface.ts: -------------------------------------------------------------------------------- 1 | import { Document } from 'mongoose'; 2 | 3 | export interface IHero extends Document { 4 | readonly id: string; 5 | readonly name: string; 6 | readonly full_name: string; 7 | readonly thumb: string; 8 | readonly photo: string; 9 | readonly description: string; 10 | readonly text: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/heroes/heroes.providers.ts: -------------------------------------------------------------------------------- 1 | import { Connection } from 'mongoose'; 2 | import {HeroSchema} from './schemas/hero.schema'; 3 | import { 4 | DATABASE_TABLE, 5 | DATABASE_CONNECTION, 6 | HERO_MODEL 7 | } from '../app.constants'; 8 | 9 | export const heroesProviders = [ 10 | { 11 | provide: HERO_MODEL, 12 | useFactory: (connection: Connection) => connection.model(DATABASE_TABLE, HeroSchema), 13 | inject: [DATABASE_CONNECTION], 14 | }, 15 | ]; -------------------------------------------------------------------------------- /src/database/database.providers.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from 'mongoose'; 2 | import {DATABASE_CONNECTION, DATABASE_URL} from '../app.constants'; 3 | 4 | export const databaseProviders = [ 5 | { 6 | provide: DATABASE_CONNECTION, 7 | useFactory: (): Promise => 8 | mongoose.connect(DATABASE_URL, { 9 | useNewUrlParser: true, 10 | useUnifiedTopology: true, 11 | useFindAndModify: false 12 | }), 13 | }, 14 | ]; -------------------------------------------------------------------------------- /src/heroes/dto/create-hero.dto.ts: -------------------------------------------------------------------------------- 1 | import {Length, IsNotEmpty} from 'class-validator'; 2 | 3 | export class CreateHeroDto { 4 | @IsNotEmpty() 5 | @Length(3, 100) 6 | readonly name: string; 7 | 8 | @IsNotEmpty() 9 | @Length(3, 100) 10 | readonly full_name: string; 11 | 12 | @IsNotEmpty() 13 | readonly thumb: string; 14 | 15 | @IsNotEmpty() 16 | readonly photo: string; 17 | 18 | @IsNotEmpty() 19 | readonly description: string; 20 | 21 | readonly text: string; 22 | } 23 | -------------------------------------------------------------------------------- /src/heroes/dto/update-hero.dto.ts: -------------------------------------------------------------------------------- 1 | import {IsNotEmpty, MaxLength, MinLength} from 'class-validator'; 2 | 3 | export class UpdateHeroDto { 4 | @IsNotEmpty() 5 | @MinLength(3) 6 | @MaxLength(100) 7 | name: string; 8 | 9 | @IsNotEmpty() 10 | @MinLength(3) 11 | @MaxLength(100) 12 | full_name: string; 13 | 14 | @IsNotEmpty() 15 | thumb: string; 16 | 17 | @IsNotEmpty() 18 | photo: string; 19 | 20 | @IsNotEmpty() 21 | description: string; 22 | 23 | text: string; 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json -------------------------------------------------------------------------------- /src/heroes/heroes.module.ts: -------------------------------------------------------------------------------- 1 | import {Module} from '@nestjs/common'; 2 | import {HeroController} from './controllers/hero.controller'; 3 | import {HeroesService} from './heroes.service'; 4 | import {DatabaseModule} from '../database/database.module'; 5 | import {heroesProviders} from './heroes.providers'; 6 | 7 | @Module({ 8 | imports: [DatabaseModule], 9 | controllers: [HeroController], 10 | providers: [ 11 | HeroesService, 12 | ...heroesProviders 13 | ], 14 | }) 15 | export class HeroesModule { 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true 15 | }, 16 | "include": [ 17 | "src/**/*" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {NestFactory} from '@nestjs/core'; 2 | import {AppModule} from './app.module'; 3 | import {ValidationPipe} from '@nestjs/common'; 4 | import {HttpExceptionFilter} from './exceptions/http-exception.filter'; 5 | import {API_PORT} from './app.constants'; 6 | 7 | async function bootstrap() { 8 | const app = await NestFactory.create(AppModule); 9 | app.useGlobalPipes(new ValidationPipe()); 10 | app.useGlobalFilters(new HttpExceptionFilter()); 11 | app.enableCors(); 12 | await app.listen(API_PORT); 13 | } 14 | bootstrap(); 15 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/heroes/controllers/hero.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import {Test, TestingModule} from '@nestjs/testing'; 2 | import {HeroController} from './hero.controller'; 3 | import {HeroesService} from '../heroes.service'; 4 | 5 | describe('HeroController', () => { 6 | let appController: HeroController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [HeroController], 11 | providers: [HeroesService], 12 | }).compile(); 13 | 14 | appController = app.get(HeroController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.findAll()).toEqual([]); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/exceptions/http-exception.filter.ts: -------------------------------------------------------------------------------- 1 | import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; 2 | import { Request, Response } from 'express'; 3 | import { MongoError } from 'mongodb'; 4 | 5 | @Catch(MongoError) 6 | export class HttpExceptionFilter implements ExceptionFilter { 7 | catch(exception: MongoError, host: ArgumentsHost) { 8 | const ctx = host.switchToHttp(); 9 | const response = ctx.getResponse(); 10 | const request = ctx.getRequest(); 11 | const status = exception.code; 12 | 13 | response 14 | .status(status) 15 | .json({ 16 | statusCode: exception.message, 17 | message: 'Not Found', 18 | timestamp: new Date().toISOString(), 19 | path: request.url, 20 | }); 21 | } 22 | } -------------------------------------------------------------------------------- /src/heroes/controllers/hero.controller.ts: -------------------------------------------------------------------------------- 1 | import {Body, Controller, Delete, Get, Param, Post, Put, Query} from '@nestjs/common'; 2 | import {HeroesService} from '../heroes.service'; 3 | import {CreateHeroDto} from '../dto/create-hero.dto'; 4 | import {UpdateHeroDto} from '../dto/update-hero.dto'; 5 | import {FindOneParams} from '../dto/find-one.dto'; 6 | 7 | @Controller('heroes') 8 | export class HeroController { 9 | constructor(private heroService: HeroesService) {} 10 | 11 | @Post() 12 | create(@Body() createHeroDto: CreateHeroDto) { 13 | return this.heroService.create(createHeroDto); 14 | } 15 | 16 | @Get() 17 | findAll(@Query('limit') param?: string) { 18 | return this.heroService.findAll(param); 19 | } 20 | 21 | @Get(':id') 22 | findOne(@Param() param: FindOneParams) { 23 | return this.heroService.findOne(param.id); 24 | } 25 | 26 | @Put(':id') 27 | update(@Param() params: FindOneParams, @Body() updateHeroDto: UpdateHeroDto) { 28 | return this.heroService.update(params.id, updateHeroDto); 29 | } 30 | 31 | @Delete(':id') 32 | remove(@Param() params: FindOneParams) { 33 | return this.heroService.remove(params.id); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heroes-api", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "prebuild": "rimraf dist", 10 | "build": "nest build", 11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 12 | "start": "nest start", 13 | "start:dev": "nest start --watch", 14 | "start:debug": "nest start --debug --watch", 15 | "start:prod": "node dist/main", 16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 17 | "test": "jest", 18 | "test:watch": "jest --watch", 19 | "test:cov": "jest --coverage", 20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 21 | "test:e2e": "jest --config ./test/jest-e2e.json" 22 | }, 23 | "dependencies": { 24 | "@nestjs/common": "^7.3.2", 25 | "@nestjs/core": "^7.3.2", 26 | "@nestjs/mongoose": "^7.0.2", 27 | "@nestjs/platform-express": "^7.3.2", 28 | "class-transformer": "^0.2.3", 29 | "class-validator": "^0.12.2", 30 | "lodash": "^4.17.18", 31 | "mongoose": "^5.9.22", 32 | "reflect-metadata": "^0.1.13", 33 | "rimraf": "^3.0.2", 34 | "rxjs": "^6.6.0" 35 | }, 36 | "devDependencies": { 37 | "@nestjs/cli": "^7.0.0", 38 | "@nestjs/schematics": "^7.0.0", 39 | "@nestjs/testing": "^7.3.2", 40 | "@types/express": "^4.17.7", 41 | "@types/jest": "25.2.3", 42 | "@types/mongoose": "^5.7.30", 43 | "@types/node": "^13.13.13", 44 | "@types/supertest": "^2.0.10", 45 | "@typescript-eslint/eslint-plugin": "3.0.2", 46 | "@typescript-eslint/parser": "3.0.2", 47 | "eslint": "^7.4.0", 48 | "eslint-config-prettier": "^6.10.0", 49 | "eslint-plugin-import": "^2.22.0", 50 | "jest": "26.0.1", 51 | "prettier": "^1.19.1", 52 | "supertest": "^4.0.2", 53 | "ts-jest": "26.1.0", 54 | "ts-loader": "^6.2.1", 55 | "ts-node": "^8.6.2", 56 | "tsconfig-paths": "^3.9.0", 57 | "typescript": "^3.9.6" 58 | }, 59 | "jest": { 60 | "moduleFileExtensions": [ 61 | "js", 62 | "json", 63 | "ts" 64 | ], 65 | "rootDir": "src", 66 | "testRegex": ".spec.ts$", 67 | "transform": { 68 | "^.+\\.(t|j)s$": "ts-jest" 69 | }, 70 | "collectCoverageFrom": [ 71 | "**/*.(t|j)s" 72 | ], 73 | "coverageDirectory": "../coverage", 74 | "testEnvironment": "node" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/heroes/heroes.service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable} from '@nestjs/common'; 2 | import {Model, UpdateQuery} from 'mongoose'; 3 | import * as _ from 'lodash'; 4 | import {HERO_MODEL} from '../app.constants'; 5 | import {IHero} from './interfaces/hero.interface'; 6 | import {CreateHeroDto} from './dto/create-hero.dto'; 7 | import {IErrorMessage} from '../common/error-message.interface'; 8 | 9 | @Injectable() 10 | export class HeroesService { 11 | constructor(@Inject(HERO_MODEL) private heroModel: Model) {} 12 | 13 | async create(createHeroDto: CreateHeroDto): Promise< IHero | IErrorMessage> { 14 | try { 15 | const createdHero = new this.heroModel(createHeroDto); 16 | return createdHero.save().then((res) => this.formatItem(res)); 17 | } catch (e) { 18 | return {message: e} 19 | } 20 | } 21 | 22 | async findAll(args?: string): Promise { 23 | try { 24 | return this.heroModel.find().limit(+args) 25 | .map((res) => this.format(res)).exec(); 26 | } catch (e) { 27 | return {message: e} 28 | } 29 | } 30 | 31 | async findOne(id: string): Promise { 32 | try { 33 | return this.heroModel.findById(id) 34 | .map((res) => this.formatItem(res)).exec(); 35 | } catch (e) { 36 | return {message: e} 37 | } 38 | } 39 | 40 | async update(id: string, updateHeroDto: UpdateQuery): Promise { 41 | try { 42 | return this.heroModel.findByIdAndUpdate(id, updateHeroDto).exec().then(() => { 43 | return this.findOne(id); 44 | }); 45 | } catch (e) { 46 | return {message: e} 47 | } 48 | } 49 | 50 | async remove(id: string): Promise { 51 | try { 52 | return this.heroModel.findByIdAndRemove(id).exec().then((res) => this.formatItem(res)); 53 | } catch (e) { 54 | return {message: e} 55 | } 56 | } 57 | 58 | private format(val: IHero[]) { 59 | return _.map(val, (item: IHero) => { 60 | return this.formatItem(item); 61 | }); 62 | } 63 | 64 | private formatItem(val: IHero|null): IHero|null { 65 | return val !== null ? { 66 | id: val._id, 67 | name: val.name, 68 | full_name: val.full_name, 69 | thumb: val.thumb, 70 | photo: val.photo, 71 | description: val.description, 72 | text: val.text 73 | } : null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master 6 | [travis-url]: https://travis-ci.org/nestjs/nest 7 | [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux 8 | [linux-url]: https://travis-ci.org/nestjs/nest 9 | 10 |

A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.

11 |

12 | NPM Version 13 | Package License 14 | NPM Downloads 15 | Travis 16 | Linux 17 | Coverage 18 | Gitter 19 | Backers on Open Collective 20 | Sponsors on Open Collective 21 | 22 | 23 |

24 | 26 | 27 | ## Description 28 | 29 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 30 | 31 | 32 | # REST API tour of heroes app 33 | dependencies: 34 | Node.js, NestJS, MongoDB 35 | 36 | 37 | ## Installation 38 | 39 | 1. Create MongoDB database with name `heroes_api` and collection name `heroes`. 40 | 41 | 2. Import data from `heroes_db.json` file. 42 | 43 | 3. Run `npm install` for installing dependencies. 44 | 45 | ```bash 46 | $ npm install 47 | ``` 48 | 49 | ## Running the app 50 | 51 | ```bash 52 | # development 53 | $ npm run start 54 | 55 | # watch mode 56 | $ npm run start:dev 57 | 58 | # production mode 59 | $ npm run start:prod 60 | ``` 61 | 62 | ## Test 63 | 64 | ```bash 65 | # unit tests 66 | $ npm run test 67 | 68 | # e2e tests 69 | $ npm run test:e2e 70 | 71 | # test coverage 72 | $ npm run test:cov 73 | ``` 74 | 75 | -------------------------------------------------------------------------------- /heroes_db.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "_id": { 3 | "$oid": "602987410a15d617780cafc8" 4 | }, 5 | "name": "IRON MAN", 6 | "full_name": "TONY STARK", 7 | "thumb": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/002irm_ons_crd_03.jpg", 8 | "photo": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/002irm_ons_mas_dsk_03.jpg", 9 | "description": "Genius. Billionaire. Philanthropist. Tony Stark's confidence is only matched by his high-flying abilities as the hero called Iron Man.", 10 | "__v": 0, 11 | "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla pulvinar eleifend sem. Praesent dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Integer lacinia. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Vivamus ac leo pretium faucibus. In convallis. Etiam neque. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Donec vitae arcu. Sed vel lectus. Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Nulla non arcu lacinia neque faucibus fringilla. Donec ipsum massa, ullamcorper in, auctor et, scelerisque sed, est. Fusce wisi. Phasellus rhoncus. Curabitur sagittis hendrerit ante." 12 | },{ 13 | "_id": { 14 | "$oid": "602987500a15d617780cafc9" 15 | }, 16 | "name": "CAPTAIN AMERICA", 17 | "full_name": "STEVE ROGERS", 18 | "thumb": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/003cap_ons_crd_03.jpg", 19 | "photo": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/003cap_ons_mas_dsk_02.jpg", 20 | "description": "Recipient of the Super-Soldier serum, World War II hero Steve Rogers fights for American ideals as one of the world’s mightiest heroes and the leader of the Avengers.", 21 | "__v": 0, 22 | "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla pulvinar eleifend sem. Praesent dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Integer lacinia. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Vivamus ac leo pretium faucibus. In convallis. Etiam neque. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Donec vitae arcu. Sed vel lectus. Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Nulla non arcu lacinia neque faucibus fringilla. Donec ipsum massa, ullamcorper in, auctor et, scelerisque sed, est. Fusce wisi. Phasellus rhoncus. Curabitur sagittis hendrerit ante." 23 | },{ 24 | "_id": { 25 | "$oid": "6029875a0a15d617780cafca" 26 | }, 27 | "name": "THOR", 28 | "full_name": "THOR ODINSON", 29 | "thumb": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/004tho_ons_crd_03.jpg", 30 | "photo": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/004tho_ons_mas_dsk_03.jpg", 31 | "description": "The son of Odin uses his mighty abilities as the God of Thunder to protect his home Asgard and planet Earth alike.", 32 | "__v": 0, 33 | "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla pulvinar eleifend sem. Praesent dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Integer lacinia. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Vivamus ac leo pretium faucibus. In convallis. Etiam neque. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Donec vitae arcu. Sed vel lectus. Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Nulla non arcu lacinia neque faucibus fringilla. Donec ipsum massa, ullamcorper in, auctor et, scelerisque sed, est. Fusce wisi. Phasellus rhoncus. Curabitur sagittis hendrerit ante." 34 | },{ 35 | "_id": { 36 | "$oid": "602987c00a15d617780cafcb" 37 | }, 38 | "name": "SPIDER-MAN", 39 | "full_name": "PETER PARKER", 40 | "thumb": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/005smp_ons_crd_02.jpg", 41 | "photo": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/005smp_ons_mas_mob_03.jpg", 42 | "description": "Bitten by a radioactive spider, Peter Parker’s arachnid abilities give him amazing powers he uses to help others, while his personal life continues to offer plenty of obstacles.", 43 | "__v": 0, 44 | "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla pulvinar eleifend sem. Praesent dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Integer lacinia. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Vivamus ac leo pretium faucibus. In convallis. Etiam neque. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Donec vitae arcu. Sed vel lectus. Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Nulla non arcu lacinia neque faucibus fringilla. Donec ipsum massa, ullamcorper in, auctor et, scelerisque sed, est. Fusce wisi. Phasellus rhoncus. Curabitur sagittis hendrerit ante." 45 | },{ 46 | "_id": { 47 | "$oid": "602988510a15d617780cafcc" 48 | }, 49 | "name": "HULK", 50 | "full_name": "BRUCE BANNER", 51 | "thumb": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/006hbb_ons_crd_03.jpg", 52 | "photo": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/006hbb_ons_mas_dsk_02_1.jpg", 53 | "description": "Dr. Bruce Banner lives a life caught between the soft-spoken scientist he’s always been and the uncontrollable green monster powered by his rage.", 54 | "__v": 0, 55 | "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla pulvinar eleifend sem. Praesent dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Integer lacinia. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Vivamus ac leo pretium faucibus. In convallis. Etiam neque. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Donec vitae arcu. Sed vel lectus. Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Nulla non arcu lacinia neque faucibus fringilla. Donec ipsum massa, ullamcorper in, auctor et, scelerisque sed, est. Fusce wisi. Phasellus rhoncus. Curabitur sagittis hendrerit ante." 56 | },{ 57 | "_id": { 58 | "$oid": "602988f20a15d617780cafcd" 59 | }, 60 | "name": "WAR MACHINE", 61 | "full_name": "JAMES RHODES", 62 | "thumb": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/042wmr_ons_crd_03.jpg", 63 | "photo": "https://terrigen-cdn-dev.marvel.com/content/prod/1x/042wmr_ons_mas_dsk_04.jpg", 64 | "description": "Military veteran James Rhodes is ready for combat in his advanced armor, adding a formidable arsenal to Tony Stark-created designs.", 65 | "__v": 0, 66 | "text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla pulvinar eleifend sem. Praesent dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nullam lectus justo, vulputate eget mollis sed, tempor sed magna. Integer lacinia. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Vivamus ac leo pretium faucibus. In convallis. Etiam neque. Curabitur ligula sapien, pulvinar a vestibulum quis, facilisis vel sapien. Donec vitae arcu. Sed vel lectus. Donec odio tempus molestie, porttitor ut, iaculis quis, sem. Maecenas fermentum, sem in pharetra pellentesque, velit turpis volutpat ante, in pharetra metus odio a lectus. Nulla non arcu lacinia neque faucibus fringilla. Donec ipsum massa, ullamcorper in, auctor et, scelerisque sed, est. Fusce wisi. Phasellus rhoncus. Curabitur sagittis hendrerit ante." 67 | }] 68 | --------------------------------------------------------------------------------