Compare commits

...

45 Commits

Author SHA1 Message Date
Kamil Myśliwiec
200e6cb673 chore(release) publish v4.5.2 2017-12-22 15:12:33 +01:00
Kamil Myśliwiec
e83aca183d update(@core) increase router performance 2017-12-22 15:08:46 +01:00
Kamil Myśliwiec
2a6ca015fc cov(@nestjs) increase test coverage 2017-12-21 22:03:16 +01:00
Kamil Myśliwiec
864fac9cea feature(@common) rename modules to imports property 2017-12-21 20:26:45 +01:00
Kamil Myśliwiec
2a727b9024 Merge remote-tracking branch 'origin/master' 2017-12-21 20:17:29 +01:00
Kamil Myśliwiec
d7b0e0557b ci(@nestjs) update prettier options 2017-12-21 20:14:23 +01:00
Kamil Myśliwiec
52e0128258 ci(@nestjs) integrate with prettier 2017-12-21 19:29:39 +01:00
Kamil Myśliwiec
bb0ce8ce3f Update Readme.md 2017-12-21 14:27:29 +01:00
Kamil Myśliwiec
8afafc6c34 Update Readme.md 2017-12-21 14:27:01 +01:00
Kamil Myśliwiec
028c8aacf0 Merge pull request #319 from XerxesMK/patch-2
Removed unused import
2017-12-21 11:47:33 +01:00
Hector Chauran
b605b8871e Removed unused import
`PrimaryGeneratedColumn` is not  being used in `photo.entity.ts` because the example uses mongodb.
2017-12-20 19:22:08 -04:00
Kamil Myśliwiec
81be8a0fbc Merge remote-tracking branch 'origin/master' 2017-12-15 23:41:53 +01:00
Kamil Myśliwiec
27b54d567a update(@nestjs) update package.json 2017-12-15 23:41:47 +01:00
Kamil Myśliwiec
4d4f7a448c Merge pull request #250 from wbhob/contrib
Add contribution guidelines v1
2017-12-15 22:55:35 +01:00
Kamil Myśliwiec
ade7aed794 Merge branch 'master' into contrib 2017-12-15 22:54:13 +01:00
Kamil Myśliwiec
fe24ae456b Merge branch 'master' into contrib 2017-12-15 22:53:32 +01:00
Kamil Myśliwiec
3e0ee2108f chore(release) publish v4.5.1 2017-12-15 22:31:27 +01:00
Kamil Myśliwiec
49bb841615 update(@nestjs) update package.json 2017-12-15 20:59:33 +01:00
Kamil Myśliwiec
ca3ff1b2d8 update(@nestjs) CHANGELOG update 2017-12-15 16:33:01 +01:00
Kamil Myśliwiec
62adce80c8 update(@nestjs) lib & CHANGELOG update 2017-12-15 16:32:05 +01:00
Kamil Myśliwiec
e22d2beb17 chore(release) publish v4.5.0 2017-12-15 15:02:22 +01:00
Kamil Myśliwiec
fb836bccee Merge remote-tracking branch 'origin/master' 2017-12-15 14:56:29 +01:00
Kamil Myśliwiec
4795b8f209 feature(@nestjs) dynamic modules, global scope, bugfixes, improvements 2017-12-15 14:34:10 +01:00
Kamil Myśliwiec
910e089a9b Merge pull request #278 from patrickhousley/fix/app-context-symbol
fix(@nestjs/core) application context, support symbol
2017-12-15 14:30:55 +01:00
Kamil Myśliwiec
b7268e145a Update Readme.md 2017-12-15 14:29:57 +01:00
Kamil Myśliwiec
a11186048a Merge pull request #291 from Caballerog/patch-1
fix(microservices-example): Remove unused imports
2017-12-10 21:04:19 +01:00
Carlos Caballero
8b825b6031 fix(microservices-example): Remove unused imports
Remove unused imports like WsException and HttpStatus
2017-12-07 17:02:54 +01:00
Patrick Housley
fece41a0fe fix(@nestjs/core) application context, support symbol
Update application context to support retrieving a module using a symbol. The injector already supports the use of symbols when declaring modules for DI.
2017-11-29 23:55:49 -06:00
Kamil Myśliwiec
853c3c96f3 Update Readme.md 2017-11-29 23:38:07 +01:00
Kamil Myśliwiec
2bca46d3d5 Update Readme.md 2017-11-29 23:05:02 +01:00
Kamil Myśliwiec
0bf4de8ef7 Update Readme.md 2017-11-29 22:57:46 +01:00
Kamil Myśliwiec
3747abc32a fix(@nestjs/core) token factory, use optional param instead 2017-11-27 22:53:45 +01:00
Kamil Myśliwiec
256d1aa054 fix(@nestjs/core) token factory bugfix 2017-11-27 22:52:55 +01:00
Kamil Myśliwiec
147410972d ci(@nestjs) fix build script (gulp) 2017-11-27 22:50:46 +01:00
Kamil Myśliwiec
64e6b1717b ci(@nestjs) fix tests 2017-11-27 22:45:39 +01:00
Kamil Myśliwiec
6a2b5a950a feature(@nestjs/core) dynamic modules improvement 2017-11-27 22:23:58 +01:00
Kamil Myśliwiec
f5c50fd377 feature(@nestjs/core) dynamic modules & global scope feature 2017-11-27 21:16:03 +01:00
Kamil Myśliwiec
7e9cca06e3 examples(@nestjs) add swagger example 2017-11-25 23:43:18 +01:00
Wilson Hobbs
82cb61aa2b Merge branch 'master' into contrib 2017-11-24 20:52:59 -05:00
Wilson Hobbs
447b8ab624 Fix the last mention of Angular 2017-11-17 09:14:44 -05:00
Wilson Hobbs
5b92c33cb2 Merge branch 'master' of https://github.com/nestjs/nest into contrib 2017-11-16 21:10:57 -05:00
Wilson Hobbs
77817b232f revert(): remove outstanding commit from other PR 2017-11-16 20:47:41 -05:00
Wilson Hobbs
40194281b1 Revert "ci(): add format checker\nthis commit will ensure that every commit is properly formatted. I\'ve included a command, [20:37:16] Using gulpfile ~/nest/gulpfile.js"
This reverts commit c4a3e0296d.
2017-11-16 20:46:37 -05:00
Wilson Hobbs
2984df1395 chore(): add contribution guidelines v1 2017-11-16 20:41:41 -05:00
Wilson Hobbs
c4a3e0296d ci(): add format checker\nthis commit will ensure that every commit is properly formatted. I\'ve included a command, [20:37:16] Using gulpfile ~/nest/gulpfile.js
[20:37:16] Starting 'format'...
[20:37:22] Finished 'format' after 5.76 s that will take care of this for you.\nThis functionality is taken directly from Angular's repository.
2017-11-16 20:37:22 -05:00
788 changed files with 16035 additions and 10921 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,6 @@
# dependencies
node_modules/
package-lock.json
# IDE
/.idea
/.awcache

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}

View File

@@ -1,3 +1,28 @@
## 4.5.3
- **core**: [improvement] increase performance
## 4.5.2
- **common**: [feature] rename `modules` to `imports` (`@Module()` decorator)
- **core**: [feature] exception filters with empty `@Catch()` metadata handle each occurred exception
## 4.5.1
- **common**: [feature] `INestAplication` provides a `getHttpServer()` method now
- **websockets**: [bugfix] `IoAdapter` bugfix
## 4.5.0
- **common**: bugfix #286
- **core**: dynamic modules feature
- **core**: global scope feature
- **core**: `ExternalContextCreator` & `ModulesContainer`
- **core**: merge `NestApplicationContext` with `NestApplication`
- **core**: `NotFoundException` is thrown when route is not available #298
- **core**: add `set()` wrapper around native express methods
- **core**: bugfix #281
- **websockets**: bugfix #271
- **microservices**: log RPC exceptions #303
- **microservices**: merge `NestApplicationContext` with `NestMicroservice`
- **microservices**: handle ECONNREFUSED #288
## 4.4.1
- **common**: `ValidationPipe` improvement
- **common**: custom route params decorators accepts pipes now

271
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,271 @@
# Contributing to Nest
We would love for you to contribute to Nest and help make it even better than it is
today! As a contributor, here are the guidelines we would like you to follow:
- [Code of Conduct](#coc)
- [Question or Problem?](#question)
- [Issues and Bugs](#issue)
- [Feature Requests](#feature)
- [Submission Guidelines](#submit)
- [Coding Rules](#rules)
- [Commit Message Guidelines](#commit)
<!-- - [Signing the CLA](#cla) -->
<!-- ## <a name="coc"></a> Code of Conduct
Help us keep Nest open and inclusive. Please read and follow our [Code of Conduct][coc]. -->
## <a name="question"></a> Got a Question or Problem?
**Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.** You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/nestjs) where the questions should be tagged with tag `nestjs`.
Stack Overflow is a much better place to ask questions since:
<!-- - there are thousands of people willing to help on Stack Overflow [maybe one day] -->
- questions and answers stay available for public viewing so your question / answer might help someone else
- Stack Overflow's voting system assures that the best answers are prominently visible.
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
## <a name="issue"></a> Found a Bug?
If you find a bug in the source code, you can help us by
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
[submit a Pull Request](#submit-pr) with a fix.
## <a name="feature"></a> Missing a Feature?
You can *request* a new feature by [submitting an issue](#submit-issue) to our GitHub
Repository. If you would like to *implement* a new feature, please submit an issue with
a proposal for your work first, to be sure that we can use it.
Please consider what kind of change it is:
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
and help you to craft the change so that it is successfully accepted into the project. For your issue name, please prefix your proposal with `[discussion]`, for example "[discussion]: your feature idea".
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
## <a name="submit"></a> Submission Guidelines
### <a name="submit-issue"></a> Submitting an Issue
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using a repository or [Gist](https://gist.github.com/). Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
- version of NestJS used
- 3rd-party libraries and their versions
- and most importantly - a use-case that fails
<!--
// TODO we need to create a playground, similar to plunkr
A minimal reproduce scenario using a repository or Gist allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If neither of these are not a suitable way to demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating the problem. -->
<!-- We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it. -->
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
You can file new issues by filling out our [new issue form](https://github.com/nestjs/nest/issues/new).
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines:
1. Search [GitHub](https://github.com/nestjs/nest/pulls) for an open or closed PR
that relates to your submission. You don't want to duplicate effort.
<!-- 1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without this. -->
1. Fork the nestjs/nest repo.
1. Make your changes in a new git branch:
```shell
git checkout -b my-fix-branch master
```
1. Create your patch, **including appropriate test cases**.
1. Follow our [Coding Rules](#rules).
1. Run the full Nest test suite, as described in the [developer documentation][dev-doc],
and ensure that all tests pass.
1. Commit your changes using a descriptive commit message that follows our
[commit message conventions](#commit). Adherence to these conventions
is necessary because release notes are automatically generated from these messages.
```shell
git commit -a
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
1. Push your branch to GitHub:
```shell
git push origin my-fix-branch
```
1. In GitHub, send a pull request to `nestjs:master`.
* If we suggest changes then:
* Make the required updates.
* Re-run the Nest test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell
git rebase master -i
git push -f
```
That's it! Thank you for your contribution!
#### After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes
from the main (upstream) repository:
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
```shell
git push origin --delete my-fix-branch
```
* Check out the master branch:
```shell
git checkout master -f
```
* Delete the local branch:
```shell
git branch -D my-fix-branch
```
* Update your master with the latest upstream version:
```shell
git pull --ff upstream master
```
## <a name="rules"></a> Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
<!--
// We're working on auto-documentation.
* All public API methods **must be documented**. (Details TBC). -->
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available, see
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Guidelines
We have very precise rules over how our git commit messages can be formatted. This leads to **more
readable messages** that are easy to follow when looking through the **project history**. But also,
we use the git commit messages to **generate the Nest change log**.
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
Footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
Samples: (even more [samples](https://github.com/nestjs/nest/commits/master))
```
docs(changelog): update change log to beta.5
```
```
fix(release): need to depend on latest rxjs and zone.js
The version in our package.json gets copied to the one we publish, and users need the latest of these.
```
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* **docs**: Documentation only changes
* **feat**: A new feature
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
### Scope
The scope should be the name of the npm package affected (as perceived by person reading changelog generated from commit messages.
The following is the list of supported scopes:
* **common**
* **core**
* **examples**
* **microservices**
* **testing**
* **websockets**
There are currently a few exceptions to the "use package name" rule:
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **changelog**: used for updating the release notes in CHANGELOG.md
* **examples/#**: for the example apps directory, replacing # with the example app number
<!-- * **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo -->
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
A detailed explanation can be found in this [document][commit-message-format].
<!-- ## <a name="cla"></a> Signing the CLA
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code
changes to be accepted, the CLA must be signed. It's a quick process, we promise!
* For individuals we have a [simple click-through form][individual-cla].
* For corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form][corporate-cla]. -->
<!-- [angular-group]: https://groups.google.com/forum/#!forum/angular -->
<!-- [coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md -->
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/nestjs/nest/blob/master/docs/DEVELOPER.md
[github]: https://github.com/nestjs/nest
[gitter]: https://gitter.im/nestjs/nest
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: http://jsfiddle.net
[plunker]: http://plnkr.co/edit
[runnable]: http://runnable.com
<!-- [stackoverflow]: http://stackoverflow.com/questions/tagged/angular -->

View File

@@ -7,7 +7,7 @@
[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
[linux-url]: https://travis-ci.org/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable web applications. :cat: </p>
<p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications, heavily inspired by <a href="https://angular.io" target="blank">Angular</a>.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
@@ -24,7 +24,7 @@
## Description
<p>Nest is a framework for building efficient, scalable <a href="http://nodejs.org" target="_blank">Node.js</a> web applications. It uses modern JavaScript, is built with <a href="http://www.typescriptlang.org" target="_blank">TypeScript</a> (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).</p>
<p>Nest is a framework for building efficient, scalable <a href="http://nodejs.org" target="_blank">Node.js</a> server-side applications. It uses modern JavaScript, is built with <a href="http://www.typescriptlang.org" target="_blank">TypeScript</a> (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).</p>
<p>Under the hood, Nest makes use of <a href="https://expressjs.com/" target="_blank">Express</a>, allowing for easy use of the myriad third-party plugins which are available.</p>
## Philosophy
@@ -32,58 +32,17 @@
<p>In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications, giving rise to awesome projects like <a href="https://angular.io/" target="_blank">Angular</a>, <a href="https://github.com/facebook/react" target="_blank">React</a> and <a href="https://github.com/vuejs/vue" target="_blank">Vue</a> which improve developer productivity and enable the construction of fast, testable, extensible frontend applications. However, on the server-side, while there are a lot of superb libraries, helpers and tools for Node, none of them effectively solve the main problem - the architecture.</p>
<p>Nest aims to provide an application architecture out of the box which allows for effortless creation of highly testable, scalable, loosely coupled and easily maintainable applications.</p>
## Features
## Getting started
<ul>
<li>Built with <a href="http://www.typescriptlang.org" target="_blank">TypeScript</a> (compatible with pure JavaScript + <a href="http://babeljs.io/" target="_blank">Babel</a>)</li>
<li><strong>Easy</strong> to learn - syntax similar to <a href="https://angular.io/" target="_blank">Angular</a></li>
<li><strong>Familiar</strong> - based on well-known libraries (<a href="https://github.com/expressjs/express" target="_blank">Express</a> / <a href="https://github.com/socketio/socket.io" target="_blank">socket.io</a>)</li>
<li><strong>Dependency Injection</strong> - built-in asynchronous <strong>IoC</strong> container with a <strong>hierarchical injector</strong></li>
<li><strong>WebSockets</strong> module (based on <a href="https://github.com/socketio/socket.io" target="_blank">socket.io</a>, but you can bring your own library, by making use of <code>WsAdapter</code>)</li>
<li><strong>Modular</strong> - defines an easy to follow module definition pattern so you can split your system into reusable modules</li>
<li><strong>Reactive microservice</strong> support with message patterns (built-in transport via TCP / <a href="https://redis.io/" target="_blank">Redis</a>, but other communication schemes can be implemented with <code>CustomTransportStrategy</code>)</li>
<li><strong>Exception layer</strong> - throwable web exceptions with status codes, exception filters</li>
<li><strong>Pipes</strong> - synchronous & asynchronous (e.g. validation purposes)</li>
<li><strong>Guards</strong> - attach additional logic in a declarative manner (e.g. role-based access control)</li>
<li><strong>Interceptors</strong> - built on top of <a href="https://github.com/reactivex/rxjs" target="blank">RxJS</a></li>
<li>Testing utilities (both <strong>e2e & unit</strong> tests)</li>
<li><strong>More</strong>!</li>
</ul>
## Installation
**Install the TypeScript Starter Project with Git:**
```bash
$ git clone https://github.com/nestjs/typescript-starter.git project
$ cd project
$ npm install
$ npm run start
```
**Install the JavaScript (Babel) Starter Project with Git:**
```bash
$ git clone https://github.com/nestjs/javascript-starter.git project
$ cd project
$ npm install
$ npm run start
```
**Start a New Project from Scratch with NPM:**
```bash
$ npm i --save @nestjs/core @nestjs/common @nestjs/microservices @nestjs/websockets @nestjs/testing reflect-metadata rxjs
```
## Documentation & Quick Start
:books: [Documentation & Tutorial](https://docs.nestjs.com)
To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
## Sponsors
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://opencollective.com/nest). Thanks! :heart_eyes:
<a href="https://valor-software.com/"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="210" /></a>
## Backers
Nest is an MIT-licensed open source project. It can grow thanks to the support by these awesome people. If you'd like to join them, please [read more here](https://opencollective.com/nest#backer). Thanks! :heart_eyes:
## Backers
<a href="https://opencollective.com/nest/backer/0/website" target="_blank"><img src="https://opencollective.com/nest/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/nest/backer/1/website" target="_blank"><img src="https://opencollective.com/nest/backer/1/avatar.svg"></a>
@@ -123,4 +82,4 @@ Nest is an MIT-licensed open source project. It can grow thanks to the support b
## License
[MIT](LICENSE)
Nest is [MIT licensed](LICENSE).

View File

@@ -1,33 +1,39 @@
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { CatsModule } from '../../src/modules/cats/cats.module';
import { CatsService } from '../../src/modules/cats/cats.service';
import { INestApplication } from '@nestjs/common';
describe('Cats', () => {
const server = express();
server.use(bodyParser.json());
let server;
let app: INestApplication;
const catsService = { findAll: () => ['test'] };
const catsService = { findAll: () => ['test'] };
beforeAll(async () => {
const module = await Test.createTestingModule({
modules: [CatsModule],
})
.overrideComponent(CatsService).useValue(catsService)
.compile();
beforeAll(async () => {
const module = await Test.createTestingModule({
modules: [CatsModule],
})
.overrideComponent(CatsService)
.useValue(catsService)
.compile();
const app = module.createNestApplication(server);
await app.init();
});
server = express();
app = module.createNestApplication(server);
await app.init();
});
it(`/GET cats`, () => {
return request(server)
.get('/cats')
.expect(200)
.expect({
data: catsService.findAll(),
});
});
});
it(`/GET cats`, () => {
return request(server)
.get('/cats')
.expect(200)
.expect({
data: catsService.findAll(),
});
});
afterAll(async () => {
await app.close();
});
});

View File

@@ -4,12 +4,13 @@ import { CatsModule } from './cats/cats.module';
import { CatsController } from './cats/cats.controller';
@Module({
modules: [CatsModule],
modules: [CatsModule],
})
export class ApplicationModule implements NestModule {
configure(consumer: MiddlewaresConsumer): void {
consumer.apply(LoggerMiddleware)
.with('ApplicationModule')
.forRoutes(CatsController);
}
}
configure(consumer: MiddlewaresConsumer): void {
consumer
.apply(LoggerMiddleware)
.with('ApplicationModule')
.forRoutes(CatsController);
}
}

View File

@@ -8,9 +8,9 @@ describe('CatsController', () => {
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [CatsController],
components: [CatsService],
}).compile();
controllers: [CatsController],
components: [CatsService],
}).compile();
catsService = module.get<CatsService>(CatsService);
catsController = module.get<CatsController>(CatsController);
@@ -24,4 +24,4 @@ describe('CatsController', () => {
expect(await catsController.findAll()).toBe(result);
});
});
});
});

View File

@@ -1,4 +1,13 @@
import { Controller, Get, Post, Body, UseGuards, ReflectMetadata, UseInterceptors, Param } from '@nestjs/common';
import {
Controller,
Get,
Post,
Body,
UseGuards,
ReflectMetadata,
UseInterceptors,
Param,
} from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
@@ -26,7 +35,10 @@ export class CatsController {
}
@Get(':id')
findOne(@Param('id', new ParseIntPipe()) id) {
findOne(
@Param('id', new ParseIntPipe())
id,
) {
// logic
}
}
}

View File

@@ -3,7 +3,7 @@ import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
components: [CatsService],
controllers: [CatsController],
components: [CatsService],
})
export class CatsModule {}
export class CatsModule {}

View File

@@ -13,4 +13,4 @@ export class CatsService {
findAll(): Cat[] {
return this.cats;
}
}
}

View File

@@ -1,12 +1,9 @@
import { IsString, IsInt } from 'class-validator';
export class CreateCatDto {
@IsString()
readonly name: string;
@IsString() readonly name: string;
@IsInt()
readonly age: number;
@IsInt() readonly age: number;
@IsString()
readonly breed: string;
}
@IsString() readonly breed: string;
}

View File

@@ -2,4 +2,4 @@ export interface Cat {
readonly name: string;
readonly age: number;
readonly breed: string;
}
}

View File

@@ -1,3 +1,3 @@
import { ReflectMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);

View File

@@ -5,4 +5,4 @@ export class ForbiddenException extends HttpException {
constructor() {
super('Forbidden', HttpStatus.FORBIDDEN);
}
}
}

View File

@@ -11,4 +11,4 @@ export class HttpExceptionFilter implements ExceptionFilter {
message: `It's a message from the exception filter`,
});
}
}
}

View File

@@ -14,7 +14,8 @@ export class RolesGuard implements CanActivate {
}
const user = req.user;
const hasRole = () => !!user.roles.find((role) => !!roles.find((item) => item === role));
const hasRole = () =>
!!user.roles.find(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
}

View File

@@ -6,10 +6,14 @@ import 'rxjs/add/observable/of';
export abstract class CacheInterceptor implements NestInterceptor {
protected abstract readonly isCached: () => boolean;
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
if (this.isCached()) {
return Observable.of([]);
}
return stream$;
}
}
}

View File

@@ -1,4 +1,9 @@
import { Interceptor, NestInterceptor, ExecutionContext, HttpStatus } from '@nestjs/common';
import {
Interceptor,
NestInterceptor,
ExecutionContext,
HttpStatus,
} from '@nestjs/common';
import { HttpException } from '@nestjs/common';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
@@ -6,9 +11,18 @@ import 'rxjs/add/observable/throw';
@Interceptor()
export class ExceptionInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
return stream$.catch((err) => Observable.throw(
new HttpException('Exception interceptor message', HttpStatus.BAD_GATEWAY),
));
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
return stream$.catch(err =>
Observable.throw(
new HttpException(
'Exception interceptor message',
HttpStatus.BAD_GATEWAY,
),
),
);
}
}
}

View File

@@ -4,12 +4,14 @@ import 'rxjs/add/operator/do';
@Interceptor()
export class LoggingInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
console.log('Before...');
const now = Date.now();
return stream$.do(
() => console.log(`After... ${Date.now() - now}ms`),
);
return stream$.do(() => console.log(`After... ${Date.now() - now}ms`));
}
}
}

View File

@@ -2,7 +2,9 @@ import { mixin } from '@nestjs/common';
import { CacheInterceptor } from './cache.interceptor';
export function mixinCacheInterceptor(isCached: () => boolean) {
return mixin(class extends CacheInterceptor {
protected readonly isCached = isCached;
});
}
return mixin(
class extends CacheInterceptor {
protected readonly isCached = isCached;
},
);
}

View File

@@ -4,7 +4,11 @@ import 'rxjs/add/operator/map';
@Interceptor()
export class TransformInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
return stream$.map((data) => ({ data }));
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
return stream$.map(data => ({ data }));
}
}
}

View File

@@ -7,5 +7,5 @@ export class LoggerMiddleware implements NestMiddleware {
console.log(`[${name}] Request...`); // [ApplicationModule] Request...
next();
};
}
}
}
}

View File

@@ -1,5 +1,10 @@
import { HttpException } from '@nestjs/common';
import { PipeTransform, Pipe, ArgumentMetadata, HttpStatus } from '@nestjs/common';
import {
PipeTransform,
Pipe,
ArgumentMetadata,
HttpStatus,
} from '@nestjs/common';
@Pipe()
export class ParseIntPipe implements PipeTransform<string> {
@@ -10,4 +15,4 @@ export class ParseIntPipe implements PipeTransform<string> {
}
return val;
}
}
}

View File

@@ -1,25 +1,30 @@
import { HttpException } from '@nestjs/common';
import { PipeTransform, Pipe, ArgumentMetadata, HttpStatus } from '@nestjs/common';
import {
PipeTransform,
Pipe,
ArgumentMetadata,
HttpStatus,
} from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
@Pipe()
export class ValidationPipe implements PipeTransform<any> {
async transform(value, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new HttpException('Validation failed', HttpStatus.BAD_REQUEST);
}
async transform(value, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
private toValidate(metatype): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.find((type) => metatype === type);
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new HttpException('Validation failed', HttpStatus.BAD_REQUEST);
}
}
return value;
}
private toValidate(metatype): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.find(type => metatype === type);
}
}

View File

@@ -2,6 +2,6 @@ import { Module } from '@nestjs/common';
import { EventsModule } from './events/events.module';
@Module({
modules: [EventsModule],
modules: [EventsModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -22,9 +22,9 @@ export class WsAdapter implements WebSocketAdapter {
process: (data: any) => Observable<any>,
) {
Observable.fromEvent(client, 'message')
.switchMap((buffer) => this.bindMessageHandler(buffer, handlers, process))
.filter((result) => !!result)
.subscribe((response) => client.send(JSON.stringify(response)));
.switchMap(buffer => this.bindMessageHandler(buffer, handlers, process))
.filter(result => !!result)
.subscribe(response => client.send(JSON.stringify(response)));
}
public bindMessageHandler(
@@ -33,11 +33,13 @@ export class WsAdapter implements WebSocketAdapter {
process: (data: any) => Observable<any>,
): Observable<any> {
const data = JSON.parse(buffer.data);
const messageHandler = handlers.find((handler) => handler.message === data.type);
const messageHandler = handlers.find(
handler => handler.message === data.type,
);
if (!messageHandler) {
return Observable.empty();
}
const { callback } = messageHandler;
return process(callback(data));
}
}
}

View File

@@ -1,3 +1,3 @@
import { ReflectMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);

View File

@@ -9,4 +9,4 @@ export class ExceptionFilter implements WsExceptionFilter {
message: `It's a message from the exception filter`,
});
}
}
}

View File

@@ -14,7 +14,8 @@ export class RolesGuard implements CanActivate {
}
const user = data.user;
const hasRole = () => !!user.roles.find((role) => !!roles.find((item) => item === role));
const hasRole = () =>
!!user.roles.find(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
}

View File

@@ -4,11 +4,15 @@ import 'rxjs/add/observable/of';
@Interceptor()
export class CacheInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
const isCached = true;
if (isCached) {
return Observable.of([]);
}
return stream$;
}
}
}

View File

@@ -4,12 +4,14 @@ import 'rxjs/add/operator/do';
@Interceptor()
export class LoggingInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
console.log('Before...');
const now = Date.now();
return stream$.do(
() => console.log(`After... ${Date.now() - now}ms`),
);
return stream$.do(() => console.log(`After... ${Date.now() - now}ms`));
}
}
}

View File

@@ -4,7 +4,11 @@ import 'rxjs/add/operator/map';
@Interceptor()
export class TransformInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
return stream$.map((data) => ({ data }));
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
return stream$.map(data => ({ data }));
}
}
}

View File

@@ -1,25 +1,30 @@
import { PipeTransform, Pipe, ArgumentMetadata, HttpStatus } from '@nestjs/common';
import {
PipeTransform,
Pipe,
ArgumentMetadata,
HttpStatus,
} from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
import { WsException } from '@nestjs/websockets';
@Pipe()
export class ValidationPipe implements PipeTransform<any> {
async transform(value, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new WsException('Validation failed');
}
async transform(value, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
private toValidate(metatype): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.find((type) => metatype === type);
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new WsException('Validation failed');
}
}
return value;
}
private toValidate(metatype): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.find(type => metatype === type);
}
}

View File

@@ -1,9 +1,17 @@
import { WebSocketGateway, SubscribeMessage, WsResponse, WebSocketServer, WsException } from '@nestjs/websockets';
import {
WebSocketGateway,
SubscribeMessage,
WsResponse,
WebSocketServer,
WsException,
} from '@nestjs/websockets';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/map';
@WebSocketGateway(81)
@WebSocketGateway({ namespace: 'events' })
export class EventsGatewayxD {}
@WebSocketGateway({ namespace: 'xd' })
export class EventsGateway {
@WebSocketServer() server;
@@ -12,7 +20,6 @@ export class EventsGateway {
const event = 'events';
const response = [1, 2, 3];
return Observable.from(response)
.map((res) => ({ event, data: res }));
return Observable.from(response).map(res => ({ event, data: res }));
}
}
}

View File

@@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { EventsGateway } from './events.gateway';
import { EventsGateway, EventsGatewayxD } from './events.gateway';
@Module({
components: [EventsGateway],
components: [EventsGateway, EventsGatewayxD],
})
export class EventsModule {}
export class EventsModule {}

View File

@@ -2,6 +2,6 @@ import { Module } from '@nestjs/common';
import { MathModule } from './math/math.module';
@Module({
modules: [MathModule],
modules: [MathModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -2,13 +2,14 @@ import * as amqp from 'amqplib';
import { ClientProxy } from '@nestjs/microservices';
export class RabbitMQClient extends ClientProxy {
constructor(
private readonly host: string,
private readonly queue: string) {
super();
}
constructor(private readonly host: string, private readonly queue: string) {
super();
}
protected async sendSingleMessage(messageObj, callback: (err, result, disposed?: boolean) => void) {
protected async sendSingleMessage(
messageObj,
callback: (err, result, disposed?: boolean) => void,
) {
const server = await amqp.connect(this.host);
const channel = await server.createChannel();
const { sub, pub } = this.getQueues();
@@ -16,15 +17,23 @@ export class RabbitMQClient extends ClientProxy {
channel.assertQueue(sub, { durable: false });
channel.assertQueue(pub, { durable: false });
channel.consume(pub, (message) => this.handleMessage(message, server, callback), { noAck: true });
channel.consume(
pub,
message => this.handleMessage(message, server, callback),
{ noAck: true },
);
channel.sendToQueue(sub, Buffer.from(JSON.stringify(messageObj)));
}
private handleMessage(message, server, callback: (err, result, disposed?: boolean) => void) {
private handleMessage(
message,
server,
callback: (err, result, disposed?: boolean) => void,
) {
const { content } = message;
const { err, response, disposed } = JSON.parse(content.toString());
if (disposed) {
server.close();
server.close();
}
callback(err, response, disposed);
}
@@ -32,4 +41,4 @@ export class RabbitMQClient extends ClientProxy {
private getQueues() {
return { pub: `${this.queue}_pub`, sub: `${this.queue}_sub` };
}
}
}

View File

@@ -3,14 +3,12 @@ import { Server, CustomTransportStrategy } from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
export class RabbitMQServer extends Server implements CustomTransportStrategy {
private server: amqp.Connection = null;
private channel: amqp.Channel = null;
private server: amqp.Connection = null;
private channel: amqp.Channel = null;
constructor(
private readonly host: string,
private readonly queue: string) {
super();
}
constructor(private readonly host: string, private readonly queue: string) {
super();
}
public async listen(callback: () => void) {
await this.init();
@@ -31,12 +29,14 @@ export class RabbitMQServer extends Server implements CustomTransportStrategy {
const handlers = this.getHandlers();
const pattern = JSON.stringify(messageObj.pattern);
if (!this.messageHandlers[pattern]) {
return;
return;
}
const handler = this.messageHandlers[pattern];
const response$ = this.transformToObservable(await handler(messageObj.data)) as Observable<any>;
response$ && this.send(response$, (data) => this.sendMessage(data));
const response$ = this.transformToObservable(
await handler(messageObj.data),
) as Observable<any>;
response$ && this.send(response$, data => this.sendMessage(data));
}
private sendMessage(message) {
@@ -50,4 +50,4 @@ export class RabbitMQServer extends Server implements CustomTransportStrategy {
this.channel.assertQueue(`${this.queue}_sub`, { durable: false });
this.channel.assertQueue(`${this.queue}_pub`, { durable: false });
}
}
}

View File

@@ -1,3 +1,3 @@
import { ReflectMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);
export const Roles = (...roles: string[]) => ReflectMetadata('roles', roles);

View File

@@ -8,4 +8,4 @@ export class ExceptionFilter implements RpcExceptionFilter {
catch(exception: RpcException): Observable<any> {
return Observable.throw(exception.getError());
}
}
}

View File

@@ -14,7 +14,8 @@ export class RolesGuard implements CanActivate {
}
const user = data.user;
const hasRole = () => !!user.roles.find((role) => !!roles.find((item) => item === role));
const hasRole = () =>
!!user.roles.find(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
}

View File

@@ -4,11 +4,15 @@ import 'rxjs/add/observable/of';
@Interceptor()
export class CacheInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
const isCached = true;
if (isCached) {
return Observable.of([]);
}
return stream$;
}
}
}

View File

@@ -4,12 +4,14 @@ import 'rxjs/add/operator/do';
@Interceptor()
export class LoggingInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
console.log('Before...');
const now = Date.now();
return stream$.do(
() => console.log(`After... ${Date.now() - now}ms`),
);
return stream$.do(() => console.log(`After... ${Date.now() - now}ms`));
}
}
}

View File

@@ -4,7 +4,11 @@ import 'rxjs/add/operator/map';
@Interceptor()
export class TransformInterceptor implements NestInterceptor {
intercept(dataOrRequest, context: ExecutionContext, stream$: Observable<any>): Observable<any> {
return stream$.map((data) => ({ data }));
intercept(
dataOrRequest,
context: ExecutionContext,
stream$: Observable<any>,
): Observable<any> {
return stream$.map(data => ({ data }));
}
}
}

View File

@@ -1,26 +1,25 @@
import { PipeTransform, Pipe, ArgumentMetadata, HttpStatus } from '@nestjs/common';
import { PipeTransform, Pipe, ArgumentMetadata } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
import { WsException } from '@nestjs/websockets';
import { RpcException } from '@nestjs/microservices';
@Pipe()
export class ValidationPipe implements PipeTransform<any> {
async transform(value, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new RpcException('Validation failed');
}
async transform(value, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
private toValidate(metatype): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.find((type) => metatype === type);
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new RpcException('Validation failed');
}
}
return value;
}
private toValidate(metatype): boolean {
const types = [String, Boolean, Number, Array, Object];
return !types.find(type => metatype === type);
}
}

View File

@@ -1,5 +1,10 @@
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { ClientProxy, Client, Transport, MessagePattern } from '@nestjs/microservices';
import {
ClientProxy,
Client,
Transport,
MessagePattern,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { LoggingInterceptor } from '../common/interceptors/logging.interceptor';
@@ -20,4 +25,4 @@ export class MathController {
sum(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
}
}

View File

@@ -2,6 +2,6 @@ import { Module } from '@nestjs/common';
import { MathController } from './math.controller';
@Module({
controllers: [MathController],
controllers: [MathController],
})
export class MathModule {}
export class MathModule {}

View File

@@ -5,4 +5,4 @@ import { FeatureModule } from './feature/feature.module';
@Module({
modules: [FeatureModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -5,4 +5,4 @@ import { CommonService } from './common.service';
components: [CommonService],
exports: [CommonService],
})
export class CommonModule {}
export class CommonModule {}

View File

@@ -6,4 +6,4 @@ export class CommonService {
constructor(private readonly coreService: CoreService) {
console.log('CommonService', coreService);
}
}
}

View File

@@ -7,4 +7,4 @@ export class ContextService {
constructor(private readonly commonService: CoreService) {
console.log('ContextService', commonService);
}
}
}

View File

@@ -9,4 +9,4 @@ import { FeatureModule } from '../feature/feature.module';
components: [CoreService, ContextService],
exports: [CommonModule],
})
export class CoreModule {}
export class CoreModule {}

View File

@@ -5,4 +5,4 @@ export class CoreService {
constructor() {
console.log('CoreService');
}
}
}

View File

@@ -6,4 +6,4 @@ import { CoreModule } from '../core/core.module';
modules: [CoreModule],
components: [FeatureService],
})
export class FeatureModule {}
export class FeatureModule {}

View File

@@ -3,8 +3,7 @@ import { CommonService } from '../common/common.service';
@Component()
export class FeatureService {
constructor(
private readonly commonService: CommonService) {
constructor(private readonly commonService: CommonService) {
console.log('FeatureService', commonService);
}
}
}

View File

@@ -0,0 +1,10 @@
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "root",
"database": "test",
"entities": ["src/**/**.entity{.ts,.js}"],
"autoSchemaSync": true
}

View File

@@ -9,10 +9,11 @@
"start:prod": "node dist/server.js"
},
"dependencies": {
"@nestjs/common": "^4.3.0",
"@nestjs/core": "^4.3.0",
"@nestjs/common": "^4.5.0",
"@nestjs/core": "^4.5.0",
"@nestjs/microservices": "^4.3.0",
"@nestjs/testing": "^4.3.0",
"@nestjs/typeorm": "^1.0.0",
"@nestjs/websockets": "^4.3.0",
"mysql": "^2.14.1",
"redis": "^2.7.1",

View File

@@ -1,7 +1,10 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PhotoModule } from './photo/photo.module';
import { Photo } from './photo/photo.entity';
@Module({
modules: [PhotoModule],
modules: [TypeOrmModule.forRoot([Photo]), PhotoModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -1,8 +0,0 @@
import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';
@Module({
components: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}

View File

@@ -1,19 +0,0 @@
import { createConnection } from 'typeorm';
export const databaseProviders = [
{
provide: 'DbConnectionToken',
useFactory: async () => await createConnection({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [
__dirname + '/../**/**.entity{.ts,.js}',
],
autoSchemaSync: true,
}),
},
];

View File

@@ -0,0 +1,13 @@
import { Controller, Get } from '@nestjs/common';
import { PhotoService } from './photo.service';
import { Photo } from './photo.entity';
@Controller('photo')
export class PhotoController {
constructor(private readonly photoService: PhotoService) {}
@Get()
findAll(): Promise<Photo[]> {
return this.photoService.findAll();
}
}

View File

@@ -2,21 +2,16 @@ import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@PrimaryGeneratedColumn() id: number;
@Column({ length: 500 })
name: string;
@Column({ length: 500 })
name: string;
@Column('text')
description: string;
@Column('text') description: string;
@Column()
filename: string;
@Column() filename: string;
@Column('int')
views: number;
@Column('int') views: number;
@Column()
isPublished: boolean;
}
@Column() isPublished: boolean;
}

View File

@@ -1,13 +1,9 @@
import { Module } from '@nestjs/common';
import { DatabaseModule } from '../database/database.module';
import { photoProviders } from './photo.providers';
import { PhotoService } from './photo.service';
import { PhotoController } from './photo.controller';
@Module({
modules: [DatabaseModule],
components: [
...photoProviders,
PhotoService,
],
components: [PhotoService],
controllers: [PhotoController],
})
export class PhotoModule {}
export class PhotoModule {}

View File

@@ -1,10 +0,0 @@
import { Connection, Repository } from 'typeorm';
import { Photo } from './photo.entity';
export const photoProviders = [
{
provide: 'PhotoRepositoryToken',
useFactory: (connection: Connection) => connection.getRepository(Photo),
inject: ['DbConnectionToken'],
},
];

View File

@@ -1,13 +1,17 @@
import { Component, Inject } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Photo } from './photo.entity';
@Component()
export class PhotoService {
constructor(
@Inject('PhotoRepositoryToken') private readonly photoRepository: Repository<Photo>) {}
@InjectRepository(Photo)
private readonly photoRepository: Repository<Photo>,
) {}
async findAll(): Promise<Photo[]> {
return await this.photoRepository.find();
}
}
}

View File

@@ -12,6 +12,8 @@
true,
"single"
],
"ban-types": false,
"indent": false,
"ordered-imports": [
false
],

View File

@@ -4,4 +4,4 @@ import { CatsModule } from './cats/cats.module';
@Module({
modules: [CatsModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -16,4 +16,4 @@ export class CatsController {
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
}

View File

@@ -7,9 +7,6 @@ import { DatabaseModule } from '../database/database.module';
@Module({
modules: [DatabaseModule],
controllers: [CatsController],
components: [
CatsService,
...catsProviders,
],
components: [CatsService, ...catsProviders],
})
export class CatsModule {}
export class CatsModule {}

View File

@@ -7,4 +7,4 @@ export const catsProviders = [
useFactory: (connection: Connection) => connection.model('Cat', CatSchema),
inject: ['DbConnectionToken'],
},
];
];

View File

@@ -5,8 +5,7 @@ import { CreateCatDto } from './dto/create-cat.dto';
@Component()
export class CatsService {
constructor(
@Inject('CatModelToken') private readonly catModel: Model<Cat>) {}
constructor(@Inject('CatModelToken') private readonly catModel: Model<Cat>) {}
async create(createCatDto: CreateCatDto): Promise<Cat> {
const createdCat = new this.catModel(createCatDto);
@@ -16,4 +15,4 @@ export class CatsService {
async findAll(): Promise<Cat[]> {
return await this.catModel.find().exec();
}
}
}

View File

@@ -2,4 +2,4 @@ export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}
}

View File

@@ -4,4 +4,4 @@ export interface Cat extends Document {
readonly name: string;
readonly age: number;
readonly breed: string;
}
}

View File

@@ -4,4 +4,4 @@ export const CatSchema = new mongoose.Schema({
name: String,
age: Number,
breed: String,
});
});

View File

@@ -5,4 +5,4 @@ import { databaseProviders } from './database.providers';
components: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}
export class DatabaseModule {}

View File

@@ -10,4 +10,4 @@ export const databaseProviders = [
});
},
},
];
];

View File

@@ -18,9 +18,9 @@
"redis": "^2.7.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.4.3",
"sequelize": "^4.12.0",
"sequelize-typescript": "^0.5.0",
"typescript": "^2.4.2"
"sequelize": "^4.28.0",
"sequelize-typescript": "^0.6.1",
"typescript": "^2.6.2"
},
"devDependencies": {
"@types/node": "^7.0.41",

View File

@@ -4,4 +4,4 @@ import { CatsModule } from './cats/cats.module';
@Module({
modules: [CatsModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -2,12 +2,9 @@ import { Table, Column, Model } from 'sequelize-typescript';
@Table
export class Cat extends Model<Cat> {
@Column
name: string;
@Column name: string;
@Column
age: number;
@Column age: number;
@Column
breed: string;
@Column breed: string;
}

View File

@@ -16,4 +16,4 @@ export class CatsController {
async findAll(): Promise<Cat[]> {
return await this.catsService.findAll();
}
}
}

View File

@@ -7,9 +7,6 @@ import { DatabaseModule } from '../database/database.module';
@Module({
modules: [DatabaseModule],
controllers: [CatsController],
components: [
CatsService,
...catsProviders,
],
components: [CatsService, ...catsProviders],
})
export class CatsModule {}
export class CatsModule {}

View File

@@ -5,4 +5,4 @@ export const catsProviders = [
provide: 'CatsRepository',
useValue: Cat,
},
];
];

View File

@@ -1,4 +1,3 @@
import { Component, Inject } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { Model } from 'sequelize-typescript';
@@ -7,7 +6,8 @@ import { Cat } from './cat.entity';
@Component()
export class CatsService {
constructor(
@Inject('CatsRepository') private readonly catsRepository: typeof Model) {}
@Inject('CatsRepository') private readonly catsRepository: typeof Cat,
) {}
async create(createCatDto: CreateCatDto): Promise<Cat> {
const cat = new Cat();
@@ -21,4 +21,4 @@ export class CatsService {
async findAll(): Promise<Cat[]> {
return await this.catsRepository.findAll<Cat>();
}
}
}

View File

@@ -2,4 +2,4 @@ export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}
}

View File

@@ -5,4 +5,4 @@ import { databaseProviders } from './database.providers';
components: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}
export class DatabaseModule {}

View File

@@ -18,4 +18,4 @@ export const databaseProviders = [
return sequelize;
},
},
];
];

View File

@@ -4,4 +4,4 @@ import { AuthModule } from './auth/auth.module';
@Module({
modules: [AuthModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -10,10 +10,7 @@ import { JwtStrategy } from './passport/jwt.strategy';
import { AuthController } from './auth.controller';
@Module({
components: [
AuthService,
JwtStrategy,
],
components: [AuthService, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule implements NestModule {

View File

@@ -4,7 +4,8 @@ import { Component, Inject } from '@nestjs/common';
@Component()
export class AuthService {
async createToken() {
const expiresIn = 60 * 60, secretOrKey = 'secret';
const expiresIn = 60 * 60,
secretOrKey = 'secret';
const user = { email: 'thisis@example.com' };
const token = jwt.sign(user, secretOrKey, { expiresIn });
return {

View File

@@ -12,7 +12,7 @@ export class JwtStrategy extends Strategy {
passReqToCallback: true,
secretOrKey: 'secret',
},
async (req, payload, next) => await this.verify(req, payload, next)
async (req, payload, next) => await this.verify(req, payload, next),
);
passport.use(this);
}

View File

@@ -5,42 +5,40 @@ import { Test } from '@nestjs/testing';
import { CatsModule } from '../../src/modules/cats/cats.module';
describe('Cats', () => {
const server = express();
server.use(bodyParser.json());
const server = express();
server.use(bodyParser.json());
beforeAll(async () => {
const module = await Test.createTestingModule({
modules: [CatsModule],
})
.compile();
beforeAll(async () => {
const module = await Test.createTestingModule({
modules: [CatsModule],
}).compile();
const app = module.createNestApplication(server);
await app.init();
});
const app = module.createNestApplication(server);
await app.init();
});
it(`/POST insert cat`, () => {
return request(server)
.post('/cats')
.send({
name: 'Tiger',
age: 2,
breed: 'Russian Blue'
})
.expect(201);
});
it(`/POST insert cat`, () => {
return request(server)
.post('/cats')
.send({
name: 'Tiger',
age: 2,
breed: 'Russian Blue',
})
.expect(201);
});
it(`/GET cats`, async (done) => {
it(`/GET cats`, async done => {
const cats = await request(server)
.get('/cats')
.expect(200);
const cats = await request(server)
.get('/cats')
.expect(200);
const [cat] = cats.body;
const [cat] = cats.body;
expect(cat.name).toBe('Tiger');
expect(cat.age).toBe(2);
expect(cat.breed).toBe('Russian Blue');
expect(cat.name).toBe('Tiger');
expect(cat.age).toBe(2);
expect(cat.breed).toBe('Russian Blue');
done();
});
});
done();
});
});

View File

@@ -4,4 +4,4 @@ import { CatsModule } from './cats/cats.module';
@Module({
modules: [CatsModule],
})
export class ApplicationModule {}
export class ApplicationModule {}

View File

@@ -16,4 +16,4 @@ export class CatsController {
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
}

View File

@@ -7,9 +7,6 @@ import { DatabaseModule } from '../database/database.module';
@Module({
modules: [DatabaseModule],
controllers: [CatsController],
components: [
CatsService,
...catsProviders,
],
components: [CatsService, ...catsProviders],
})
export class CatsModule {}
export class CatsModule {}

View File

@@ -4,7 +4,7 @@ import { CatSchema } from './schemas/cat.schema';
export const catsProviders = [
{
provide: 'CatModelToken',
useFactory: (mongoose) => mongoose.connection.model('Cat', CatSchema),
useFactory: mongoose => mongoose.connection.model('Cat', CatSchema),
inject: ['DbToken'],
},
];
];

View File

@@ -5,8 +5,7 @@ import { CreateCatDto } from './dto/create-cat.dto';
@Component()
export class CatsService {
constructor(
@Inject('CatModelToken') private readonly catModel: Model<Cat>) {}
constructor(@Inject('CatModelToken') private readonly catModel: Model<Cat>) {}
async create(createCatDto: CreateCatDto): Promise<Cat> {
const createdCat = new this.catModel(createCatDto);
@@ -16,4 +15,4 @@ export class CatsService {
async findAll(): Promise<Cat[]> {
return await this.catModel.find().exec();
}
}
}

View File

@@ -2,4 +2,4 @@ export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}
}

View File

@@ -4,4 +4,4 @@ export interface Cat extends Document {
readonly name: string;
readonly age: number;
readonly breed: string;
}
}

View File

@@ -4,4 +4,4 @@ export const CatSchema = new mongoose.Schema({
name: String,
age: Number,
breed: String,
});
});

Some files were not shown because too many files have changed in this diff Show More