# cacheable-lookup
> A cacheable [`dns.lookup(…)`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) that respects TTL :tada:
[![Build Status](https://travis-ci.org/szmarczak/cacheable-lookup.svg?branch=master)](https://travis-ci.org/szmarczak/cacheable-lookup)
[![Coverage Status](https://coveralls.io/repos/github/szmarczak/cacheable-lookup/badge.svg?branch=master)](https://coveralls.io/github/szmarczak/cacheable-lookup?branch=master)
[![npm](https://img.shields.io/npm/dm/cacheable-lookup.svg)](https://www.npmjs.com/package/cacheable-lookup)
[![install size](https://packagephobia.now.sh/badge?p=cacheable-lookup)](https://packagephobia.now.sh/result?p=cacheable-lookup)
Making lots of HTTP requests? You can save some time by caching DNS lookups :zap:
## Usage
### Using the `lookup` option
```js
const http = require('http');
const CacheableLookup = require('cacheable-lookup');
const cacheable = new CacheableLookup();
http.get('https://example.com', {lookup: cacheable.lookup}, response => {
// Handle the response here
});
```
### Attaching CacheableLookup to an Agent
```js
const http = require('http');
const CacheableLookup = require('cacheable-lookup');
const cacheable = new CacheableLookup();
cacheable.install(http.globalAgent);
http.get('https://example.com', response => {
// Handle the response here
});
```
## API
### new CacheableLookup(options)
Returns a new instance of `CacheableLookup`.
#### options
Type: `Object`
Default: `{}`
Options used to cache the DNS lookups.
##### options.cacheAdapter
Type: [Keyv adapter instance](https://github.com/lukechilds/keyv)
Default: `new Map()`
A Keyv adapter which stores the cache.
##### options.maxTtl
Type: `number`
Default: `Infinity`
Limits the cache time (TTL in seconds).
If set to `0`, it will make a new DNS query each time.
##### options.resolver
Type: `Function`
Default: [`new dns.Resolver()`](https://nodejs.org/api/dns.html#dns_class_dns_resolver)
An instance of [DNS Resolver](https://nodejs.org/api/dns.html#dns_class_dns_resolver) used to make DNS queries.
### Entry object
Type: `Object`
#### address
Type: `string`
The IP address (can be an IPv4 or IPv6 address).
#### family
Type: `number`
The IP family (`4` or `6`).
##### expires
Type: `number`
**Note**: This is not present when using the native `dns.lookup(...)`!
The timestamp (`Date.now() + ttl * 1000`) when the entry expires.
#### ttl
**Note**: This is not present when using the native `dns.lookup(...)`!
The time in seconds for its lifetime.
### Entry object (callback-style)
When `options.all` is `false`, then `callback(error, address, family, expires, ttl)` is called.
When `options.all` is `true`, then `callback(error, entries)` is called.
### CacheableLookup instance
#### servers
Type: `Array`
DNS servers used to make the query. Can be overridden - then the new servers will be used.
#### [lookup(hostname, options, callback)](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback)
#### lookupAsync(hostname, options)
The asynchronous version of `dns.lookup(…)`.
Returns an [entry object](#entry-object).
If `options.all` is true, returns an array of entry objects.
**Note**: If entry(ies) were not found, it will return `undefined`.
##### hostname
Type: `string`
##### options
Type: `Object`
The same as the [`dns.lookup(…)`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) options.
##### options.throwNotFound
Type: `boolean`
Default: `false`
Throw when there's no match.
If set to `false` and it gets no match, it will return `undefined`.
**Note**: This option is meant **only** for the asynchronous implementation! The synchronous version will always give an error if no match found.
#### query(hostname, family)
An asynchronous function which returns cached DNS lookup entries. This is the base for `lookupAsync(hostname, options)` and `lookup(hostname, options, callback)`.
**Note**: This function has no options.
Returns an array of objects with `address`, `family`, `ttl` and `expires` properties.
#### queryAndCache(hostname, family)
An asynchronous function which makes a new DNS lookup query and updates the database. This is used by `query(hostname, family)` if no entry in the database is present.
Returns an array of objects with `address`, `family`, `ttl` and `expires` properties.
#### updateInterfaceInfo()
Updates interface info. For example, you need to run this when you plug or unplug your WiFi driver.
## High performance
See the benchmarks (queries `localhost`, performed on i7-7700k):
```
CacheableLookup#lookupAsync x 265,390 ops/sec ±0.65% (89 runs sampled)
CacheableLookup#lookupAsync.all x 119,187 ops/sec ±2.57% (87 runs sampled)
CacheableLookup#lookupAsync.all.ADDRCONFIG x 119,666 ops/sec ±0.75% (89 runs sampled)
CacheableLookup#lookup x 116,604 ops/sec ±0.68% (88 runs sampled)
CacheableLookup#lookup.all x 115,627 ops/sec ±0.72% (89 runs sampled)
CacheableLookup#lookup.all.ADDRCONFIG x 115,578 ops/sec ±0.90% (88 runs sampled)
CacheableLookup#lookupAsync - zero TTL x 60.83 ops/sec ±7.43% (51 runs sampled)
CacheableLookup#lookup - zero TTL x 49.22 ops/sec ±20.58% (49 runs sampled)
dns#resolve4 x 63.00 ops/sec ±5.88% (51 runs sampled)
dns#lookup x 21,303 ops/sec ±29.06% (35 runs sampled)
dns#lookup.all x 22,283 ops/sec ±21.96% (38 runs sampled)
dns#lookup.all.ADDRCONFIG x 5,922 ops/sec ±10.18% (38 runs sampled)
Fastest is CacheableLookup#lookupAsync
```
The package is based on [`dns.resolve4(…)`](https://nodejs.org/api/dns.html#dns_dns_resolve4_hostname_options_callback) and [`dns.resolve6(…)`](https://nodejs.org/api/dns.html#dns_dns_resolve6_hostname_options_callback).
[Why not `dns.lookup(…)`?](https://github.com/nodejs/node/issues/25560#issuecomment-455596215)
> It is not possible to use `dns.lookup(…)` because underlying calls like [getaddrinfo](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html) have no concept of servers or TTL (caching is done on OS level instead).
## Related
- [cacheable-request](https://github.com/lukechilds/cacheable-request) - Wrap native HTTP requests with RFC compliant cache support
## License
MIT