Skip to content

Commit 5fa9eec

Browse files
committed
chore: custom errors
1 parent 29b6a18 commit 5fa9eec

File tree

5 files changed

+72
-10
lines changed

5 files changed

+72
-10
lines changed

.changeset/two-jeans-kick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-loqate": major
3+
---
4+
5+
Breaking: implement LoqateError and ReactLoqateError

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ import AddressSearch from 'react-loqate';
9595
/>;
9696
```
9797

98+
### Errors
99+
100+
Two types of errors can be thrown, LoqateError and ReactLoqateError.
101+
Loqate Errors are errors from the Loqate API. Their structure, causes and resolutions can be [found in the loqate docs](https://www.loqate.com/developers/api/generic-errors/).
102+
103+
Currently only one ReactLoqateError can be thrown. This error occurs when the Retrieve API returns an empty Items array after querying it with an existing ID.
104+
105+
It is on you as the implementing party to catch and handle these errors.
106+
98107
### Contributing
99108

100109
This codebases use [@changesets](https://github.com/changesets/changesets) for release and version management

src/error.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
type ReactLocateErrorCode = 'NO_ITEMS_RETRIEVED';
2+
3+
export class ReactLoqateError extends Error {
4+
public code: ReactLocateErrorCode;
5+
6+
constructor({
7+
message,
8+
code,
9+
}: {
10+
message: string;
11+
code: ReactLocateErrorCode;
12+
}) {
13+
super(message);
14+
this.code = code;
15+
}
16+
}
17+
18+
export class LoqateError extends Error {
19+
public Cause: string;
20+
public Description: string;
21+
public Error: string;
22+
public Resolution: string;
23+
24+
constructor({
25+
Description,
26+
Cause,
27+
Error,
28+
Resolution,
29+
}: {
30+
Description: string;
31+
Cause: string;
32+
Error: string;
33+
Resolution: string;
34+
}) {
35+
super(Description);
36+
this.Cause = Cause;
37+
this.Description = Description;
38+
this.Error = Error;
39+
this.Resolution = Resolution;
40+
}
41+
}

src/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export interface Item {
110110
Highlight: string;
111111
}
112112

113-
export interface ErrorItem {
113+
export interface LoqateErrorItem {
114114
Error: string;
115115
Description: string;
116116
Cause: string;
@@ -172,16 +172,13 @@ function AddressSearch(props: Props): JSX.Element {
172172
Items = res.Items;
173173
}
174174
} catch (e) {
175+
setSuggestions([]);
175176
// error needs to be thrown in the render in order to be caught by the ErrorBoundary
176177
setError(() => {
177178
throw e;
178179
});
179180
}
180181

181-
if (Items.length) {
182-
setSuggestions([]);
183-
}
184-
185182
onSelect(Items[0] as unknown as Address);
186183
return;
187184
}

src/utils/Loqate.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { ErrorItem, Item } from '..';
1+
import { Item, LoqateErrorItem } from '..';
22
import {
33
LOQATE_BASE_URL,
44
LOQATE_FIND_URL,
55
LOQATE_RETRIEVE_URL,
66
} from '../constants/loqate';
7+
import { LoqateError, ReactLoqateError } from '../error';
78

89
interface FindQuery {
910
text: string;
@@ -13,7 +14,7 @@ interface FindQuery {
1314
containerId?: string;
1415
}
1516

16-
type LoqateResponse = { Items?: Item[] | ErrorItem[] };
17+
type LoqateResponse = { Items?: Item[] | LoqateErrorItem[] };
1718
type LoqateNoErrorResponse = { Items?: Item[] };
1819
class Loqate {
1920
constructor(
@@ -29,7 +30,16 @@ class Loqate {
2930
const params = new URLSearchParams({ Id: id, Key: this.key });
3031
const url = `${this.baseUrl}/${LOQATE_RETRIEVE_URL}?${params.toString()}`;
3132
const res = await fetch(url).then<LoqateResponse>((r) => r.json());
32-
return this.handleErrors(res);
33+
const noLoqateErrosRes = this.handleErrors(res);
34+
35+
if (noLoqateErrosRes.Items && !noLoqateErrosRes.Items?.length) {
36+
throw new ReactLoqateError({
37+
code: 'NO_ITEMS_RETRIEVED',
38+
message: `Loqate retrieve API did not return any address items for the provided ID ${id}`,
39+
});
40+
}
41+
42+
return noLoqateErrosRes;
3343
}
3444

3545
public async find(query: FindQuery): Promise<LoqateNoErrorResponse> {
@@ -54,9 +64,9 @@ class Loqate {
5464
}
5565

5666
private handleErrors = (res: LoqateResponse): LoqateNoErrorResponse => {
57-
const firstItem: Item | ErrorItem | undefined = res?.Items?.[0];
67+
const firstItem: Item | LoqateErrorItem | undefined = res?.Items?.[0];
5868
if (firstItem && Object.hasOwn(firstItem, 'Error')) {
59-
throw new Error(`Loqate error: ${JSON.stringify(firstItem)}`);
69+
throw new LoqateError(firstItem as LoqateErrorItem);
6070
}
6171

6272
return res as LoqateNoErrorResponse;

0 commit comments

Comments
 (0)