Skip to content

Commit

Permalink
Feat/prepare release (#5)
Browse files Browse the repository at this point in the history
Closes #3 #4 #2
  • Loading branch information
vboechat authored May 18, 2024
2 parents 3ea7767 + 5978617 commit 3b1b4d3
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 37 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/pr-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Test changes

on:
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 'latest'
registry-url: 'https://registry.npmjs.org/'

- name: Install dependencies
run: yarn install

- name: Test project
run: yarn test
3 changes: 3 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
- name: Install dependencies
run: yarn install

- name: Test project
run: yarn test

- name: Build project
run: yarn build

Expand Down
60 changes: 55 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pnpm install network-error-handling

## Usage

### Network error handling

1. Import

```typescript
Expand All @@ -28,18 +30,21 @@ import { networkErrorHandling } from "network-error-handling";

2. Call the function, example:

> [!IMPORTANT]
> The `error` parameter is the `AxiosError` object from the axios response.
```typescript
networkErrorHandling(error)
.addError(
StatusCode.CONFLICT,
409,
"User already exists",
"The user already exists, please try again with another email.",
() => console.log("Error while creating user")
)
.handle();
```

## Using toast
#### Using toast

If you plan to display a toast of error, you will need to have a function to handle the toast, example using Shadcn
UI toast component
Expand All @@ -56,7 +61,12 @@ After this, you can use the `withToast` method to handle the toast, example:
```typescript
networkErrorHandling(error)
.addError(
StatusCode.CONFLICT,
400,
"Invalid form data",
"The form data is invalid, please check the fields."
)
.addError(
409,
"User already exists",
"The user already exists, please try again with another email."
)
Expand All @@ -69,7 +79,7 @@ Ooh, you can also use a callback function when using a toast!
```typescript
networkErrorHandling(error)
.addError(
StatusCode.CONFLICT,
409,
"User already exists",
"The user already exists, please try again with another email.",
() => console.log("Error while creating user")
Expand All @@ -78,6 +88,46 @@ networkErrorHandling(error)
.handle();
```

### Status Codes

This package provides a list of status codes that you can use to handle the errors, example:

```typescript
import { StatusCode } from "network-error-handling";

networkErrorHandling(error)
.addError(
StatusCode.CONFLICT,
"User already exists",
"The user already exists, please try again with another email."
)
.handle();
```

## Api References

### `networkErrorHandling(error: AxiosError)`

- `error`: The `AxiosError` object from the axios response.

### `addError(statusCode: number, title: string, description: string, callback?: () => void)`

- `statusCode`: The status code to handle the error.
- `title`: The title of the error.
- `description`: The description of the error.
- `callback`: Optional callback function to execute when the error is handled.

> [!CAUTION]
> For now, the callback parameter is not async aware, so you can't use async functions inside the callback.
### `withToast(toastFunction: (title: string, description: string) => void)`

- `toastFunction`: The function to handle the toast.

### `handle()`

- Handle the error.

## License

[MIT](LICENSE)
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
14 changes: 9 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"version": "1.0.3",
"description": "An useful error handler for axios network requests in a React application",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/vboechat/network-error-handling"
},
"author": {
"name": "Victor Ribeiro Boechat",
"email": "[email protected]",
Expand All @@ -15,12 +19,12 @@
"dist"
],
"scripts": {
"build": "tsc"
},
"dependencies": {
"axios": "^1.6.8"
"build": "tsc",
"test": "vitest"
},
"devDependencies": {
"typescript": "^5.4.5"
"axios": "^1.6.8",
"typescript": "^5.4.5",
"vitest": "^1.6.0"
}
}
125 changes: 125 additions & 0 deletions src/network-error-handling.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { describe, it, expect, vi } from "vitest";
import { AxiosError } from "axios";
import { networkErrorHandling, ToastFunction } from "./network-error-handling";
import { StatusCode } from "./status-codes";

describe("networkErrorHandling", () => {
it("should add an error and handle it without toast", () => {
const axiosError = {
response: { status: 404 },
} as AxiosError;

const handler = networkErrorHandling(axiosError).addError(
StatusCode.NOT_FOUND,
"Not Found",
"The requested resource was not found"
);

const callback = vi.fn();
handler.addError(
StatusCode.INTERNAL_SERVER_ERROR,
"Server Error",
"Internal server error",
callback
);

handler.handle();

expect(callback).not.toHaveBeenCalled();
});

it("should add an error and handle it with toast", () => {
const axiosError = {
response: { status: 404 },
} as AxiosError;

const toast: ToastFunction = vi.fn();

const handler = networkErrorHandling(axiosError)
.addError(
StatusCode.NOT_FOUND,
"Not Found",
"The requested resource was not found"
)
.withToast(toast);

handler.handle();

expect(toast).toHaveBeenCalledWith(
"Not Found",
"The requested resource was not found"
);
});

it("should add multiple errors and handle them correctly", () => {
const axiosError = {
response: { status: 500 },
} as AxiosError;

const toast: ToastFunction = vi.fn();
const callback = vi.fn();

const handler = networkErrorHandling(axiosError)
.addError(
StatusCode.NOT_FOUND,
"Not Found",
"The requested resource was not found"
)
.addError(
StatusCode.INTERNAL_SERVER_ERROR,
"Server Error",
"Internal server error",
callback
)
.withToast(toast);

handler.handle();

expect(toast).toHaveBeenCalledWith("Server Error", "Internal server error");
expect(callback).toHaveBeenCalled();
});

it("should not handle error if status is not in the map", () => {
const axiosError = {
response: { status: 403 },
} as AxiosError;

const toast: ToastFunction = vi.fn();
const callback = vi.fn();

const handler = networkErrorHandling(axiosError)
.addError(
StatusCode.NOT_FOUND,
"Not Found",
"The requested resource was not found"
)
.addError(
StatusCode.INTERNAL_SERVER_ERROR,
"Server Error",
"Internal server error",
callback
)
.withToast(toast);

handler.handle();

expect(toast).not.toHaveBeenCalled();
expect(callback).not.toHaveBeenCalled();
});

it("should handle error without status", () => {
const axiosError = {
response: {},
} as AxiosError;

const handler = networkErrorHandling(axiosError).addError(
StatusCode.NOT_FOUND,
"Not Found",
"The requested resource was not found"
);

handler.handle();

expect(true).toBe(true);
});
});
35 changes: 9 additions & 26 deletions src/network-error-handling.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { AxiosError } from "axios";
import { ToastFunction } from "./types/toast-function";

/**
* Interface for error handling.
*/
interface ErrorHandler {
export type ToastFunction = (title: string, description: string) => void;

export type ErrorHandler = {
/**
* Adds an error with status, title, message, and optional callback.
* @param {number} status - HTTP status code.
Expand All @@ -19,12 +17,9 @@ interface ErrorHandler {
message: string,
callback?: () => void
) => ErrorHandlerWithHandle;
}
};

/**
* Interface for error handling with both addError and handle methods.
*/
interface ErrorHandlerWithHandle {
export type ErrorHandlerWithHandle = {
/**
* Adds an error with status, title, message, and optional callback.
* @param {number} status - HTTP status code.
Expand All @@ -51,22 +46,16 @@ interface ErrorHandlerWithHandle {
* Handles the error by executing the callback.
*/
handle: () => void;
}
};

/**
* Interface for error handling with toast notifications and handle method.
*/
interface ErrorHandlingWithToastHandle {
export type ErrorHandlingWithToastHandle = {
/**
* Handles the error by executing the callback and/or displaying a toast.
*/
handle: () => void;
}
};

/**
* Type for error details.
*/
type ErrorDetails = {
export type ErrorDetails = {
title: string;
message: string;
callback?: () => void;
Expand All @@ -80,12 +69,6 @@ type ErrorDetails = {
export function networkErrorHandling(error: AxiosError): ErrorHandler {
const errors = new Map<number, ErrorDetails>();

/**
* Creates an error handler with the current errors and toast function.
* @param {Map<number, ErrorDetails>} currentErrors - Map of current error details.
* @param {ToastFunction | null} currentToast - Current toast function, if any.
* @returns {ErrorHandler & ErrorHandlerWithHandle} - Returns the ErrorHandler instance.
*/
const createHandler = (
currentErrors: Map<number, ErrorDetails>,
currentToast: ToastFunction | null
Expand Down
34 changes: 34 additions & 0 deletions src/status-codes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export const StatusCode = {
OK: 200,
CREATED: 201,
ACCEPTED: 202,
NO_CONTENT: 204,
MOVED_PERMANENTLY: 301,
FOUND: 302,
SEE_OTHER: 303,
NOT_MODIFIED: 304,
TEMPORARY_REDIRECT: 307,
PERMANENT_REDIRECT: 308,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_ALLOWED: 405,
NOT_ACCEPTABLE: 406,
CONFLICT: 409,
GONE: 410,
LENGTH_REQUIRED: 411,
PRECONDITION_FAILED: 412,
PAYLOAD_TOO_LARGE: 413,
URI_TOO_LONG: 414,
UNSUPPORTED_MEDIA_TYPE: 415,
RANGE_NOT_SATISFIABLE: 416,
EXPECTATION_FAILED: 417,
UPGRADE_REQUIRED: 426,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
HTTP_VERSION_NOT_SUPPORTED: 505,
} as const;
1 change: 0 additions & 1 deletion src/types/toast-function.ts

This file was deleted.

0 comments on commit 3b1b4d3

Please sign in to comment.