# Declarative Events
5 April 2018
There is another abstraction in Node that must be considered. And this is the *events*.
*[ If you didn't read [previous article](https://guseyn.com/posts/async-objects-instead-of-async-calls?v=1.0.100), I would recommend read it first before moving on. ]*
Let's look at the most popular example in Node:
```js
http.createServer((request, response) => {
// send back a response every time you get a request
}).listen(8080, '127.0.0.1', () => {
console.log('server is listening on 127.0.0.1:8080')
})
```
Here method `createServer` uses *request listener* as argument, which actually works like an event: on every `request` it provides a `response`. Unlike simple async call, event is never finished and it's being invoked every time when it's needed.
It can be rewritten in the following declarative way:
```js
new LoggedListeningServer(
new ListeningServer(
new CreatedServer(
new RequestResponseEvent()
), 8080, '127.0.0.1'
), 'server is listening on 127.0.0.1:8080'
).call()
```
As you can see, `RequestResponseEvent` is a node of the async tree that represents request listener, but it's not a simple argument or async object. `RequestResponseEvent` implements `Event` interface and it needs to be treated in a special way, so it requires more flexibility of the whole system. But we also can create `Event` via `AsyncObject`.
Basically, `Event` is an interface that provides only one method: `body(...args)` that must be implemented by the extended classes. The main purpose of this interface is to replace functions of events(or listeners). `Event` is not an `AsyncObject`, but it represents function of some event. But you cannot use `AsyncObject` that represents some `Event` instead of the `Event`. In that case you can use `AsyncObject` that represents some function. Actually, you can use a function in the async composition instead of `Event`, but for readability it's better to use `Event`.
```js
class Event {
constructor () {}
// TO BE OVERRIDDEN
body (...args) {
throw new Error(`Method body must be overriden with arguments ${args} of the event/eventListener you call`)
}
}
```
**How to create an Event**
Let's say we have a `ReadStream` and we need to be able to attach an `'open'` event to it. So, we need to create an async object `ReadStreamWithOpenEvent` that represents `ReadStream` with attached `'open'` event.
```js
// Represented result is a ReadStream
class ReadStreamWithOpenEvent extends AsyncObject {
/*
event is an Event with body(fd)
*/
constructor ( readStream, event) {
super(readStream, event)
}
syncCall () {
return (readStream, event) => {
readStream.on('open', event)
return readStream
}
}
}
```
Actually `readStream` with `'open'` event has the following signature:
```js
readStream.on('open', (fd) => {
// here we work with fd
})
```
So, `OpenEvent` would be:
```js
class OpenEvent extends Event {
constructor () {
super ()
}
body (fd) {
// here we work with fd
}
}
```
As you can see `body` use the same arguments as the event of the `readStream`.
So, in the composition it would look something like this:
```js
new ReadStreamWithOpenEvent(
new CreatedSomeHowReadStream(), new OpenEvent()
).call()
```
The main problem of `Event` is that it cannot encapsulate async objects, because it's being replaced by corresponding function (which is actually `body()`) in a moment of construction of the async tree that contains this event. So, if you want use an event that can be constructed by async objects you can simply create `AsyncObject` that represents a function that is the `body` of the event:
```js
class OpenEvent extends AsyncObject {
constructor (...asyncObjects) {
super(...asyncObjects)
}
syncCall () {
return (...resultsFromAsyncObjects) => {
// This is body of the event
return (fd) => {
/* now you can use here not only fd but also
...resultsFromAsyncObjects */
}
}
}
}
```
And now the composition of objects would look something like this:
```js
new ReadStreamWithOpenEvent(
new CreatedSomeHowReadStream(),
new OpenEvent(
new SomeAsyncParameter()
)
).call()
```
**Updates:** you can create `Event` via [`Created`](https://github.com/Guseyn/cutie-created) async object, it will allow to encapsulate data from async objects inside of `Event`.
References
* [Cutie on GitHub](https://github.com/Guseyn/cutie)