@adaskothebeast/angular-date-http-interceptor
v4.0.1
Published
## What problem does this set of libraries solve?
Downloads
22
Readme
Date interceptors
What problem does this set of libraries solve?
Working with dates and durations in JSON can be cumbersome and error-prone due to the lack of a standard format for date-time serialization. JSON, by its nature, does not have a specific data type for dates or durations. As a result, dates are usually serialized as strings, which then require additional parsing to be used as date objects in your application. This can lead to various issues, such as incorrect time zone conversions, invalid date formats, and the cumbersome handling of duration calculations.
This library addresses these challenges by providing a robust solution for converting date and duration strings from JSON payloads into native Date objects and Duration objects, respectively. By doing so, it enables developers to work with date and duration data more naturally and efficiently in their applications, without having to deal with the intricacies of manual string parsing and conversion. This conversion is not just limited to top-level fields; this library is designed to walk through deep object compositions and arrays, ensuring that every date and duration string, no matter where it is nested within your data structure, is converted accurately.
Key Features
- Deep Object and Array Traversal: This library is capable of navigating through complex data structures, converting every date and duration string found in objects and arrays. This feature is particularly useful for applications dealing with deeply nested JSON data, where manual conversion would be tedious and error-prone.
- Automatic Conversion: Automatically converts date strings from JSON into JavaScript Date objects, making it easier to work with dates without manual parsing.
- Duration Handling: Converts duration strings into Duration objects, allowing for straightforward duration calculations and manipulations.
- Time Zone Awareness: Ensures that date conversions take into account time zone differences, preventing common errors related to time zone handling.
- Flexible Format Support: Supports multiple date and duration string formats, providing flexibility to work with various JSON structures and conventions.
- Easy Integration: Designed to be easily integrated into any JavaScript or TypeScript project, enhancing date and duration handling with minimal setup.
Value for Developers
This library significantly simplifies the handling of dates and durations in JavaScript applications, especially those that consume JSON data from APIs or external sources. By abstracting away the complexity of parsing and converting date and duration strings, it allows developers to focus on the core logic of their applications, leading to cleaner, more maintainable code. Additionally, the library's support for various formats and time zones ensures that it can be used in a wide range of applications, from simple projects to complex, data-intensive applications.
Badges
Which libraries are supported?
Helpers are prepared for following libraries:
- pure js Date object
- date-fns - Date and Duration objects
- Day.js - Dayjs and Duration object
- js-joda - ZonedDateTime object
- luxon - DateTime and Duration object
- moment.js - Moment and Duration object
What frameworks are supported?
- Angular in form of interceptor named
HierarchicalDateHttpInterceptor
- react all api call libraries are supported - special case for rtk-query is solved in form of hook
useAdjustUseQueryHookResultWithHierarchicalDateConverter
Installation dependant of date library
Based on your needs, install one of the following packages:
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
import { hierarchicalConvertToDateFns } from '@adaskothebeast/hierarchical-convert-to-date-fns';
import { hierarchicalConvertToDayjs } from '@adaskothebeast/hierarchical-convert-to-dayjs';
import { hierarchicalConvertToJsJoda } from '@adaskothebeast/hierarchical-convert-to-js-joda';
import { hierarchicalConvertToLuxon } from '@adaskothebeast/hierarchical-convert-to-luxon';
import { hierarchicalConvertToMoment } from '@adaskothebeast/hierarchical-convert-to-moment';
Installation dependant of framework
Additionally in some cases you need to install framework specific package:
Angular
In your application's root module, import library module and symbol and provide the hierarchicalConvertToDate
or other function using the HIERARCHICAL_DATE_ADJUST_FUNCTION token:
import { AngularDateHttpInterceptorModule, HIERARCHICAL_DATE_ADJUST_FUNCTION } from '@adaskothebeast/angular-date-http-interceptor';
// Adjust this import as needed - this will import adjustment function for pure js Date object
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
@NgModule({
imports: [
// ...
AngularDateHttpInterceptorModule,
],
providers: [
{ provide: HIERARCHICAL_DATE_ADJUST_FUNCTION, useValue: hierarchicalConvertToDate },
// other providers...
]
})
export class AppModule { }
In this setup, Angular's dependency injection system will provide the hierarchicalConvertToDate
function to the HierarchicalDateHttpInterceptor
when it's instantiated, even though the function is provided in the application's module and the interceptor is provided in the library module. This is because Angular's DI system is hierarchical and can inject dependencies from parent injectors into child injectors.
React
In case of react there are multiple libraries that can be used for api calls. For one of it there is special hook prepared:
rtk-query
Hook useAdjustUseQueryHookResultWithHierarchicalDateConverter
must be called within a React component or another custom hook, and the useQueryFunction
argument it receives should be a hook that has already been invoked.
You would then use it in a component like this:
import { useAdjustUseQueryHookResultWithHierarchicalDateConverter} from '@adaskothebeast/react-date-query-hook';
const MyComponent: React.FC = () => {
const useQueryResult = useQueryFunction(arg, options); // <-- Call your hook here
const adjustedQueryResult = useAdjustUseQueryHookResultWithHierarchicalDateConverter(useQueryResult); // <-- Pass the result to your custom hook
// Rest of your component...
}
This would adhere to the rules of Hooks, as the hook is being called at the top level of a React function component, not inside a callback or other function.
redux-query-react
To create a custom React hook that uses the hierarchicalConvertToDate
function in combination with Redux Query, we first need to define how redux-query
is set up in your application. For simplicity, let's assume that you are using useRequest
or useMutation
hooks provided by redux-query-react
.
We can create a custom hook named useParsedRequest
that takes the same parameters as useRequest
and uses hierarchicalConvertToDate
to parse any date strings in the response data into Date
objects.
Here's a possible implementation in TypeScript:
import { useRequest, RequestConfig } from 'redux-query-react';
import { useMemo } from 'react';
// Adjust this import as needed - this will import adjustment function for pure js Date object
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
export function useParsedRequest(config: RequestConfig) {
const { url, ...restConfig } = config;
const transformedConfig: RequestConfig = useMemo(() => ({
...restConfig,
url,
transform: (data: any) => {
hierarchicalConvertToDate(data);
return restConfig.transform ? restConfig.transform(data) : data;
},
}), [url, restConfig]);
return useRequest(transformedConfig);
}
In this example, we first destructure the config
parameter to separate the url
and restConfig
. This is because we'll only be changing the transform
function and we want to make sure our useMemo
dependency array doesn't change too often.
We then define transformedConfig
using useMemo
to create a new config object that includes our hierarchicalConvertToDate
call inside the transform
function. We're still calling the original transform function if it was provided.
Finally, we call useRequest
with our transformedConfig
and return the result.
You can use useParsedRequest
just like you would use useRequest
, but the response data will be passed through hierarchicalConvertToDate
before being returned.
Remember to adjust the import paths and the hierarchicalConvertToDate
function to match your project structure and requirements.
react-query
To use the hierarchicalConvertToDate
function within the context of react-query
, you can incorporate it within the fetcher function that you pass to react-query
's useQuery
hook.
Here's a sample implementation:
import { useQuery } from 'react-query';
// Adjust this import as needed - this will import adjustment function for pure js Date object
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
// Fetcher function that retrieves data and applies date parsing
async function fetcher(url: string) {
const response = await fetch(url);
const data = await response.json();
hierarchicalConvertToDate(data);
return data;
}
function MyComponent() {
const { data, isLoading, error } = useQuery('myKey', () => fetcher('/api/my-endpoint'));
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error occurred</div>;
}
return (
<div>
{/* Render data here */}
</div>
);
}
In the code above, we defined an asynchronous fetcher
function that retrieves data from an API endpoint, applies the hierarchicalConvertToDate
function to the retrieved data, and then returns the parsed data. This fetcher
function is then passed to the useQuery
hook from react-query
. The results (data, loading state, and error state) are then used in MyComponent
to display the appropriate UI based on the state of the data fetch.
redux-saga
In order to perform this task with redux-saga
, you would need to define a saga that fetches the data, parses the dates, and then dispatches a success action with the parsed data as its payload.
Here's a general example of how you could structure this:
import { call, put, takeEvery } from 'redux-saga/effects';
import axios from 'axios';
// Adjust this import as needed - this will import adjustment function for pure js Date object
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
// Saga worker
function* fetchData(action) {
try {
const response = yield call(axios.get, action.payload.url);
hierarchicalConvertToDate(response.data);
yield put({ type: 'FETCH_SUCCEEDED', payload: response.data });
} catch (e) {
yield put({ type: 'FETCH_FAILED', message: e.message });
}
}
// Saga watcher
function* watchFetchData() {
yield takeEvery('FETCH_REQUESTED', fetchData);
}
// Export the saga (single or root)
export default function* rootSaga() {
yield all([watchFetchData()]);
}
This code consists of two parts. The fetchData
generator function (the "worker" saga) performs the asynchronous fetch operation when a FETCH_REQUESTED
action is dispatched. It then uses the call
effect to perform the API call with axios.get
, applies the hierarchicalConvertToDate
function to the response data, and then dispatches a FETCH_SUCCEEDED
action with the parsed data. If an error occurs during this process, it dispatches a FETCH_FAILED
action with the error message.
The watchFetchData
generator function (the "watcher" saga) waits for FETCH_REQUESTED
actions to be dispatched, and then triggers the fetchData
worker saga each time this happens.
In your React component, you would dispatch a FETCH_REQUESTED
action to initiate this process. For example:
import { useDispatch } from 'react-redux';
function MyComponent() {
const dispatch = useDispatch();
const fetchData = () => {
dispatch({ type: 'FETCH_REQUESTED', payload: { url: '/api/my-endpoint' } });
};
// Call fetchData() at the appropriate time (e.g. in a useEffect or in response to user interaction)
}
Remember to integrate the saga with your store using the redux-saga
middleware. The exact setup will depend on your application structure and configuration.
Please adjust the code according to your requirements.
SWR
In order to use the hierarchicalConvertToDate
function within the context of swr
(Stale While Revalidate), you can incorporate it within the fetcher
function that you pass to swr
's useSWR hook.
Here's a sample implementation:
import useSWR from 'swr';
// Adjust this import as needed - this will import adjustment function for pure js Date object
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
// Fetcher function that retrieves data and applies date parsing
async function fetcher(url: string) {
const response = await fetch(url);
const data = await response.json();
hierarchicalConvertToDate(data);
return data;
}
function MyComponent() {
const { data, error } = useSWR('/api/my-endpoint', fetcher);
if (error) {
return <div>Error occurred</div>;
}
if (!data) {
return <div>Loading...</div>;
}
return (
<div>
{/* Render data here */}
</div>
);
}
In the code above, we defined an asynchronous fetcher
function that retrieves data from an API endpoint, applies the hierarchicalConvertToDate
function to the retrieved data, and then returns the parsed data. This fetcher
function is then passed to the useSWR
hook from swr
. The results (data and error state) are then used in MyComponent
to display the appropriate UI based on the state of the data fetch.
Please adjust the code according to your project structure and requirements.
redux-thunk
When using redux-thunk
, you'll dispatch a function (the "thunk") that performs the asynchronous request and dispatches actions to represent the lifecycle of the request.
We'll create a function which represents the asynchronous operation:
// Adjust this import as needed - this will import adjustment function for pure js Date object
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
function fetchApiData(url: string) {
return async function(dispatch: Function) {
dispatch({ type: 'FETCH_DATA_REQUEST' });
try {
const response = await fetch(url);
const data = await response.json();
hierarchicalConvertToDate(data); // Apply the date adjustment
dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
} catch (error) {
dispatch({ type: 'FETCH_DATA_FAILURE', payload: error.message });
}
};
}
In this function, FETCH_DATA_REQUEST
, FETCH_DATA_SUCCESS
, and FETCH_DATA_FAILURE
are action types that your reducer should handle.
In your component, you can dispatch this function like so:
import { useDispatch } from 'react-redux';
function MyComponent() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchApiData('/api/my-endpoint'));
}, [dispatch]);
// Rest of your component here...
}
This will initiate the fetch when your component mounts and dispatch either a success or failure action when the fetch completes, allowing you to store the fetched data (or any error that occurred) in your Redux state.
Please adjust the code according to your requirements and project structure.
Axios with AxiosInstanceManager
The AxiosInstanceManager class simplifies the process of using Axios with the hierarchicalConvertToDate
function. By utilizing this class, you can easily create and use a centralized Axios instance with a response interceptor that automatically processes response data.
Here's how to use AxiosInstanceManager:
import { AxiosInstanceManager } from '@adaskothebeast/axios-interceptor';
import { hierarchicalConvertToDate } from '@adaskothebeast/hierarchical-convert-to-date';
// Create an Axios instance using AxiosInstanceManager
const instance = AxiosInstanceManager.createInstance(hierarchicalConvertToDate);
async function fetchApiData() {
try {
const response = await instance.get('/api/my-endpoint');
console.log(response.data);
} catch (error) {
console.error(error);
}
}
fetchApiData();
In the code above:
- The createInstance method of AxiosInstanceManager is used to create and configure an Axios instance. This instance is configured with a response interceptor that applies hierarchicalConvertToDate to response.data. This conversion function processes any date strings in the response data into JavaScript Date objects (or in case of other libs proper class for given date lib).
- The fetchApiData function demonstrates using the configured Axios instance to make a GET request. The response data, with date strings already converted into Date (or in case of other libs proper class for given date lib) objects, is logged to the console. Errors from the request are caught and logged.
This approach encapsulates the Axios configuration, making your code cleaner and more maintainable. Remember to adjust imports and function calls as per your project's file structure and requirements.