Browse Source

FEATURE | axios setup

merge-requests/11/head
andrew_bashliy 3 years ago
parent
commit
2535b62017
  1. 3
      .prettierrc.js
  2. 98
      package-lock.json
  3. 5
      package.json
  4. 60
      src/api/http.decorstors.ts
  5. 94
      src/api/http.service.ts
  6. 3
      src/api/interfaces/api-helpers.interfaces.ts
  7. 1
      src/api/interfaces/index.ts
  8. 4
      src/config/index.ts
  9. 18
      src/services/global-container.service.ts
  10. 2
      src/services/index.ts
  11. 19
      src/services/network.service.ts

3
.prettierrc.js

@ -1,9 +1,10 @@ @@ -1,9 +1,10 @@
module.exports = {
bracketSpacing: false,
bracketSpacing: true,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
tabWidth: 4,
useTabs: true,
semi: false,
};

98
package-lock.json generated

@ -1281,6 +1281,22 @@ @@ -1281,6 +1281,22 @@
"chalk": "^4.0.0"
}
},
"@react-native-async-storage/async-storage": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.15.6.tgz",
"integrity": "sha512-kVfy6O5Xbce9GfD9Islxn5JaOczNz6dF3Ce/7tP4foVLPNwo7UfdgXeKZ7iac07ZbvDvViSUuNyzzrN81FgqkQ==",
"requires": {
"merge-options": "^3.0.4"
}
},
"@react-native-community/async-storage": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.12.1.tgz",
"integrity": "sha512-70WGaH3PKYASi4BThuEEKMkyAgE9k7VytBqmgPRx3MzJx9/MkspwqJGmn3QLCgHLIFUgF1pit2mWICbRJ3T3lg==",
"requires": {
"deep-assign": "^3.0.0"
}
},
"@react-native-community/cli-debugger-ui": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-5.0.1.tgz",
@ -1456,6 +1472,11 @@ @@ -1456,6 +1472,11 @@
"integrity": "sha512-W/J0fNYVO01tioHjvYWQ9m6RgndVtbElzYozBq1ZPrHO/iCzlqoySHl4gO/fpCl9QEFjvJfjPgtPMTMlsoq5DQ==",
"dev": true
},
"@react-native-community/netinfo": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-6.0.0.tgz",
"integrity": "sha512-Z9M8VGcF2IZVOo2x+oUStvpCW/8HjIRi4+iQCu5n+PhC7OqCQX58KYAzdBr///alIfRXiu6oMb+lK+rXQH1FvQ=="
},
"@react-native/assets": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
@ -2066,6 +2087,14 @@ @@ -2066,6 +2087,14 @@
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"babel-core": {
"version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@ -2393,6 +2422,16 @@ @@ -2393,6 +2422,16 @@
"unset-value": "^1.0.0"
}
},
"cachios": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cachios/-/cachios-3.0.0.tgz",
"integrity": "sha512-DLvbmAhX6r3n/bOdcIcF+mMnFwuIK5uuf7R2piU5eQeWymWSncxy3aQjb5apJt08jelEwA5IOf4QximSKiAeiw==",
"requires": {
"axios": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0",
"node-cache": "^4.1.1 || ^5.0.0",
"object-hash": "^2.0.0"
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@ -2797,6 +2836,14 @@ @@ -2797,6 +2836,14 @@
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
"deep-assign": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-3.0.0.tgz",
"integrity": "sha512-YX2i9XjJ7h5q/aQ/IM9PEwEnDqETAIYbggmdDB3HLTlSgo1CxPsj6pvhPG68rq6SVE0+p+6Ywsm5fTYNrYtBWw==",
"requires": {
"is-obj": "^1.0.0"
}
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@ -3771,6 +3818,11 @@ @@ -3771,6 +3818,11 @@
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz",
"integrity": "sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg=="
},
"follow-redirects": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
"integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA=="
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@ -4365,6 +4417,16 @@ @@ -4365,6 +4417,16 @@
"integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==",
"dev": true
},
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
},
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@ -5584,6 +5646,14 @@ @@ -5584,6 +5646,14 @@
"object-visit": "^1.0.0"
}
},
"merge-options": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
"requires": {
"is-plain-obj": "^2.1.0"
}
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -6045,6 +6115,21 @@ @@ -6045,6 +6115,21 @@
"resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz",
"integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
},
"node-cache": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz",
"integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==",
"requires": {
"clone": "2.x"
},
"dependencies": {
"clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
}
}
},
"node-dir": {
"version": "0.1.17",
"resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
@ -6214,6 +6299,11 @@ @@ -6214,6 +6299,11 @@
}
}
},
"object-hash": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
},
"object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
@ -6862,6 +6952,14 @@ @@ -6862,6 +6952,14 @@
"nullthrows": "^1.1.1"
}
},
"react-native-expire-storage": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/react-native-expire-storage/-/react-native-expire-storage-0.0.3.tgz",
"integrity": "sha512-JFaAe6nOJ7HfoIVXl6rLnqUgQfmf2Mf58ITAQeYDdlo6I+u0coG8o8QIMnK8I9CoZZ7ym+W1CtVWNpaWWSsw6A==",
"requires": {
"@react-native-community/async-storage": "^1.6.2"
}
},
"react-native-masked-text": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/react-native-masked-text/-/react-native-masked-text-1.13.0.tgz",

5
package.json

@ -11,11 +11,16 @@ @@ -11,11 +11,16 @@
"pod": "cd ./ios && pod install && cd ../"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.15.6",
"@react-native-community/netinfo": "^6.0.0",
"axios": "^0.21.1",
"cachios": "^3.0.0",
"jet-tools": "^1.1.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"react": "17.0.1",
"react-native": "0.64.2",
"react-native-expire-storage": "0.0.3",
"react-native-masked-text": "^1.13.0",
"react-native-raw-bottom-sheet": "^2.2.0",
"react-native-splash-screen": "^3.2.0",

60
src/api/http.decorstors.ts

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import { AxiosRequestConfig, AxiosResponse } from 'axios'
import { NetworkService } from '@/services'
import { ApiResponse } from './interfaces'
const PREFIX = '@http-offline'
const getAsyncStorageKey = key => `${PREFIX}/${key}`
const setToStorage = async (key: string, data: unknown) => {
await AsyncStorage.setItem(getAsyncStorageKey(key), JSON.stringify(data))
}
const getFromStorage = async (key: string) => {
try {
const data = await AsyncStorage.getItem(getAsyncStorageKey(key))
return JSON.parse(data)
} catch (e) {
return null
}
}
export const OfflineDecorator = async <T>(
requestCall: () => ApiResponse<T>,
key: string,
): ApiResponse<T> => {
if (NetworkService.getInternetConnection()) {
const response: AxiosResponse<T> = await requestCall()
setToStorage(key, response.data)
return response
} else {
const data = await getFromStorage(key)
return {
data,
status: 200,
statusText: 'Ok',
headers: {},
config: null,
}
}
}
export const generateKeyFromRequest = (
url: string,
params?: AxiosRequestConfig,
) => {
let result = url
if (params) {
if (params.params && Object.keys(params.params).length) {
const keys = Object.keys(params.params)
const toResult: string[] = []
keys.map((it: string) =>
toResult.push(`${it}=${JSON.stringify(params.params[it])}`),
)
toResult.sort()
result = `${url}?${toResult.join('&')}`
}
}
return result
}

94
src/api/http.service.ts

@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import cachios from 'cachios'
import { config } from '@/config'
import { GlobalContainerService } from '@/services'
import Storage from 'react-native-expire-storage'
const store = () => GlobalContainerService.getFromGlobalContainer('store')
const getDispatchSaveTokenPair = () =>
GlobalContainerService.getFromGlobalContainer('dispatchSaveTokenPair')
const axiosInstance = axios.create({
baseURL: config.baseUrl,
headers: {
'Content-Type': 'application/json',
},
timeout: 180000,
})
axiosInstance.interceptors.request.use((config: any) => {
const token = store().getState().auth.accessToken
if (token) {
config.headers['authorization'] = `Bearer ${token}`
}
return config
})
const cachiosInstance = cachios.create(axiosInstance)
cachiosInstance.cache = {
get: async (cacheKey: string) => {
const res = await Storage.getItem(cacheKey)
return res ? res : undefined
},
set: async (cacheKey: string, cacheValue: any, ttl: number) => {
await Storage.setItem(cacheKey, cacheValue, ttl)
},
}
const requestAccessToken = async () => {
const response = await axiosInstance.post('/app/auth/reset-token', {
refreshToken: store().getState().auth.refreshToken,
})
getDispatchSaveTokenPair()({
accessToken: response.data.accessToken,
})
}
const request = async <T>(func: Function): Promise<AxiosResponse<T>> => {
try {
let response = await func()
return response as any as AxiosResponse
} catch (e) {
if (e.response.status === 401) {
await requestAccessToken()
return (await func()) as any as AxiosResponse
}
throw e
}
}
export interface ICacheRequestConfig extends AxiosRequestConfig {
ttl?: number
force?: boolean
needCache?: true
}
interface INonCacheRequestConfig extends AxiosRequestConfig {
needCache?: false
}
type GetRequstConfig = ICacheRequestConfig | INonCacheRequestConfig
const api = {
get: <T>(url: string, params?: GetRequstConfig) => {
if (params && params.needCache) {
if (!params.ttl) params.ttl = 60 * 60 * 5
return request<T>(() => cachiosInstance.get(url, params))
} else {
return request<T>(() => axiosInstance.get<T>(url, params))
}
},
post: <T>(url: string, data: any, params?: AxiosRequestConfig) =>
request<T>(() => axiosInstance.post<T>(url, data, params)),
put: <T>(url: string, data: any, params?: AxiosRequestConfig) =>
request<T>(() => axiosInstance.put<T>(url, data, params)),
patch: <T>(url: string, data: any, params?: AxiosRequestConfig) =>
request<T>(() => axiosInstance.patch<T>(url, data, params)),
delete: <T>(url: string, params?: AxiosRequestConfig) =>
request<T>(() => axiosInstance.delete<T>(url, params)),
}
export default api

3
src/api/interfaces/api-helpers.interfaces.ts

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
import { AxiosResponse } from 'axios'
export type ApiResponse<T> = Promise<AxiosResponse<T>>

1
src/api/interfaces/index.ts

@ -0,0 +1 @@ @@ -0,0 +1 @@
export * from './api-helpers.interfaces'

4
src/config/index.ts

@ -2,7 +2,9 @@ import {fonts} from './fonts'; @@ -2,7 +2,9 @@ import {fonts} from './fonts';
/**
* Dev
*/
export const dymanicConfig = {};
export const dymanicConfig = {
baseUrl: 'http://localhost:3000/app/',
};
// /**
// * Prod

18
src/services/global-container.service.ts

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
const globalData: {
store?: any
internetConnect?: boolean
} = {
store: null,
internetConnect: true,
}
const setToGlobalContainer = (key: string, value: any) => {
globalData[key] = value
}
const getFromGlobalContainer = (key: string) => globalData[key]
export const GlobalContainerService = {
setToGlobalContainer,
getFromGlobalContainer,
}

2
src/services/index.ts

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
export * from './global-container.service'
export * from './network.service'

19
src/services/network.service.ts

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
import NetInfo from '@react-native-community/netinfo'
const localData = {
internerIsConnected: true,
}
const init = () => {
const unsubscribe = NetInfo.addEventListener(state => {
localData.internerIsConnected = state.isConnected
})
unsubscribe()
}
const getInternetConnection = () => localData.internerIsConnected
export const NetworkService = {
init,
getInternetConnection,
}
Loading…
Cancel
Save