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

kyoongdev-nestjs

v1.5.2

Published

본 라이브러리는 **@nestjs/swagger**의 사용 간소화 및 기타 유틸성 기능을 제공하는 라이브러리입니다.

Downloads

12

Readme

Nestjs Swagger & Utils Helper

본 라이브러리는 @nestjs/swagger의 사용 간소화 및 기타 유틸성 기능을 제공하는 라이브러리입니다.

프로젝트 세팅 시 필요한 기능을 제공합니다.

오류 발생 시 [email protected]으로 연락주시면 감사하겠습니다.

Swagger

스웨거 세팅방법

const swaggerConfig = new DocumentBuilder()
  .setTitle('제목')
  .setDescription('설명')
  .setVersion('1.0.0')
  .addServer('서버 URL')
  .addBearerAuth(
    {
      type: 'http',
      scheme: 'bearer',
      name: 'JWT',
      in: 'header',
    },
    'access-token'
  )
  .build();

const document = SwaggerModule.createDocument(app, swaggerConfig, {});

SwaggerModule.setup('api-docs', app, document);

@RequestApi(swaggerOptions : SwaggerOptions)

스웨거 Request 옵션

  • SwaggerOptions
    • summary?: ApiOperationOptions;
    • headers?: ApiHeaderOptions | ApiHeaderOptions[];
    • params?: ApiParamOptions | ApiParamOptions[];
    • query?: ApiQueryOptions | ApiQueryOptions[];
    • body?: ApiBodyOptions;

@ResponseApi(options: ApiResponseOptions & { isPaging?: boolean },code = 200 as HttpStatus)

스웨거 Response 옵션

  • ApiResponseOptions = ApiResponseMetadata | ApiResponseSchemaHost

  • ApiResponseMetadata

    • status?: number | 'default';
    • type?: Type | Function | [Function] | string;
    • isArray?: boolean;
    • description?: string;
  • ApiResponseSchemaHost

    • schema: SchemaObject & Partial;
    • status?: number;
    • description?: string;

@ApiFile(fieldName = "file")

스웨거 및 인터셉터 파일 업로드

@Auth(guard: Function[], name = 'access-token')

스웨거 및 UseGuards 가드 사용

@ApiFile(fieldName = "file")

Multi-Form 데이터 필요 시 사용

@Property({ apiProperty = {}, validation, overrideExisting, typeOptions = {} }: PropertyProps)

DTO 스웨거 명세 및 Validation (class-transformer, class-validation)

  • Property
    • apiProperty?: ApiPropertyOptions;
    • validation?: ValidationOptions;
    • overrideExisting?: boolean;
    • typeOptions?: TypeOptions;

페이징 관련

Request Swagger 용

export class PagingDTO {
  @Property({ apiProperty: { type: 'number', minimum: 1, default: 1 } })
  page: number;

  @Property({ apiProperty: { type: 'number', minimum: 1, default: 20 } })
  limit: number;

  constructor(page: number, limit: number) {
    this.page = page;
    this.limit = limit;
  }

  public getSkipTake(): SkipTake {
    const take = Number(this.limit) || 20;
    const skip = (Number(this.page) - 1) * take;

    return { skip, take };
  }

  public getSqlPaging(): PagingDTO {
    return {
      ...this,
      page: (this.page ? this.page - 1 : 1) * (this.limit || 1),
    };
  }
}

Response 데이터 전처리 용

export class PaginationDTO<T extends object> {
  @Property({ apiProperty: { isArray: true } })
  data: T[];

  @Property({ apiProperty: { type: PagingMetaDTO } })
  paging: PagingMetaDTO;

  constructor(data: T[], { paging, count }: PagingMetaDTOInterface) {
    this.data = data;
    this.paging = new PagingMetaDTO({ paging, count });
  }
}

미들웨어 적용

app.use(PaginationMiddleware);

Paging Params Decorator

async function example(@Paging() paging: PagingDTO) {}

Utils

Exception

CommonException

export class CommonException extends HttpException {
  constructor(error: BaseErrorCode) {
    super(error.message, error.code);
  }
}

표준화된 에러 response 필요 시 사용

ex)

const AUTH_ERROR = {
  WRONG_ACCESS_TOKEN: '잘못된 access 토큰입니다.',
};

export const AUTH_ERROR_CODE: ErrorCode<typeof AUTH_ERROR> = {
  WRONG_ACCESS_TOKEN: {
    code: HttpStatus.UNAUTHORIZED,
    message: AUTH_ERROR.WRONG_ACCESS_TOKEN,
  },
};

throw CommonException(AUTH_ERROR_CODE.WRONG_ACCESS_TOKEN);

HttpExceptionFilter

Http 관련 Exception을 처리할 수 있는 Filter

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  constructor(private readonly httpAdapterHost: HttpAdapterHost) {}

  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();

    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const errRes = exception['getResponse'] ? exception.getResponse() : null;
    const statusCode = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
    const message =
      errRes?.message && Array.isArray(errRes.message) && errRes.message.length > 0
        ? errRes.message
        : exception.message || 'Internal Server Error';

    console.error(exception.stack || message);

    response.status(statusCode).json({
      statusCode,
      timestamp: new Date().toISOString(),
      path: request.url,
      message,
    });
    request.destroy();
  }
}

Firebase

파이어베이스 기반 푸시 알림 설정

FirebaseMessaging

@Injectable()
export class FirebaseMessaging {
  private app: admin.app.App;

  constructor(private readonly configService: ConfigService) {
    this.app = admin.initializeApp({
      credential: admin.credential.cert(this.configService.get('FIRE_BASE_ACCOUNT') as string),
    });
  }

  async sendMessage({ token, notification }: SendMessageProps): Promise<SendMessageResponse> {
    try {
      await this.app.messaging().send({
        token,
        notification,
      });
      return true;
    } catch (error) {
      return false;
    }
  }

  async sendMessages(messages: SendMessagesProps): Promise<SendMessagesResponse> {
    const result: SendMessagesResponse = { success: [], failure: [] };
    for await (const message of messages) {
      const messageResult = await this.sendMessage({
        token: message.token,
        notification: message.notification as Notification,
      });

      if (messageResult) {
        result.success.push(message);
      } else {
        result.failure.push(message);
      }
    }

    return result;
  }
}

env에 "FIRE_BASE_ACCOUNT"를 통해 인증 정보가 있는 파일의 경로를 입력해주세요.

JWT

jwt 토큰을 생성, 검증할 수 있습니다.

JwtProvider

@Injectable()
export class JwtProvider {
  private readonly accessTokenExpiresIn: string = '2h' as const;
  private readonly refreshTokenExpiresIn: string = '14d' as const;

  constructor(private readonly configService: ConfigService) {
    if (configService.get('ACCESS_TOKEN_EXPIRES_IN')) {
      this.accessTokenExpiresIn = configService.get('ACCESS_TOKEN_EXPIRES_IN') as string;
    }
    if (configService.get('REFRESH_TOKEN_EXPIRES_IN')) {
      this.accessTokenExpiresIn = configService.get('REFRESH_TOKEN_EXPIRES_IN') as string;
    }
  }

  signJwt<T extends object>(value: T, options?: SignOptions): string {
    try {
      if (typeof value !== 'string' && typeof value !== 'object' && !Buffer.isBuffer(value)) {
        throw { status: 400, message: 'BadRequest Payload' };
      }

      return jwt.sign(value, this.configService.get<string>('JWT_KEY') as string, options ?? {});
    } catch (error) {
      throw new JsonWebTokenError('sign Failed');
    }
  }

  verifyJwt<T = any>(token: string, options?: VerifyOptions): T | any {
    try {
      return jwt.verify(token, this.configService.get<string>('JWT_KEY') as string, options ?? {}) as T;
    } catch (error) {
      throw new JsonWebTokenError('sign Failed');
    }
  }

  async createTokens<T extends object>(value: T, options?: SignOptions) {
    const key = nanoid();

    const accessToken = this.signJwt<T>({ ...value, key }, { ...options, expiresIn: this.accessTokenExpiresIn });
    const refreshToken = this.signJwt<T>({ ...value, key }, { ...options, expiresIn: this.refreshTokenExpiresIn });

    return { accessToken, refreshToken };
  }
}

env에 ACCESS_TOKEN_EXPIRES_IN 혹은 REFRESH_TOKEN_EXPIRES_IN을 설정 시 설정된 값으로 만료 기한이 설정됩니다.

Location

네이버, 카카오, 구글 지도 기반 API를 사용할 수 있는 Module입니다.

  • 각 서비스의 API 명세가 변경될 경우 작동하지 않을 수 있습니다.

SocialLocationModule

@Module({
  providers: [SocialLocationService],
  exports: [SocialLocationService],
})
export class SocialLocationModule {
  static forRoot(config: LocationProps = {}): DynamicModule {
    const providers: Provider[] = [
      {
        provide: LOCATION_CONFIG,
        useValue: config,
      },
    ];
    return {
      module: SocialLocationModule,
      providers,
      exports: providers,
    };
  }
}

LocatoinProps

export interface NaverLocationConfig {
  clientId: string;
  clientSecret: string;
}

export interface LocationProps {
  kakaoRestKey?: string;
  googleRestKey?: string;
  naver?: NaverLocationConfig;
}

SocialLocationService

getNaverLocation(params: NaverGeocodeQuery,config?: NaverLocationConfig): Promise<NaverGeocodeResponse>

네이버 좌표 기반 검색

getKakaoLocationByAddress({address,analyze_type = 'similar',page = 1,limit = 20,kakaoRestKey,}: KakaoAddressProps): Promise<{ data: KakaoAddressResponse[]; count: number } | null>

카카오 주소 기반 검색

getKakaoLocationByKeyword({keyword,latitude,longitude,radius = 200,page = 1,limit = 20,kakaoRestKey,category_group_code,}: KakaoKeywordProps): Promise<{ data: Array<KakaoKeywordResponse>; count: KakaoMeta } | null>

카카오 키워드 기반 검색

getKakaoLocationByGeocode({latitude,longitude,page = 1,limit = 20,kakaoRestKey}: KakaoGeocodeProps): Promise<{ data: KakaoGeocodeResponse; count: number } | null>

카카오 주소 기반 검색

getGoogleLocationByGeocode({ googleRestKey, latitude, longitude }: GoogleGeocodeProps)

구글 좌표 기반 검색

getDistance({ target, current }: DistanceProps): number

각 좌표 사이 직선 거리

QrCode

QrCode를 생성할 수 있는 Provider입니다.

QrCode

createQRCodeData(props: QrCode): Promise<QRCodeData | undefined>

QrCode 1개 생성

createQrCodesData(props: Array<QrCode>): Promise<QrCodesResponse>

QrCode 여러 개 생성

Social

소셜 로그인 관련 통합 모듈입니다. (Naver, Kakao, Google, Apple 포함)

SocialLoginModule

export interface NaverConfig {
  clientId: string;
  clientSecret: string | undefined;
  redirectUrl: string | undefined;
}

export interface GoogleConfig {
  clientId: string;
  clientSecret: string | undefined;
  redirectUri: string | undefined;
}

export interface KakaoConfig {
  restKey: string;
  secretKey: string | undefined;
  redirectUrl: string | undefined;
  adminKey: string | undefined;
}

export interface SocialConfig {
  kakao?: KakaoConfig;
  google?: GoogleConfig;
  naver?: NaverConfig;
  apple?: AppleConfig;
}

export interface AppleConfig {
  appleConfig: AppleAuthConfig; // apple-auth의 config
  path: string;
}


SocialLoginModule.forRoot(config: SocialConfig = {})

NaverLogin

getRest(res: Response, code: string, redirectUrl?: string)

redirectUrl로 redirect

getUser(token: string): Promise<NaverUser | undefined>

토큰을 통해 네이버 유저 검색

getToken(code: string): Promise<NaverToken | undefined>

로그인 성공 후 코드를 통해 토큰 생성

getRestCallback(code: string): Promise<NaverGetRestCallback | undefined>

로그인 성공 후 네이버 유저 정보 반황

KakaoLogin

getRest(res: Response, redirectUrl?: string)

redirectUrl로 redirect

getUser(token: string): Promise<KakaoGetUser | undefined>

토큰을 통해 카카오 유저 검색

getToken(code: string, redirectUrl?: string): Promise<string | undefined>

로그인 성공 후 코드를 통해 토큰 생성

getRestCallback(code: string): Promise<KakaoGetRestCallback | undefined>

로그인 성공 후 카카오 유저 정보 반환

GoogleLogin

public getRest(res: Response, redirectUrl?: string)

redirectUrl로 redirect

getToken(code: string): Promise<string | undefined>

로그인 성공 후 코드를 통해 토큰 생성

getAppUser(token: string): Promise<GoogleUser | undefined>

토큰을 통해 구글 유저 검색 (앱 사용 시)

getWebUser(token: string): Promise<GoogleUser | undefined>

토큰을 통해 구글 유저 검색 (웹 사용 시)

getRestCallback(code: string): Promise<GoogleGetRestCallback | undefined>

로그인 성공 후 구글 유저 정보 반환

Apple Login

애플 로그인은 HTTPS 설정이 완료되어야 사용 가능합니다.

private setAppleAuth()

애플 인증 정보 설정하기

getRest(res: Response)

redirectUrl로 redirect (애플은 redirect url의 HTTP method가 POST이어야 합니다.)

getUser(id_token: string): Promise<AppleUser | undefined>

id_token을 통해 애플 유저 반환

getRestCallback(code: string): Promise<AppleUser | undefined>

로그인 성공 후 애플 유저 반환