Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1 #38

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

V1 #38

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/dist
/types
package-lock.json

# Logs
Expand Down
21 changes: 4 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
{
"name": "tachijs",
"version": "0.15.1",
"version": "1.0.0-2",
"description": "Highly testable dead simple web server written in Typescript",
"main": "dist",
"types": "types",
"files": [
"dist/**/*",
"!dist/examples/**/*",
"!dist/specs/**/*",
"types/**/*",
"!types/examples/**/*",
"!types/specs/**/*",
"src/**/*",
"!src/examples/**/*",
"!src/specs/**/*"
"!dist/specs/**/*"
],
"scripts": {
"dev": "nodemon",
"build": "rimraf dist types && tsc",
"build": "rimraf dist && tsc",
"format": "prettier --write 'src/**/*.ts'",
"lint": "npm run lint:prettier && npm run lint:tslint",
"lint:prettier": "prettier --check 'src/**/*.ts'",
Expand Down Expand Up @@ -58,7 +51,7 @@
"nodemon": "^1.18.9",
"prettier": "^1.16.4",
"pug": "^2.0.3",
"reflect-metadata": "^0.1.12",
"reflect-metadata": "^0.1.13",
"rimraf": "^2.6.3",
"supertest": "^3.3.0",
"ts-jest": "^23.10.5",
Expand All @@ -68,12 +61,6 @@
"typescript": "^3.2.2"
},
"dependencies": {
"class-transformer": "^0.2.0",
"class-transformer-validator": "^0.6.0",
"class-validator": "^0.9.1",
"express": "^4.16.4"
},
"peerDependencies": {
"reflect-metadata": "^0.1.12"
}
}
130 changes: 57 additions & 73 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,16 @@ Luckily, TachiJS tackles those problems. If you have other ideas, please create
### Install tachijs

```sh
npm i tachijs reflect-metadata
npm i tachijs
```

Add two compiler options, `experimentalDecorators` and `emitDecoratorMetadata`, to `tsconfig.json`.
Enable `experimentalDecorators` of `compilerOptions` to `tsconfig.json`.

```json
{
"compilerOptions": {
...
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
...
}
}
Expand Down Expand Up @@ -77,9 +76,9 @@ Now you can access [http://localhost:8000/](http://localhost:8000/).

For other http methods, tachijs provides `@httpPost`, `@httpPut`, `@httpPatch`, `@httpDelete`, `@httpOptions`, `@httpHead` and `@httpAll`.

### Configuring express app(Middlewares)
### Configuring express app(Middleware)

There are lots of ways to implement express middlewares.
There are lots of ways to implement express middleware.

#### Use `before` and `after` options

Expand Down Expand Up @@ -146,9 +145,9 @@ app.use(errorHandler)
app.listen(8000)
```

#### Apply middlewares to controllers and methods
#### Apply middleware to controllers and methods

Sometimes, you might want to apply middlewares to several methods only.
Sometimes, you might want to apply middleware to several methods only.

```ts
import { controller, httpGet, ForbiddenException } from 'tachijs'
Expand Down Expand Up @@ -261,43 +260,7 @@ We also provide `reqHeaders`, `reqCookies` and `reqSession` for `req.headers`, `

#### Body validation

`@reqBody` supports validation via `class-validator`.

Please install `class-validator` package first.

```sh
npm install class-validator
```

```ts
import { IsString } from 'class-validator'

class PostDTO {
@IsString()
title: string

@IsString()
content: string
}


@controller('/posts')
class PostController() {
@httpPost('/')
// Tachijs can access `PostDTO` via reflect-metadata.
async create(@reqBody() body: PostDTO) {
// `body` is already validated and transformed into an instance of `PostDTO`.
// So we don't need any extra validation.
const post = await Post.create({
...body
})

return {
post
}
}
}
```
It has been deprecated from v1. We'll provide this feature as a separated module.

#### Custom parameter decorators!

Expand Down Expand Up @@ -355,27 +318,28 @@ export function cookieSetter() {
}
```

##### `design:paramtype`
##### `meta.paramType`

Moreover, tachijs exposes metadata of parameters to forth argument. So you can make your custom validator for query with `class-transformer-validator` like below. (`req.body` is also using this.)
If you are using `reflect-metadata`, tachijs exposes `paramType` to the forth argument, `meta`, of `handlerParam` from `design:paramtypes`. With this feature, you could access argument types on runtime. The below example is validating and transforming query with DTO class by class-validator.

```ts
import 'reflect-metadata'
import { controller, httpGet, handlerParam } from 'tachijs'
import { IsString } from 'class-validator'
import { transformAndValidate } from 'class-transformer-validator'

function validatedQuery() {
return handlerParam((req, res, next, meta) => {
// meta.paramType is from `design:paramtypes`.
// It is `Object` if the param type is unknown or any.
// Now tachijs will expose `paramType`.
// If the param type is unknown or any, paramType will become `Object`.
return meta.paramType !== Object
? transformAndValidate(meta.paramType, req.query)
: req.query
})
}

// Validator class
class SearchQuery {
class SearchQueryDTO {
@IsString()
title: string
}
Expand All @@ -384,10 +348,10 @@ class SearchQuery {
class PostController {
@httpGet('/search')
// Provide the validator class to param type.
// tachijs can access it via `reflect-metadata`.
search(@validatedQuery() query: SearchQuery) {
search(@validatedQuery() query: SearchQueryDTO) {
// Now `query` is type-safe
// because it has been validated and transformed into an instance of SearchQuery.
// because it has been validated and transformed into an instance of SearchQueryDTO.
// If validation errors happen, tachijs will pass the error into `next` so you can handle it easily by your error request handler.
const { title } = query

return {
Expand All @@ -397,6 +361,20 @@ class PostController {
}
```

To enable it, you have to install `reflect-metadata` and to apply `emitDecoratorMetadata` of `compilerOptions` to `tsconfig.json`.

```sh
npm i reflect-metadata
```

```json
{
"compilerOptions": {
"emitDecoratorMetadata": true
}
}
```

To know more, see `@handlerParam` api documentation below.

### Redirection, Rendering via pug and others...
Expand Down Expand Up @@ -513,8 +491,6 @@ class HomeController {
}
```

> `#httpContext`, `#inject` and `#injector` will be deprecated from v1.0.0. Please use `#context`

#### Customize result

If you want to have customized result behavior, you can do it with `BaseResult`.
Expand Down Expand Up @@ -804,38 +780,49 @@ type ConfigSetter = (app: express.Application) => void
```

- `app` Optional. If you provide this option, tachijs will use it rather than creating new one.
- `before` Optional. You can configure express app before registering controllers for applying middlewares.
- `before` Optional. You can configure express app before registering controllers for applying middleware.
- `after` Optional. You can configure express app before registering controllers for error handling.
- `controllers` Optional. Array of controller classes.
- `container` Optional. A place for registered services.
If you want to use DI, you have to register services to here first.

### `@controller(path: string, middlewares: RequestHandler[] = [], routerOptions: RouterOptions = {})`
### `@controller(path: string, middleware: MiddlewareParams | RequestHandler[] = {}, routerOptions: RouterOptions = {})`

It marks class as a controller.

- `path` Target path.
- `middlewares` Optional. Array of middlewares.
- `middleware` Optional. `MiddlewareParams` or Array of middleware.
If it provided as array, tachijs will set the middleware before controller method.
- `routerOptions` Optional. Express router options.

### `@httpMethod(method: string, path: string, middlewares: RequestHandler[] = [])`
#### `MiddlewareParams`

```ts
interface MiddlewareParams {
before?: RequestHandler[]
after?: RequestHandler[]
}
```

### `@httpMethod(method: string, path: string, middleware: MiddlewareParams | RequestHandler[] = {})`

It marks method as a request handler.

- `method` Target http methods, `'get'`, `'post'`, `'put'`, `'patch'`, `'delete'`, `'options'`, `'head'` or `'all'` are available. (`'all'` means any methods.)
- `path` Target path.
- `middlewares` Optional. Array of middlewares.
- `middleware` Optional. `MiddlewareParams` or Array of middleware.
If it provided as array, tachijs will set the middleware before controller method.

tachijs also provides shortcuts for `@httpMethod`.

- `@httpGet(path: string, middlewares: RequestHandler[] = [])`
- `@httpPost(path: string, middlewares: RequestHandler[] = [])`
- `@httpPut(path: string, middlewares: RequestHandler[] = [])`
- `@httpPatch(path: string, middlewares: RequestHandler[] = [])`
- `@httpDelete(path: string, middlewares: RequestHandler[] = [])`
- `@httpOptions(path: string, middlewares: RequestHandler[] = [])`
- `@httpHead(path: string, middlewares: RequestHandler[] = [])`
- `@httpAll(path: string, middlewares: RequestHandler[] = [])`
- `@httpGet(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpPost(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpPut(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpPatch(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpDelete(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpOptions(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpHead(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`
- `@httpAll(path: string, middleware: MiddlewareParams | RequestHandler[] = {})`

### `@handlerParam<T>(selector: HandlerParamSelector<T>)`

Expand All @@ -854,28 +841,25 @@ export type HandlerParamSelector<T> = (
interface HandlerParamMeta<T> {
index: number
selector: HandlerParamSelector<T>
paramType: any
paramType?: any
}
```

- `index` Number index of the parameter.
- `selector` Its selector.
- `paramType` metadata from `design:paramtypes`.

#### `@reqBody(validator?: any)`
#### `@reqBody()`

Inject `req.body`.

- `validator` Optional. A class with decorators of `class-validator`. tachijs will validate `req.body` with it and transform `req.body` into the validator class. If `validator` is not given but the parameter has a class validator as its param type, tachijs will use it via `reflect-metadata`.

```ts
import { controller, httpPost, reqBody } from 'tachijs'

@controller('/post')
class PostController {
@httpPost('/')
// Identically same to `create(@reqBody(PostDTO) post: PostDTO)`
create(@reqBody() post: PostDTO) {
create(@reqBody() post: any) {
...
}
}
Expand Down
Loading