npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@enoviah/nest-core

v1.2.0

Published

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Downloads

2

Readme

NestJs

Created At: Jan 20, 2021 10:55 AM Destination: common Environnement: Outworld-QA Last Update: Feb 3, 2021 11:03 AM Responsable: Arthur Pain Type: Documentation Univers: Technique

Build Status

1 - Guideline

Par défaut, Nest se base sur le système d'Angular. Ce qui implique que vous pouvez utiliser des modules, des providers, des controllers et des services.

Nest propose sont propre système d'injection semblable à celui d'Angular.

Vous pouvez accéder à la documentation ici.

1.1 - Structure

Voici la structure à garder en tête lors de la création d'une api. Elle peut être modifié en fonction des besoins. Mais pour un soucis de maintenabilité, veuillez la garder au maximum semblable à celle-ci.

--| src
	  --| modules
        --| users
            --| users.module.ts // Global module
            --| users.controller.ts // User controller (All access POST, GET, ...)
            --| user.providers.ts // User provider (Provide user Schema)
            --| user.service.ts // User method (Controller should call the service)
            --| schema
                --| user.schema.ts // Define user schema for mongoDb
            --| models
                --| user.dto.ts // Define all DTO of user
                --| user.model.ts // Define user model & user Document
    --| environment
    --| providers
    --| 
--| main.ts
--| app.module.ts
--| config.ts

2 - Configuration

Par défaut, vous devez appliquer le guide Typescript à votre api NestJs.

Votre api doit obligatoirement utiliser le modules @enoviah/nest-core

$> npm install --save @enoviah/nest-core:latest

3 - Nest-Core

Nest-core est le module interne à Outworld qui surcouche nestJs pour proposer différentes features.

3.1 - Environnement

Le module nest-core expose une gestion de l'environnement. Par défaut, dotenv est utilisé pour charger l’environnement.

3.1.1 - Chargement de l'environnement

Voici l'ordre de priorité:

  1. .env
  2. .env.example
  3. environnement système

Si le .env n'existe pas, le .env.example sera chargé. Si il n'existe pas, l'environnement du système sera utilisé.

3.1.2 Configuration

src/environment/ Location des fichiers liés à l'environnement

env.model Model de l'environnement

interface Environment {
PORT: string;
}

export default Environment;

env.ts Export de l'environnement

import { EnvironmentService } from '@enoviah/nest-core';
import Environment from './env.model';

const environment = new EnvironmentService<Environment>();
environment.loadEnvironment(false);
export default environment;

Optionnel env.ts Validation de l'environnement avec un schéma

import { EnvironmentService } from '@enoviah/nest-core';
import Environment from './env.model';
import envSchema from './env.schema';

const environment = new EnvironmentService<Environment>();
environment.validators = envSchema; // Assignation du schéma
environment.loadEnvironment(true);
export default environment;

Optionnel env.schema.ts JsonSchema de l'environnement

import { Schema } from 'jsonschema';

const envSchema: Schema = {
  id: '/Env',
  type: 'object',
  properties: {
    PORT: { type: 'string' },
  },
  required: ['PORT'],
};
export default envSchema;

3.1.3 - Utilisation

Example d'utilisation

/src/main.ts

import environment from './env/env';

console.log(environment.environment.PORT);

3.2 CRUD operations

Ce module expose un service qui va gérer les opérations basiques d'un controller (Create, Read, Update, Delete).

La class CRUD expose par défaut:

  • create(): Create document
  • findMany(): Find documents from query (Voir queries automatique)
  • findOne(): Find a document
  • updateOne(): Update a document
  • deleteOne(): Delete a document

user.service.ts

import { CRUD } from '@enoviah/nest-core';
import { Document, Model } from 'mongoose';
import { User, UserDocument } from './models/user.model';
import { Inject } from '@nestjs/common';
import { matchField } from '@enoviah/nest-core';

export class UsersService extends CRUD<User> {
  constructor(@Inject('USER_MODEL') private readonly usersModel: Model<UserDocument>) {
    super(usersModel);
    this.queryList.push({
      matcher: ['status'],
      handler: (key: string, value: string) => {
        return matchField({ status: value });
      },
      priority: 100,
    });
  }
}

3.3 - MongoDb

Nest-core expose un module de base de donnée

3.3.1 - Environnement

Vous devez définir votre environnement avec les variables demandées par le module:

MONGO_DATABASE=myDb
MONGO_ADDRESS=mongodb:27017
MONGO_USER=default // Do not use if auth is not defined on your database
MONGO_PASSWORD=default  // Do not use if auth is not defined on your database

3.3.2 - Utilisation

Exemple d'utilisation pour la collection Users.

/src/modules/users

user.schema.ts Définition du schéma

import { Schema } from 'mongoose';
import ObjectId = Schema.Types.ObjectId;

const UserSchema = new Schema({
  firstName: { type: String, required: true },
  lastName: { type: String, required: true },
  email: { type: String, required: true },
  authId: { type: ObjectId, required: true },
}, { timestamps: true });

export default UserSchema;

user.providers.ts

import { Provider } from '@nestjs/common';
import { Connection } from 'mongoose';
import UserSchema from './user.schema';

const providers: Provider[] = [{
  provide: 'USERS_MODEL',
  useFactory: (connection: Connection) => connection.model('Users', UserSchema),
  inject: ['DATABASE_CONNECTION'],
}];
export default providers;

user.module.ts

import {
  DatabaseModule,
} from '@enoviah/nest-core';
import { Module } from '@nestjs/common';
import userProviders from './users.providers';
import UsersService from './users.service';

@Module({
  imports: [DatabaseModule],
  controllers: [],
  providers: [...userProviders, UsersService],
  exports: [UsersService],
})
class UsersModule {
}

export default UsersModule;

user.service.ts

import {Model} from 'mongoose';
import {
  Inject,
  Injectable,
} from '@nestjs/common';

@Injectable()
class UsersService {
  constructor(@Inject('USERS_MODEL') private readonly userModel: Model<UserDocument>) {
  }
}

3.4 - Queries automatique

Vous pouvez utiliser le système de queries automatique.

Il y a deux modes :

  • Pagination
  • Sans pagination

Ces deux modes peuvent être activé grâce à l'objet de configuration.

Par défaut, la class Query expose deux queries:

  • limit (Limite des résultats)
  • offset (Début des résulats)

Si vous utilisez le mode pagination et que vous envoyez une de ces deux queries, elles sera appliquée.

Exemple avec une query possible sur la key firstName de User.

user.service.ts

import {Model} from 'mongoose';
import {
  Inject,
  Injectable,
} from '@nestjs/common';
import { ExtractedQueries, Query, Stage, Utils, matchField } from '@enoviah/nest-core';

@Injectable()
class UsersService extends Query {
  constructor(@Inject('USERS_MODEL') private readonly userModel: Model<UserDocument>) {
		this.queryList.push({
		  matcher: ['firstName'],
		  handler: async (key: string, value: string) => {
		    const search = new RegExp('^' + value, 'ig');
		    return matchField({ firstName: search });
		  },
		  priority: 1,
		});
	}
	// Mode pagination
	getUsers(queries: Record<string, string>): Observable<{results: User[], count: number}> {
		return this.extractQuery(queries, {count: true)
      .pipe(mergeMap((queries: ExtractedQueries[]) => {
        return from(this.userModel.aggregate([queries]).exec()).pipe(Utils.mapAggregateCount()) 
				};
        }));
      }));
	}
  // Mode sans pagination
	getUsers(queries: Record<string, string>): Observable<User[]> {
		return this.extractQuery(queries, {})
      .pipe(mergeMap((queries: ExtractedQueries[]) => {
        return from(this.userModel.aggregate([queries]).exec());
				};
        }));
      }));
	}
}

3.5 - Validation de données

Nest-core propose un service de validation de donnée basé sur Json-Schema.

user.module.ts

import {
  DatabaseModule,
	JsonSchemaModule,
} from '@enoviah/nest-core';
import { Module } from '@nestjs/common';
import userProviders from './users.providers';
import UsersService from './users.service';

@Module({
  imports: [DatabaseModule, JsonSchemaModule],
  controllers: [],
  providers: [...userProviders, UsersService],
  exports: [UsersService],
})
class UsersModule {
}

export default UsersModule;

user.service.ts

import {
  AuthUser,
  BadRequest,
  JsonSchemaService,
} from '@enoviah/nest-core';
import {
  BadRequestException,
  Inject,
  Injectable,
} from '@nestjs/common';
import {
  Model,
} from 'mongoose';
import {
  catchError,
  mergeMap,
} from 'rxjs/operators';
import { UserDocument } from '../../models/user/user.document';
import CreateUserRequest from '../../models/user/user.dto';
import creatUserSchema from '../../models/user/user.validations';

@Injectable()
class UsersService {
  constructor(@Inject('USERS_MODEL') private readonly userModel: Model<UserDocument>,
    private readonly jsonSchemaService: JsonSchemaService) {
  }

  create(body: CreateUserRequest): Observable<UserDocument> {
	// Will automatically throw a 400 bad request if the validation fail
    this.jsonSchemaService.validate(body, creatUserSchema, true);
   }
}

export default UsersService;

3.6 - Gestion d'erreur

Nest-core propose une gestion des exceptions via un filtre.

Il agira sur les exceptions et les transformeras en une réponse http formatée.

main.ts

**import { NestExpressApplication } from '@nestjs/platform-express';
import { EnvStatus } from '@enoviah/nest-core/dist/models/environment.model';
import { NestFactory } from '@nestjs/core';
import * as cors from 'cors';
import * as bodyParser from 'body-parser';
import { HttpExceptionFilter, Utils } from '@enoviah/nest-core';
import * as helmet from 'helmet';
import { Logger } from '@nestjs/common';
import AppModule from './app.module';
import environment from './environment/env';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.use(helmet());
  app.use(cors({ origin: '*' }));
  app.use(bodyParser.json());
  
  // Register the filter
	app.useGlobalFilters(new HttpExceptionFilter());

  Logger.debug(`API listening on ${environment.environment.PORT}`);
  await app.listen(+environment.environment.PORT);
}

bootstrap();**

Si j'ai le code suivant:

app.controller.ts

import {
  Controller,
  Get
} from '@nestjs/common';
import {
  BadRequest,
} from '@enoviah/nest-core';

@Controller('/')
class AppController {
  constructor() {
  }

  @Get('/500')
  async getAccount() {
	  throw new Error('Oops');
  }

  @Get('/400')
  async getAccount() {
		throw new BadRequest({ message: 'Passwords missmatch', code: 'EPASSWORDMISSMATCH' });  }
	}

export default AccountController;

les réponses http seront les suivantes:

// /500
{
	"message": "Oops",
	"status": 500,
	"code": "EINTERNALESERVERERROR",
}
// /400
{
	"message": "Passwords missmatch",
  "code": "EPASSWORDMISSMATCH",
	"status": 400,
}

Une erreur inconnue sera aussi traitée par l’intercepteur et sera transformée en 500.

3.7 - Resources

Pour uniformiser la géstion des images / Vidéos, nest-core propose un module de gestion de ces derniers.

3.7.1 - Philosophie

Une resource est un document contenu dans la collection Resources. Il représente un fichier (qu'importe l'extension) stocké à un emplacement (Google Storage, Local, ...).

Ce module vous permet d'upload un fichier, de valider son contenu et de pouvoir générer l'url d'accés à n'importe quel moment.

3.7.2 - Utilisation

Rentrons dans le vif du sujet.

D'abord, il faut définir les variables d’environnements suivantes :

.env

UPLOAD_LIMIT=1250000 // Taille max d'un fichier
UPLOAD_DIR=media // Dossier dans lequel les fichiers seront mis (/public/media)

Ensuite, il faut utiliser le module qui va exposer les router des resources

app.module.ts

import { Module } from '@nestjs/common';
import { NestCoreModule, GmapsModule, ResourceModule, Utils } from '@enoviah/nest-core';

@Module({
  imports: [
    NestCoreModule,
    ResourceModule,
    ],
  controllers: [],
  providers: [],
})
export class AppModule {
}

Si vous avez bien configurer votre environnement, vous pouvez maintenant utiliser les routes. Voir l'api-docs pour la liste.

Si vous voulez pouvoir accéder aux resources via une url, il faut ajouter la ligne suivante:

main.ts

function bootstrap() {
...
app.useStaticAssets(join(__dirname, 'public'));
}

Example pour un utilisateur

user.schema.ts

import { Schema } from 'mongoose';
import ObjectId = Schema.Types.ObjectId;

export const UserSchema = new Schema({
  firstName: { type: String },
  lastName: { type: String },
  phoneNumber: { type: String },
  email: { type: String },
  avatar: {type: ObjectId, ref: 'Resources'} // On indique au schéma que c'est une ressource
}, { timestamps: true });

user.controller.ts

import { Body, Controller, Get, Param, Post, Put, Req, UseGuards } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './model/user.model';
import {
  AuthenticatedRequest,
  BearerGuard,
  InternalErrorResponse,
  Roles,
  RolesGuard,
  UnauthorizedErrorResponse,
} from '@enoviah/nest-core';

@Controller('users')
@ApiTags('Users')
export class UserController {
  constructor(private readonly userService: UserService) {
  }

  @Get(':id')
  @UseGuards(BearerGuard)
  @UseInterceptors(ResourceInterceptor) // On utilise l'interceptor des resources
  @SetMetadata('resources', ['avatar']) // on indique ou se trouve la resource dans l'objet
  updateOne(@Param('id') id: string) {
    return this.userService.findOne(id).pipe(mergeMap((user) => {
			return from(user.populate('avatar').execPopulate());
		}));
  }
}

On obtient après cet appel :

GET /USERS/:id
{
 ...,
 "avatar": {
	"_id": "string",
  "url": "https://xxxx/public/resources/xxx.png",
 }
} 

3.7.3 - Resource service

Vous pouvez accéder à ResourceService pour directement agir sur une resource.

3.8 - Google maps

Vous pouvez utiliser le controller Google maps de nest-core.

Il vous permet de :

  • D'auto-compléter une adresse en France
  • D'obtenir les coordonnées d'une adresse
  • D'obtenir les informations d'une place
  • D'obtenir les places autour d'une coordonnée

3.8.1 - Utilisation

Comme pour les autres modules, il vous suffit de l'importer dans votre module et de définir votre clef google.

Attention: Pensez à activer les différentes API sur votre panel Google.

.env

GMAPS_API_KEY=azeazxxxxazefezfzefez-azes

app.module.ts

import { Module } from '@nestjs/common';
import { NestCoreModule, GmapsModule, ResourceModule, Utils } from '@enoviah/nest-core';

@Module({
  imports: [
    NestCoreModule,
    GmapsModule,
    ],
  controllers: [],
  providers: [SyncGateway],
})
export class AppModule {
}

Vous pouvez maintenant utiliser les différentes routes.