Quickstart
@nhtio/adonis-maxmind is an Adonis plugin which provides a consistent API for interacting with Maxmind GeoIP functionality.
It provides easy access to a MaxMind Reader instance through:
- The Adonis IoC container bindings
- A property of the Adonis Application
- A property of the Adonis HTTP Context
It also provides a helper utility to the Adonis HTTP Context which automatically resolves the country for the incoming request.
Installation
You can install @nhtio/adonis-maxmind using the Adonis Ace Add Command, which will both install the package and configure it.
node ace add @nhtio/adonis-maxmindManual Installation and Automatic Configuration
Install @nhtio/adonis-maxmind directly from your preferred package manager using one of the following commands:
npm i @nhtio/adonis-maxmindpnpm add @nhtio/adonis-maxmindyarn add @nhtio/adonis-maxmindThen run the Adonis Ace Configure Command:
node ace configure @nhtio/adonis-maxmindConfiguration Flags
The following flags can be passed to either the Adonis Ace Add Command or to the Adonis Ace Configure Command to modify the behavior of the configuration:
| Flag | Description |
|---|---|
--install | If all required information is available, automatically download the appropriate MaxMind GeoIP database for use |
--ci | Do not require interactivity |
--maxmind-edition=<string> | Automatically configure the MAXMIND_EDITION environmental variable. |
--maxmind-account-id=<string> | Automatically configure the MAXMIND_ACCOUNT_ID environmental variable. |
--maxmind-license-key=<string> | Automatically configure the MAXMIND_LICENSE_KEY environmental variable. |
Manual Configuration
In the AdonisRC file:
Add @nhtio/adonis-maxmind/providers/maxmind to the providers
{
providers: [
() => import('@adonisjs/core/providers/app_provider'),
() => import('@adonisjs/core/providers/http_provider'),
() => import('@adonisjs/core/providers/hash_provider'),
// ...
() => import('@nhtio/adonis-maxmind/providers/maxmind'),
]
}Add @nhtio/adonis-maxmind/commands to the commands
{
commands: [
() => import('@adonisjs/core/commands'),
() => import('@adonisjs/lucid/commands')
// ...
() => import('@nhtio/adonis-maxmind/commands'),
]
}Create the file config/maxmind.ts and insert the following:
import env from '#start/env'
import { defineConfig } from '@nhtio/adonis-maxmind/config'
import { InferMaxmindReader } from '@nhtio/adonis-maxmind/types'
const maxmindConfig = defineConfig({
edition: env.get('MAXMIND_EDITION'),
accountId: env.get('MAXMIND_ACCOUNT_ID'),
licenseKey: env.get('MAXMIND_LICENSE_KEY'),
})
export default maxmindConfig
/**
* Inferring types from the configured edition
*/
declare module '@nhtio/adonis-maxmind/types' {
export interface MaxmindReader extends InferMaxmindReader<typeof maxmindConfig> {}
}Add the following to start/env.ts:
import { Env } from '@adonisjs/core/env'
export default await Env.create(new URL('../', import.meta.url), {
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
PORT: Env.schema.number(),
APP_KEY: Env.schema.string(),
HOST: Env.schema.string({ format: 'host' }),
LOG_LEVEL: Env.schema.string(),
MAXMIND_EDITION: Env.schema.enum.optional(['GeoLiteCity', 'GeoLiteCountry', 'GeoIP2City', 'GeoIP2Country'] as const),
MAXMIND_ACCOUNT_ID: Env.schema.string.optional(),
MAXMIND_LICENSE_KEY: Env.schema.string.optional()
})Environmental Variables
The following environmental variables are needed in order to use the functionality provided by @nhtio/adonis-maxmind:
| Variable | Description |
|---|---|
MAXMIND_EDITION | The edition of the MaxMind GeoIP Database being used / downloaded. Options are: GeoLiteCity, GeoLiteCountry, GeoIP2City and GeoIP2Country |
MAXMIND_ACCOUNT_ID | The MaxMind.com account ID used to retreive the MaxMind GeoIP database |
MAXMIND_LICENSE_KEY | The MaxMind.com license key used to retreive the MaxMind GeoIP database |
See the Adonis Environment variables documentation for more information on leveraging environment variables inside an AdonisJS application.
Updating the GeoIP Database
To update the GeoIP Database according to the configured credentials, you can run:
node ace maxmind:db:updateThe command accepts the following optional flags:
| Flag | Alias | Description |
|---|---|---|
--account | -a | The equivilent of the MAXMIND_ACCOUNT_ID environmental variable |
--key | -k | The equivilent of the MAXMIND_LICENSE_KEY environmental variable |
--edition | -e | The equivilent of the MAXMIND_EDITION environmental variable |
TIP
The command will utilize environmental variables stored in the .env file or provided to the process if the flag is not set or does not provide a valid value.
Usage
The MaxMind reader can be accessed:
As an importable service:
import maxmind from '@nhtio/adonis-maxmind/services/maxmind'As an attribute of the Adonis Application
import app from "@adonisjs/core/services/app";
app.maxmind // the MaxMind reader is accessible as `app.maxmind`As a container service:
import app from "@adonisjs/core/services/app";
// Resolve the Adonis Maxmind reader from the IoC container
const maxmind = await app.container.make('maxmind')As an attribute of the Adonis HTTP Context
import { HttpContext } from '@adonisjs/core/http'
export default class MyController {
async method({ maxmind, resolveIpCountry }: HttpContext) {
}
}The MaxMind reader provides a .get(ipAddress) method to look up geographical information for an IP address. For details on available methods and response data structures, see the maxmind documentation.
The IP Country Resolution Helper
@nhtio/adonis-maxmind provides a helper for resolving countries from the incoming requests's IP address to the Adonis HTTP Context: resolveIpCountry
import { HttpContext } from '@adonisjs/core/http'
export default class MyController {
async method({ maxmind, resolveIpCountry }: HttpContext) {
}
}It has the following signature:
type resolveIpCountry = () => MaxmindResolvedCountryFor more information on the MaxmindResolvedCountry type, see the MaxmindResolvedCountry API documentation.
Examples
Using the MaxMind Reader Directly
import { HttpContext } from '@adonisjs/core/http'
export default class GeoLocationController {
async lookup({ maxmind, request, response }: HttpContext) {
const ip = request.input('ip')
const result = maxmind.get(ip)
if (result && 'country' in result) {
return response.ok({
country: result.country?.iso_code,
names: result.country?.names,
})
}
return response.notFound({ error: 'Country not found' })
}
}Using the IP Country Resolution Helper
import { HttpContext } from '@adonisjs/core/http'
export default class RestrictedController {
async index({ resolveIpCountry, response }: HttpContext) {
const country = resolveIpCountry()
// Returns 'US', 'GB', 'XX' (unknown), 'T1' (Tor), etc.
if (country === 'XX') {
return response.badRequest({ error: 'Unable to determine country' })
}
return response.ok({ country })
}
}