Skip to content

Commit 2b0154b

Browse files
committed
Support named params for lookup() method
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
1 parent ff4f0b7 commit 2b0154b

File tree

3 files changed

+101
-16
lines changed

3 files changed

+101
-16
lines changed

README.md

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,16 @@ Import the library.
3131
import IPData from 'ipdata';
3232
```
3333

34-
**Note:** If you are using `require()` then you will need to use the default value exported from the library.
34+
A named export is also available:
3535

3636
```js
37-
const IPData = require('ipdata').default;
37+
import { IPData } from 'ipdata';
38+
```
39+
40+
If you are using `require()`:
41+
42+
```js
43+
const { IPData } = require('ipdata');
3844
```
3945

4046
### Create an Instance
@@ -82,6 +88,8 @@ const ipdata = new IPData('<apiKey>', undefined, 'https://eu-api.ipdata.co/');
8288

8389
### Lookup
8490

91+
The `lookup()` method accepts either positional arguments or a single named-params object.
92+
8593
The library will lookup the ip address of the host computer if no ip address is provided.
8694

8795
```js
@@ -92,35 +100,48 @@ ipdata.lookup()
92100
});
93101
```
94102

95-
You can pass an ip address as the first parameter to the `lookup()` method to lookup information about the ip address using IPData.
103+
You can pass an ip address to lookup information about it.
96104

97105
```js
98-
const ip = '1.1.1.1';
99-
ipdata.lookup(ip)
106+
ipdata.lookup('1.1.1.1')
100107
.then(function(info) {
101-
// info.ip === 1.1.1.1
108+
// info.ip === '1.1.1.1'
102109
// ...
103110
});
104111
```
105112

106-
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.
113+
You can specify a single field to be returned.
107114

108115
```js
109-
const ip = '1.1.1.1';
110-
const selectField = 'ip';
111-
ipdata.lookup(ip, selectField)
116+
ipdata.lookup('1.1.1.1', 'ip')
112117
.then(function(info) {
113-
// info.select_field === 1.1.1.1
118+
// info.ip === '1.1.1.1'
114119
// ...
115120
});
116121
```
117122

118-
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.
123+
You can specify multiple fields to be returned.
119124

120125
```js
121-
const ip = '1.1.1.1';
122-
const fields = ['ip', 'city'];
123-
ipdata.lookup(ip, null, fields)
126+
ipdata.lookup('1.1.1.1', undefined, ['ip', 'city'])
127+
.then(function(info) {
128+
// ...
129+
});
130+
```
131+
132+
#### Named Parameters
133+
134+
You can also pass a single object, which is especially convenient when you only need `fields` or `selectField` without specifying an IP.
135+
136+
```js
137+
// Lookup your own IP with specific fields
138+
ipdata.lookup({ fields: ['ip', 'city'] })
139+
.then(function(info) {
140+
// ...
141+
});
142+
143+
// Lookup a specific IP with a select field
144+
ipdata.lookup({ ip: '1.1.1.1', selectField: 'city' })
124145
.then(function(info) {
125146
// ...
126147
});

src/ipdata.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,43 @@ describe('lookup()', () => {
261261
});
262262
});
263263

264+
describe('named params', () => {
265+
it('should return information with no params', async () => {
266+
mockFetch.mockReturnValueOnce(mockFetchResponse(MOCK_DEFAULT_IP_DATA));
267+
const info = await ipdata.lookup({});
268+
expect(info).toHaveProperty('ip');
269+
expect(info).toHaveProperty('status');
270+
});
271+
272+
it('should return information with ip param', async () => {
273+
mockFetch.mockReturnValueOnce(mockFetchResponse(MOCK_IP1_DATA));
274+
const info = await ipdata.lookup({ ip: TEST_IP });
275+
expect(info).toHaveProperty('ip', TEST_IP);
276+
expect(info).toHaveProperty('status');
277+
});
278+
279+
it('should return a selectField response', async () => {
280+
mockFetch.mockReturnValueOnce(mockFetchResponse(false));
281+
const info = await ipdata.lookup({ selectField: 'is_eu' });
282+
expect(info).toHaveProperty('is_eu', false);
283+
expect(info).toHaveProperty('status');
284+
});
285+
286+
it('should return a fields response', async () => {
287+
mockFetch.mockReturnValueOnce(mockFetchResponse({ ip: TEST_IP, is_eu: false }));
288+
const info = await ipdata.lookup({ ip: TEST_IP, fields: ['ip', 'is_eu'] });
289+
expect(info).toHaveProperty('ip', TEST_IP);
290+
expect(info).toHaveProperty('is_eu', false);
291+
expect(info).toHaveProperty('status');
292+
});
293+
294+
it('should throw if selectField and fields are both provided', async () => {
295+
await expect(ipdata.lookup({ selectField: 'ip', fields: ['ip'] })).rejects.toThrow(
296+
'The selectField and fields parameters cannot be used at the same time.',
297+
);
298+
});
299+
});
300+
264301
describe('new API fields', () => {
265302
it('should return threat object with new fields', async () => {
266303
mockFetch.mockReturnValueOnce(mockFetchResponse(MOCK_IP1_DATA));

src/ipdata.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ export interface CacheConfig {
6969
ttl?: number;
7070
}
7171

72+
export interface LookupParams {
73+
ip?: string;
74+
selectField?: string;
75+
fields?: string[];
76+
}
77+
7278
export interface LookupResponse {
7379
ip: string;
7480
is_eu: boolean;
@@ -158,7 +164,28 @@ export class IPData {
158164
return url;
159165
}
160166

161-
async lookup(ip?: string, selectField?: string, fields?: string[]): Promise<LookupResponse> {
167+
async lookup(params: LookupParams): Promise<LookupResponse>;
168+
async lookup(ip?: string, selectField?: string, fields?: string[]): Promise<LookupResponse>;
169+
async lookup(
170+
ipOrParams?: string | LookupParams,
171+
positionalSelectField?: string,
172+
positionalFields?: string[],
173+
): Promise<LookupResponse> {
174+
let ip: string | undefined;
175+
let selectField: string | undefined;
176+
let fields: string[] | undefined;
177+
178+
if (typeof ipOrParams === 'object' && ipOrParams !== null) {
179+
({ ip, selectField, fields } = ipOrParams);
180+
} else if (typeof ipOrParams === 'string') {
181+
ip = ipOrParams;
182+
selectField = positionalSelectField;
183+
fields = positionalFields;
184+
} else {
185+
selectField = positionalSelectField;
186+
fields = positionalFields;
187+
}
188+
162189
if (ip && !isValidIP(ip)) {
163190
throw new Error(`${ip} is an invalid IP address.`);
164191
}

0 commit comments

Comments
 (0)