npm install volcano-express-cli -g
To create all the files and import all the dependencies needed for a new project, simply use the init command from the CLI.
The init command will create all the files needed to get started.
volcano --init
You can find more informations on the CLI commands on the Volcano-express CLI npm package page.
To start the server, use the npm start command.
By default, the server starts at port 3000.
npm start
If the server starts with no error, it outputs a success message in the console :
Server started at port 3000
Once you have started the server, you should be able to test it with an http request at :
GET/ http://localhost:3000/demo
You should receive a 200 OK response with the following content if everything is working properly :
"Demo"
There are multiples ways to register your services to inject them into your controllers or other services :
- Using the @Injectable decorator :
@Injectable(CarRepository)
export class InMemoryCarRepository {
...
}
- Using service registering the main file :
const server = Volcano.createServer({
controllers : [...],
middlewares: [...],
services: [
{ interface: CarRepository, use: InMemoryCarRepository }
]
});
- Using the ServiceLocator register method to register the service directly :
ServiceLocator.register(CarRepository, InMemoryCarRepository);
A few way are available to inject the registered services into your controllers or others services.
- You can use the @Inject decorator :
@Inject(CarRepository) private carRepository: CarRepository;
- You can also call the ServiceLocator resolve method to get a service instance directly :
private carRepository: CarRepository = ServiceLocator.resolve(CarRepository);
@Controller()
export class CarController extends HttpController {}
The following http actions are supported by the HttpController :
- GET
- POST
- PUT
- DELETE
@Controller()
export class CarController extends HttpController {
@GET('cars')
getCars(): Result { ... }
@POST('cars')
addCar(car: Car): Result { ... }
@PUT('cars/:id')
updateCar(id: string, car: Car): Result { ... }
@DELETE('cars/:id')
deleteCar(id: string): Result { ... }
}
The parameters of an HttpAction decorated method must be in this given order : The parameters from the route (i.e.: id in '/cars/:id) must be first, in appearing order. The body will always be the last parameter of a signature. GET decorated method cannot have a body.
@Controller()
export class CarController extends HttpController {
@PUT('cars/:id')
updateCar(id: string, car: Car): Result {
...
}
}
In the above example, id is the first parameter because it comes from the route. The last parameter (car) is the request body.
The Result that must be returned by an HttpAction needs an HttpStatusCode. The content is optional.
The following types are the ones available by default :
- JsonResult : Returns JSON response
- TextResult : Returns TEXT response
- HtmlResult : Returns HTML response
- XmlResult : Returns XML response
@Controller()
export class CarController extends HttpController {
@GET('cars')
getCars(): Result {
const cars = ...
return new JsonResult(HttpStatusCode.OK, cars);
}
}
You can also extend the Result class to implement a custom return type:
export class CustomResult extends Result {
sendWith(response: Response): void {
response.status(this.statusCode).send(...)
}
}
Middlewares are used to intercept requests before an HttpAction from a HttpController is called.
You can add middlewares to a controller or a specific route to intercept requests.
When a request is intercepted, you have access to the actuals express request and response.
You can create a middleware by extending the HttpMiddleware class :
export class Logger extends HttpMiddleware {
intercept(request: Request, response: Response): boolean {
console.log('I am interceptor');
return true;
}
}
When you add a middleware on a controller, it will apply the middleware for all the routes of that controller :
@Middleware(Logger) // <-- Added a middleware to all the routes
@Controller()
export class PingController extends HttpController {
...
}
You can also add it on specific routes :
@Controller()
export class PingController extends HttpController {
@GET('ping', [Logger]) // <-- Added a middleware to this specific route
ping(): JsonResult {
...
}
}
When you have multiple middlewares applied to a controller or route, they will always apply in order of appearance in the method signature :
@GET('ping', [Logger, Guard]) // <-- Logger will be first, Guard will be second
ping(): JsonResult {
...
}
When you have middlewares on the controller and on a route, the middlewares from the controller will be applied first :
@Middleware(Logger) // <-- Logger will be first
@Controller()
export class PingController extends HttpController {
@GET('ping', [Guard]) // <-- Guard will be second
ping(): JsonResult {
...
}
}
The following websocket actions are supported by the WebsocketController :
- OnConnect
- OnDisconnect
- OnMessage
@WebsocketController()
export class ChatController extends WsController {
@OnConnect()
onConnect(websocket: Websocket, server: Server): WebsocketResponse { ... }
@OnDisconnect()
onDisconnect(websocket: Websocket, server: Server) : WebsocketResponse { ... }
@On('message')
onSendMessage(message: string, websocket: Websocket, server: Server) : WebsocketResponse { ... }
}
The parameters of a WebsocketAction decorated method must be in this given order :
- OnConnect and OnDisconnect : The OnConnect and OnDisconnect have both access to the websocket instance and the server instance in that given order.
@OnConnect()
onConnect(websocket: Websocket, server: Server): WebsocketResponse { ... }
@OnDisconnect()
onDisconnect(websocket: Websocket, server: Server) : WebsocketResponse { ... }
- OnMessage : The OnMessage method has as first parameter the body of the message. The OnMessage have also access to the websocket instance and the server instance in that given order as the last two (2) parameters of the signature.
@On('message')
onSendMessage(message: string, websocket: Websocket, server: Server) : WebsocketResponse { ... }
The WebsocketResponse that must be returned by WebsocketAction need a content.
You can specify which clients to send the response to with the broadcast property or the receivers list.
The following types are the ones available by default :
- JsonWebsocketResponse : Returns JSON response
- TextWebsocketResponse : Returns TEXT response
- XmlWebsocketResponse : Returns XML response
For example, a JsonWebsocketResponse return would look like this :
@OnConnect()
onConnect(websocket: Websocket, server: Server): WebsocketResponse {
const sessionId = ...
return new JsonWebsocketResponse({sessionId, event: "Has come online"}, broadcast: true);
}
This would send a message to all the connected clients which says that someone has just come online :
{
"sessionId" : "...",
"event" : "Has come online"
}
You can also extend the WebsocketResponse class to implement a custom return type:
export class CustomWebsocketResponse extends WebsocketResponse {
sendWith(server: Server, websocket: Websocket) {
const content = ...
this.send(server, websocket, content);
}
}
Middlewares are used to intercept requests before an WebsocketAction from a WebsocketController is called.
You can add middlewares to a controller or a specific action to intercept requests.
You can create a middleware by extending the WebsocketMiddleware class :
export class Logger extends HttpMiddleware {
intercept(request: Request, response: Response): boolean {
console.log('I am interceptor');
return true;
}
}
When you add a middleware on a controller, it will apply the middleware for all the actions of that controller :
@Middleware(Logger) // <-- Added a middleware to all the routes
@WebsocketController()
export class ChatController extends WsController {
...
}
You can also add it on specific action :
@WebsocketController()
export class ChatController extends WsController {
@OnConnect([Logger]) // <-- Added a middleware to this specific action
onConnect(websocket: Websocket, server: Server): WebsocketResponse {
...
}
}
Look at the Http middlewares order section for how the middlewares order works.