From 2b0154b0075c1b8e08b0944e0885dfb3df34b7d0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 08:00:55 +0000 Subject: [PATCH] Support named params for lookup() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an overloaded lookup() signature that accepts a single { ip, selectField, fields } object, so callers no longer need to pass undefined placeholders for unused positional arguments. Both call styles are supported — no breaking change. Closes #27 https://claude.ai/code/session_01UabaLo3R3sXovyxaZo2yCF --- README.md | 51 ++++++++++++++++++++++++++++++++-------------- src/ipdata.test.ts | 37 +++++++++++++++++++++++++++++++++ src/ipdata.ts | 29 +++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b340942..4cfe695 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,16 @@ Import the library. import IPData from 'ipdata'; ``` -**Note:** If you are using `require()` then you will need to use the default value exported from the library. +A named export is also available: ```js -const IPData = require('ipdata').default; +import { IPData } from 'ipdata'; +``` + +If you are using `require()`: + +```js +const { IPData } = require('ipdata'); ``` ### Create an Instance @@ -82,6 +88,8 @@ const ipdata = new IPData('', undefined, 'https://eu-api.ipdata.co/'); ### Lookup +The `lookup()` method accepts either positional arguments or a single named-params object. + The library will lookup the ip address of the host computer if no ip address is provided. ```js @@ -92,35 +100,48 @@ ipdata.lookup() }); ``` -You can pass an ip address as the first parameter to the `lookup()` method to lookup information about the ip address using IPData. +You can pass an ip address to lookup information about it. ```js -const ip = '1.1.1.1'; -ipdata.lookup(ip) +ipdata.lookup('1.1.1.1') .then(function(info) { - // info.ip === 1.1.1.1 + // info.ip === '1.1.1.1' // ... }); ``` -You can specify only a select field to be returned when looking up an ip address by passing a field as the second parameter to the `lookup()` method. +You can specify a single field to be returned. ```js -const ip = '1.1.1.1'; -const selectField = 'ip'; -ipdata.lookup(ip, selectField) +ipdata.lookup('1.1.1.1', 'ip') .then(function(info) { - // info.select_field === 1.1.1.1 + // info.ip === '1.1.1.1' // ... }); ``` -You can specify only certain fields to be returned when looking up an ip address by passing an array of fields as the third parameter to the `lookup()` method. +You can specify multiple fields to be returned. ```js -const ip = '1.1.1.1'; -const fields = ['ip', 'city']; -ipdata.lookup(ip, null, fields) +ipdata.lookup('1.1.1.1', undefined, ['ip', 'city']) + .then(function(info) { + // ... + }); +``` + +#### Named Parameters + +You can also pass a single object, which is especially convenient when you only need `fields` or `selectField` without specifying an IP. + +```js +// Lookup your own IP with specific fields +ipdata.lookup({ fields: ['ip', 'city'] }) + .then(function(info) { + // ... + }); + +// Lookup a specific IP with a select field +ipdata.lookup({ ip: '1.1.1.1', selectField: 'city' }) .then(function(info) { // ... }); diff --git a/src/ipdata.test.ts b/src/ipdata.test.ts index 6a34818..fdb3442 100644 --- a/src/ipdata.test.ts +++ b/src/ipdata.test.ts @@ -261,6 +261,43 @@ describe('lookup()', () => { }); }); + describe('named params', () => { + it('should return information with no params', async () => { + mockFetch.mockReturnValueOnce(mockFetchResponse(MOCK_DEFAULT_IP_DATA)); + const info = await ipdata.lookup({}); + expect(info).toHaveProperty('ip'); + expect(info).toHaveProperty('status'); + }); + + it('should return information with ip param', async () => { + mockFetch.mockReturnValueOnce(mockFetchResponse(MOCK_IP1_DATA)); + const info = await ipdata.lookup({ ip: TEST_IP }); + expect(info).toHaveProperty('ip', TEST_IP); + expect(info).toHaveProperty('status'); + }); + + it('should return a selectField response', async () => { + mockFetch.mockReturnValueOnce(mockFetchResponse(false)); + const info = await ipdata.lookup({ selectField: 'is_eu' }); + expect(info).toHaveProperty('is_eu', false); + expect(info).toHaveProperty('status'); + }); + + it('should return a fields response', async () => { + mockFetch.mockReturnValueOnce(mockFetchResponse({ ip: TEST_IP, is_eu: false })); + const info = await ipdata.lookup({ ip: TEST_IP, fields: ['ip', 'is_eu'] }); + expect(info).toHaveProperty('ip', TEST_IP); + expect(info).toHaveProperty('is_eu', false); + expect(info).toHaveProperty('status'); + }); + + it('should throw if selectField and fields are both provided', async () => { + await expect(ipdata.lookup({ selectField: 'ip', fields: ['ip'] })).rejects.toThrow( + 'The selectField and fields parameters cannot be used at the same time.', + ); + }); + }); + describe('new API fields', () => { it('should return threat object with new fields', async () => { mockFetch.mockReturnValueOnce(mockFetchResponse(MOCK_IP1_DATA)); diff --git a/src/ipdata.ts b/src/ipdata.ts index abe686c..f6c4637 100644 --- a/src/ipdata.ts +++ b/src/ipdata.ts @@ -69,6 +69,12 @@ export interface CacheConfig { ttl?: number; } +export interface LookupParams { + ip?: string; + selectField?: string; + fields?: string[]; +} + export interface LookupResponse { ip: string; is_eu: boolean; @@ -158,7 +164,28 @@ export class IPData { return url; } - async lookup(ip?: string, selectField?: string, fields?: string[]): Promise { + async lookup(params: LookupParams): Promise; + async lookup(ip?: string, selectField?: string, fields?: string[]): Promise; + async lookup( + ipOrParams?: string | LookupParams, + positionalSelectField?: string, + positionalFields?: string[], + ): Promise { + let ip: string | undefined; + let selectField: string | undefined; + let fields: string[] | undefined; + + if (typeof ipOrParams === 'object' && ipOrParams !== null) { + ({ ip, selectField, fields } = ipOrParams); + } else if (typeof ipOrParams === 'string') { + ip = ipOrParams; + selectField = positionalSelectField; + fields = positionalFields; + } else { + selectField = positionalSelectField; + fields = positionalFields; + } + if (ip && !isValidIP(ip)) { throw new Error(`${ip} is an invalid IP address.`); }