Skip to content

feat: add support for wildcard "all" routes #536

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

Merged
merged 3 commits into from
Jul 21, 2020
Merged
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
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ There are set of prepared errors you can use:
* UnauthorizedError


You can also create and use your own errors by extending `HttpError` class.
You can also create and use your own errors by extending `HttpError` class.
To define the data returned to the client, you could define a toJSON method in your error.

```typescript
Expand All @@ -755,7 +755,7 @@ class DbError extends HttpError {
}
}
}
```
```

#### Enable CORS

Expand Down Expand Up @@ -796,7 +796,7 @@ app.listen(3000);

#### Default settings

You can override default status code in routing-controllers options.
You can override default status code in routing-controllers options.

```typescript
import "reflect-metadata";
Expand All @@ -809,9 +809,9 @@ const app = createExpressServer({
//with this option, null will return 404 by default
nullResultCode: 404,

//with this option, void or Promise<void> will return 204 by default
//with this option, void or Promise<void> will return 204 by default
undefinedResultCode: 204,

paramOptions: {
//with this option, argument will be required by default
required: true
Expand Down Expand Up @@ -1486,7 +1486,8 @@ export class QuestionController {
| `@Patch(route: string\|RegExp)` | `@Patch("/users/:id") patch()` | Methods marked with this decorator will register a request made with PATCH HTTP Method to a given route. In action options you can specify if action should response json or regular text response. | `app.patch("/users/:id", patch)` |
| `@Delete(route: string\|RegExp)` | `@Delete("/users/:id") delete()` | Methods marked with this decorator will register a request made with DELETE HTTP Method to a given route. In action options you can specify if action should response json or regular text response. | `app.delete("/users/:id", delete)` |
| `@Head(route: string\|RegExp)` | `@Head("/users/:id") head()` | Methods marked with this decorator will register a request made with HEAD HTTP Method to a given route. In action options you can specify if action should response json or regular text response. | `app.head("/users/:id", head)` |
| `@Method(methodName: string, route: string\|RegExp)` | `@Method("move", "/users/:id") move()` | Methods marked with this decorator will register a request made with given `methodName` HTTP Method to a given route. In action options you can specify if action should response json or regular text response. | `app.move("/users/:id", move)` |
| `@All(route: string\|RegExp)` | `@All("/users/me") rewrite()` | Methods marked with this decorator will register a request made with any HTTP Method to a given route. In action options you can specify if action should response json or regular text response. | `app.all("/users/me", rewrite)` |
| `@Method(methodName: string, route: string\|RegExp)` | `@Method("move", "/users/:id") move()` | Methods marked with this decorator will register a request made with given `methodName` HTTP Method to a given route. In action options you can specify if action should response json or regular text response. | `app.move("/users/:id", move)` |

#### Method Parameter Decorators

Expand Down
28 changes: 28 additions & 0 deletions src/decorator/All.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {getMetadataArgsStorage} from "../index";

/**
* Registers an action to be executed when a request comes on a given route.
* Must be applied on a controller action.
*/
export function All(route?: RegExp): Function;

/**
* Registers an action to be executed when a request comes on a given route.
* Must be applied on a controller action.
*/
export function All(route?: string): Function;

/**
* Registers an action to be executed when a request comes on a given route.
* Must be applied on a controller action.
*/
export function All(route?: string|RegExp): Function {
return function (object: Object, methodName: string) {
getMetadataArgsStorage().actions.push({
type: "all",
target: object.constructor,
method: methodName,
route: route
});
};
}
4 changes: 2 additions & 2 deletions src/driver/express/ExpressDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export class ExpressDriver extends BaseDriver {
// This causes a double action execution on our side, which results in an unhandled rejection,
// saying: "Can't set headers after they are sent".
// The following line skips action processing when the request method does not match the action method.
if (request.method.toLowerCase() !== actionMetadata.type)
if (actionMetadata.type !== "all" && request.method.toLowerCase() !== actionMetadata.type)
return next();

return executeCallback({request, response, next});
Expand Down Expand Up @@ -207,7 +207,7 @@ export class ExpressDriver extends BaseDriver {

case "session-param":
return request.session[param.name];

case "session":
return request.session;

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {importClassesFromDirectories} from "./util/importClassesFromDirectories"

export * from "./container";

export * from "./decorator/All";
export * from "./decorator/Authorized";
export * from "./decorator/Body";
export * from "./decorator/BodyParam";
Expand Down
5 changes: 3 additions & 2 deletions src/metadata/types/ActionType.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* Controller action type.
*/
export type ActionType = "checkout"
export type ActionType = "all"
|"checkout"
|"connect"
|"copy"
|"delete"
Expand All @@ -26,4 +27,4 @@ export type ActionType = "checkout"
|"subscribe"
|"trace"
|"unlock"
|"unsubscribe";
|"unsubscribe";
18 changes: 18 additions & 0 deletions test/functional/controller-methods.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Head} from "../../src/decorator/Head";
import {Delete} from "../../src/decorator/Delete";
import {Patch} from "../../src/decorator/Patch";
import {Put} from "../../src/decorator/Put";
import {All} from "../../src/decorator/All";
import {ContentType} from "../../src/decorator/ContentType";
import {JsonController} from "../../src/decorator/JsonController";
import {UnauthorizedError} from "../../src/http-error/UnauthorizedError";
Expand Down Expand Up @@ -52,6 +53,10 @@ describe("controller methods", () => {
head() {
return "<html><body>Removing user</body></html>";
}
@All("/users/me")
all() {
return "<html><body>Current user</body></html>";
}
@Method("post", "/categories")
postCategories() {
return "<html><body>Posting categories</body></html>";
Expand Down Expand Up @@ -196,6 +201,19 @@ describe("controller methods", () => {
});
});

describe("all respond with proper status code, headers and body content", () => {
const callback = (response: any) => {
expect(response).to.have.status(200);
expect(response).to.have.header("content-type", "text/html; charset=utf-8");
expect(response.body).to.be.equal("<html><body>Current user</body></html>");
};

assertRequest([3001, 3002], "get", "users/me", callback);
assertRequest([3001, 3002], "put", "users/me", callback);
assertRequest([3001, 3002], "patch", "users/me", callback);
assertRequest([3001, 3002], "delete", "users/me", callback);
});

describe("custom method (post) respond with proper status code, headers and body content", () => {
assertRequest([3001, 3002], "post", "categories", response => {
expect(response).to.have.status(200);
Expand Down