You can think of Web application requests as a pipeline. A pipeline is composed of pipes, and you can very easily add new pipes to your pipeline every time you think that's appropriate.
Now imagine that every pipe you add to your pipeline were capable of doing something special with the fluid flowing through the pipeline. For instance, if water were the fluid flowing through the pipeline, you could add a pipe that filters any dirt and impurities, then you could add a pipe that heats the water to 80C, then you could add a pipe that adds powder milk to the water, and then add another pipe that adds powder chocolate to it and at the end of the pipeline you get chocolate milk.
Well, imagine the same thing, but as you go, the fluid is your http request, and you can do all kinds of things to your request in every pipe (i.e. middleware) that you add to your pipeline, in such a way that the next pipe will get a modified/improved request. And as you go, you can gradually build your http response, which is what you would expect to emerge at the other side of the pipeline.
For instance, the body of your request may come encrypted, so you may add a decryption pipe to your pipeline such that the next pipes in your pipeline can work with a decrypted request. Other pipes can look for query parameters and put them in a hash, other can look for form parameters and do the same, other could extract header values, what about one to deal with cookies?, etc, etc, etc.
So, you can see you can easily add more and more pipes to your pipeline, every one doing something else the previous one did not do. And as you go you improve the request with more and more information and that helps you to eventually build a response to send back to the client.
Some of these pipes can be used to reject the request, for instance, in a REST API you could add a pipe at the beginning that checks the API key sent in the request, and if invalid, immediately discards the request, and otherwise sends the request down the pipeline.
So you can see some pipes work as filters which decide which requests must be handled and which should be discarded or terminated. Other pipes may act as transformers that change the request by adding more data to it or changing data in it and then pass it to the next pipe in the pipeline. Some pipes are routers, that is a pipe with a single entry point but with many exit points; this type of pipe can send the request through a different pipeline depending on its contents (i.e. path, content-type, accepted languages, etc, etc.). Finally, some pipes are terminals, which means when you reach them you are at the end of the pipeline and you are supposed to provide a response there, whether successful or not.
Many web frameworks work this way, not only Koa. Koa is being developed by the same creators of Express, and this latter works in a similar way, so it's only natural they reused the best ideas from Expeess in Koa. However frameworks of earlier days like Java Servlets can work in similar way using a concept called filters. So, this is not new, just probably the terminology.