What is Polka ?
Polka is an extremely minimal, highly performant Express.js alternative.
Installation.
npm i --save polka
Usage
Polka has similar patterns with ExpressJS in terms of routing and API calls.
Simple Example.
constpolka=require('polka');polka().get('/',(req,res)=>{res.end('Hello there !');}).listen(9000).then(_=>{console.log(`> Running on localhost:3000`);});
Polka's API
Polka has four (4) main API methods.
- Polka(options) - Returns an instance of polka.
- use(base, ..fn)
- parse(req)
- listen(port, hostname)
- handler(req, res, parsed)
Routing with Polka.
Routes are used to define how an application responds to varying HTTP methods and endpoints.
Basics
Each route is comprised of apath pattern, aHTTP method, and ahandler (aka, what you want to do).
In code, this looks like:
app.METHOD(pattern,handler);
wherein:
app
is an instance ofpolka
*method
is any valid HTTP method, lowercasedpattern
is a routing pattern (string)handler
is the function to execute whenpattern
is matched
Also, a single pathname (orpattern
) may be reused with multiple METHODs.
The following example demonstrates some simple routes.
constapp=polka();app.get('/',(req,res)=>{res.end('Hello world!');});app.get('/users',(req,res)=>{res.end('Get all users!');});app.post('/users',(req,res)=>{res.end('Create a new User!');});app.put('/users/:id',(req,res)=>{res.end(`Update User with ID of${req.params.id}`);});app.delete('/users/:id',(req,res)=>{res.end(`CY@ User${req.params.id}!`);});
Patterns
Unlike the very popularpath-to-regexp
, Polka uses string comparison to locate route matches. Whilefaster & more memory efficient, this does also prevent complex pattern matching.
However, have no fear! 💥 All the basic and most commonly used patterns are supported. You probably only ever used these patterns in the first place. 😉
See
comparison
for the list ofRegExp
-based patterns that Polka does not support.
The supported pattern types are:
- static (
/users
) - named parameters (
/users/:id
) - nested parameters (
/users/:id/books/:title
) - optional parameters (
/users/:id?/books/:title?
) - any match / wildcards (
/users/*
)
Parameters
Any named parameters included within your routepattern
will be automatically added to your incomingreq
object. All parameters will be found withinreq.params
under the same name they were given.
Important: Your parameter names should be unique, as shared names will overwrite each other!
app.get('/users/:id/books/:title',(req,res)=>{let{id,title}=req.params;res.end(`User:${id} && Book:${title}`);});
$curl /users/123/books/Narnia#=> User: 123 && Book: Narnia
Methods
Any valid HTTP method is supported! However, only the most common methods are used throughout this documentation for demo purposes.
Note: For a full list of valid METHODs, please seethis list.
Handlers
Request handlers accept the incomingClientRequest
and the formulatingServerResponse
.
Every route definition must contain a validhandler
function, or else an error will be thrown at runtime.
Important: You mustalways terminate a
ServerResponse
!
It's avery good practice toalways terminate your response (res.end
) inside a handler, even if you expect a middleware to do it for you. In the event a response is/was not terminated, the server will hang & eventually exit with aTIMEOUT
error.
Note: This is a native
http
behavior.
Async Handlers
If using Node 7.4 or later, you may leverage nativeasync
andawait
syntax! 😻
No special preparation is needed — simply add the appropriate keywords.
constapp=polka();constsleep=ms=>newPromise(r=>setTimeout(r,ms));asyncfunctionauthenticate(req,res,next){lettoken=req.getHeader('authorization');if(!token)returnapp.send(res,401);req.user=awaitUsers.find(token);// <== fakenext();// done, woot!}app.use(authenticate).get('/',async(req,res)=>{// log middleware's findingsconsole.log('~> current user',req.user);// force sleep, because we can~!awaitsleep(500);// send greetingres.end(`Hello,${req.user.name}`);});
Middleware
Middleware are functions that run in between (hence "middle") receiving the request & executing your route'shandler
response.
Coming from Express? Use any middleware you already know & love! 🎉
The middleware signature receives the request (req
), the response (res
), and a callback (next
).
These can apply mutations to thereq
andres
objects, and unlike Express, have access toreq.params
,req.pathname
,req.search
, andreq.query
!
Most importantly, a middlewaremust either callnext()
or terminate the response (res.end
). Failure to do this will result in a never-ending response, which will eventually crash thehttp.Server
.
// Log every requestfunctionlogger(req,res,next){console.log(`~> Received${req.method} on${req.url}`);next();// move on}functionauthorize(req,res,next){// mutate req; available laterreq.token=req.getHeader('authorization');req.token?next():((res.statusCode=401)&&res.end('No token!'));}polka().use(logger,authorize).get('*',(req,res)=>{console.log(`~> user token:${req.token}`);res.end('Hello, valid user');});
$curl /# ~> Received GET on /#=> (401) No token!$curl-H"authorization: secret" /foobar# ~> Received GET on /foobar# ~> user token: secret#=> (200) Hello, valid user
In Polka, middleware functions are mounted globally, which means that they'll run on every request. Instead, you'll have to apply internal filters to determine when & where your middleware should run.
Note: This might change in Polka 1.0 🤔
functionfoobar(req,res,next){if(req.pathname.startsWith('/users')){// do something magical}next();}
Middleware Errors
If an error arises within a middleware, the loop will be exited. This means that no other middleware will execute & neither will the route handler.
Similarly, regardless ofstatusCode
, an early response termination will also exit the loop & prevent the route handler from running.
There are three ways to "throw" an error from within a middleware function.
Hint: None of them use
throw
*Pass any string to
next()
*This will exit the loop & send a
500
status code, with your error string as the response body.
polka().use((req,res,next)=>next('💩')).get('*',(req,res)=>res.end('wont run'));
$curl /#=> (500)
Pass an
Error
tonext()
This is similar to the above option, but gives you a window in changing the
statusCode
to something other than the500
default.
functionoopsies(req,res,next){leterr=newError('Try again');err.code=422;next(err);}
$curl /#=> (422) Try again
Terminate the response early
Once the response has been ended, there's no reason to continue the loop!
This approach is the most versatile as it allows to control every aspect of the outgoing
res
.
functionoopsies(req,res,next){if(true){// something bad happened~res.writeHead(400,{'Content-Type':'application/json','X-Error-Code':'Please dont do this IRL'});letjson=JSON.stringify({error:'Missing CSRF token'});res.end(json);}else{next();// never called FYI}}
$curl /#=> (400) {"error":"Missing CSRF token"}
Benchmarks
A round of Polka-vs-Express benchmarks across varying Node versions can befound here.
Important: Time is mostly spent inyour application code rather than Express or Polka code! Switching from Express to Polka will (likely) not show such drastic performance gains.
Node 8.9.0Native Thread Stats Avg Stdev Max +/- Stdev Latency 2.24ms 112.34us 5.57ms 92.15% Req/Sec 5.38k 99.48 5.57k 81.81% 432562 requests in 10.10s, 42.90MB read Requests/sec: 42815.14 Transfer/sec: 4.25MBPolka Thread Stats Avg Stdev Max +/- Stdev Latency 2.26ms 115.55us 5.19ms 87.16% Req/Sec 5.32k 97.34 5.55k 72.77% 428208 requests in 10.10s, 42.47MB read Requests/sec: 42388.92 Transfer/sec: 4.20MBExpress Thread Stats Avg Stdev Max +/- Stdev Latency 5.15ms 421.69us 8.51ms 77.95% Req/Sec 2.34k 77.06 2.55k 72.12% 186390 requests in 10.01s, 36.97MB read Requests/sec: 18628.36 Transfer/sec: 3.70MBFastify Thread Stats Avg Stdev Max +/- Stdev Latency 2.91ms 201.13us 7.51ms 58.07% Req/Sec 4.14k 130.04 4.48k 65.59% 333158 requests in 10.10s, 41.30MB read Requests/sec: 32979.84 Transfer/sec: 4.09MBKoa Thread Stats Avg Stdev Max +/- Stdev Latency 3.43ms 369.96us 8.67ms 87.30% Req/Sec 3.51k 114.78 4.12k 69.76% 281808 requests in 10.10s, 38.97MB read Requests/sec: 27892.99 Transfer/sec: 3.86MB
Comparisons
Polka's API aims to bevery similar to Express since most Node.js developers are already familiar with it. If you know Express, you already know Polka! 💃
There are, however, a few main differences. Polka does not support or offer:
1)Any built-in view/rendering engines.
Most templating engines can be incorporated into middleware functions or used directly within a route handler.
2)The ability tothrow
from within middleware.
However, all other forms of middleware-errors are supported.( see middleware options)
functionmiddleware(res,res,next){// pass an error message to next()next('uh oh');// pass an Error to next()next(newError('🙀'));// send an early, customized error responseres.statusCode=401;res.end('Who are you?');}
3)Express-like response helpers... yet! (#14)
Express has a nice set ofresponse helpers. While Polka relies on thenative Node.js response methods, it would be very easy/possible to attach a global middleware that contained a similar set of helpers. (TODO)
4)RegExp
-based route patterns.
Polka's router uses string comparison to match paths against patterns. It's a lot quicker & more efficient.
The following routing patternsare not supported:
app.get('/ab?cd',_=>{});app.get('/ab+cd',_=>{});app.get('/ab*cd',_=>{});app.get('/ab(cd)?e',_=>{});app.get(/a/,_=>{});app.get(/.*fly$/,_=>{});
The following routing patternsare supported:
app.get('/users',_=>{});app.get('/users/:id',_=>{});app.get('/users/:id?',_=>{});app.get('/users/:id/books/:title',_=>{});app.get('/users/*',_=>{});
Credits.
All credits goes toLuke Edwards for his awesome works.
Top comments(4)

- LocationDelhi, India
- WorkFullstack Web Developer at Codeword Tech
- Joined
However, have no fear! 💥
- were you trying emojis like in GitHub

Oh Yeah ! Silly me

- LocationTampa, Florida, US
- EducationCS50 Web
- WorkSoftware Engineer, UI/UX Designer at Ashley Furniture
- Joined
Great! Thanks
For further actions, you may consider blocking this person and/orreporting abuse