Created
December 28, 2020 12:46
-
-
Save hadynz/7ff18af7049344c1d42a019ccf0d0eea to your computer and use it in GitHub Desktop.
A Strapi repository that will share header tokens across multiple instances
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios, { | |
AxiosInstance, | |
AxiosRequestConfig, | |
AxiosResponse, | |
Method, | |
} from "axios"; | |
import Cookies from "js-cookie"; | |
import qs from "qs"; | |
export interface Authentication { | |
user: any; | |
jwt: string; | |
} | |
export type Provider = "google"; | |
export interface ProviderToken { | |
access_token?: string; | |
code?: string; | |
oauth_token?: string; | |
} | |
export interface CookieConfig { | |
key: string; | |
options: object; | |
} | |
export interface LocalStorageConfig { | |
key: string; | |
} | |
export interface StoreConfig { | |
cookie?: CookieConfig | false; | |
localStorage?: LocalStorageConfig | false; | |
} | |
export default class StrapiRepository { | |
public axios: AxiosInstance; | |
public storeConfig: StoreConfig; | |
/** | |
* Default constructor. | |
* @param baseURL Your Strapi host. | |
* @param axiosConfig Extend Axios configuration. | |
*/ | |
constructor( | |
baseURL?: string, | |
storeConfig?: StoreConfig, | |
requestConfig?: AxiosRequestConfig | |
) { | |
this.axios = axios.create({ | |
baseURL, | |
paramsSerializer: qs.stringify, | |
...requestConfig, | |
}); | |
this.storeConfig = { | |
cookie: { | |
key: "jwt", | |
options: { | |
path: "/", | |
}, | |
}, | |
localStorage: { | |
key: "jwt", | |
}, | |
...storeConfig, | |
}; | |
// On every request, attempt to attach any existing bearer tokens | |
this.axios.interceptors.request.use((config) => { | |
const token = this.getToken(); | |
if (token) { | |
config.headers.Authorization = token ? `Bearer ${token}` : ""; | |
} | |
return config; | |
}); | |
const existingToken = this.getToken(); | |
if (existingToken) { | |
this.setToken(existingToken, true); | |
} | |
} | |
/** | |
* Axios request | |
* @param method Request method | |
* @param url Server URL | |
* @param requestConfig Custom Axios config | |
*/ | |
public async request<T>( | |
method: Method, | |
url: string, | |
requestConfig?: AxiosRequestConfig | |
): Promise<T> { | |
try { | |
const response: AxiosResponse = await this.axios.request({ | |
method, | |
url, | |
...requestConfig, | |
}); | |
return response.data as T; | |
} catch (error) { | |
if (error.response) { | |
throw error.response.data; | |
} else { | |
throw error; | |
} | |
} | |
} | |
/** | |
* Register a new user. | |
* @returns Authentication User token and profile | |
*/ | |
public async register( | |
email: string, | |
password: string | |
): Promise<Authentication> { | |
this.clearToken(); | |
const authentication: Authentication = await this.request( | |
"post", | |
"/auth/local/register", | |
{ | |
data: { | |
email, | |
username: email, | |
password, | |
}, | |
} | |
); | |
this.setToken(authentication.jwt); | |
return authentication; | |
} | |
/** | |
* Login by getting an authentication token. | |
* @param identifier Can either be an email or a username. | |
* @param password | |
* @returns Authentication User token and profile | |
*/ | |
public async login( | |
identifier: string, | |
password: string | |
): Promise<Authentication> { | |
this.clearToken(); | |
const authentication: Authentication = await this.request( | |
"post", | |
"/auth/local", | |
{ | |
data: { | |
identifier, | |
password, | |
}, | |
} | |
); | |
this.setToken(authentication.jwt); | |
return authentication; | |
} | |
/** | |
* Sends an email to a user with the link of your reset password page. | |
* This link contains an URL param code which is required to reset user password. | |
* Received link url format https://my-domain.com/rest-password?code=privateCode. | |
* @param email | |
* @param url Link that user will receive. | |
*/ | |
public async forgotPassword(email: string, url: string): Promise<void> { | |
this.clearToken(); | |
await this.request("post", "/auth/forgot-password", { | |
data: { | |
email, | |
url, | |
}, | |
}); | |
} | |
/** | |
* Reset the user password. | |
* @param code Is the url params received from the email link (see forgot password). | |
* @param password | |
* @param passwordConfirmation | |
*/ | |
public async resetPassword( | |
code: string, | |
password: string, | |
passwordConfirmation: string | |
): Promise<void> { | |
this.clearToken(); | |
await this.request("post", "/auth/reset-password", { | |
data: { | |
code, | |
password, | |
passwordConfirmation, | |
}, | |
}); | |
} | |
/** | |
* Retrieve the connect provider URL | |
* @param provider | |
*/ | |
public getProviderAuthenticationUrl(provider: Provider): string { | |
return `${this.axios.defaults.baseURL}/connect/${provider}`; | |
} | |
/** | |
* Authenticate the user with the token present on the URL (for browser) or in `params` (on Node.js) | |
* @param provider | |
* @param params | |
*/ | |
public async authenticateProvider( | |
provider: Provider, | |
params?: ProviderToken | |
): Promise<Authentication> { | |
this.clearToken(); | |
// Handling browser query | |
if (this.isBrowser()) { | |
params = qs.parse(window.location.search, { ignoreQueryPrefix: true }); | |
} | |
const authentication: Authentication = await this.request( | |
"get", | |
`/auth/${provider}/callback`, | |
{ | |
params, | |
} | |
); | |
this.setToken(authentication.jwt); | |
return authentication; | |
} | |
/** | |
* List entries | |
* @param contentTypePluralized | |
* @param params Filter and order queries. | |
*/ | |
public getEntries<T>( | |
contentTypePluralized: string, | |
params?: AxiosRequestConfig["params"] | |
): Promise<T[]> { | |
return this.request("get", `/${contentTypePluralized}`, { | |
params, | |
}); | |
} | |
/** | |
* Get the total count of entries with the provided criteria | |
* @param contentType | |
* @param params Filter and order queries. | |
*/ | |
public getEntryCount( | |
contentType: string, | |
params?: AxiosRequestConfig["params"] | |
): Promise<object[]> { | |
return this.request("get", `/${contentType}/count`, { | |
params, | |
}); | |
} | |
/** | |
* Get a specific entry | |
* @param contentTypePluralized Type of entry pluralized | |
* @param id ID of entry | |
*/ | |
public getEntry<T>( | |
contentTypePluralized: string, | |
id?: string, | |
params?: AxiosRequestConfig["params"] | |
): Promise<T> { | |
const path = id | |
? `/${contentTypePluralized}/${id}` | |
: `/${contentTypePluralized}`; | |
return this.request<T>("get", path, { | |
params, | |
}); | |
} | |
/** | |
* Create data | |
* @param contentTypePluralized Type of entry pluralized | |
* @param data New entry | |
*/ | |
public createEntry( | |
contentTypePluralized: string, | |
data: AxiosRequestConfig["data"] | |
): Promise<object> { | |
return this.request("post", `/${contentTypePluralized}`, { | |
data, | |
}); | |
} | |
/** | |
* Update data | |
* @param contentTypePluralized Type of entry pluralized | |
* @param id ID of entry | |
* @param data | |
*/ | |
public updateEntry( | |
contentTypePluralized: string, | |
id: string, | |
data: AxiosRequestConfig["data"] | |
): Promise<object> { | |
return this.request("put", `/${contentTypePluralized}/${id}`, { | |
data, | |
}); | |
} | |
/** | |
* Delete an entry | |
* @param contentTypePluralized Type of entry pluralized | |
* @param id ID of entry | |
*/ | |
public deleteEntry( | |
contentTypePluralized: string, | |
id: string | number | |
): Promise<object> { | |
return this.request("delete", `/${contentTypePluralized}/${id}`); | |
} | |
/** | |
* Search for files | |
* @param query Keywords | |
*/ | |
public searchFiles(query: string): Promise<object[]> { | |
return this.request("get", `/upload/search/${decodeURIComponent(query)}`); | |
} | |
/** | |
* Get files | |
* @param params Filter and order queries | |
* @returns Object[] Files data | |
*/ | |
public getFiles(params?: AxiosRequestConfig["params"]): Promise<object[]> { | |
return this.request("get", "/upload/files", { | |
params, | |
}); | |
} | |
/** | |
* Get file | |
* @param id ID of entry | |
*/ | |
public getFile(id: string): Promise<object> { | |
return this.request("get", `/upload/files/${id}`); | |
} | |
/** | |
* Upload files | |
* | |
* ### Browser example | |
* ```js | |
* const form = new FormData(); | |
* form.append('files', fileInputElement.files[0], 'file-name.ext'); | |
* form.append('files', fileInputElement.files[1], 'file-2-name.ext'); | |
* const files = await strapi.upload(form); | |
* ``` | |
* | |
* ### Node.js example | |
* ```js | |
* const FormData = require('form-data'); | |
* const fs = require('fs'); | |
* const form = new FormData(); | |
* form.append('files', fs.createReadStream('./file-name.ext'), 'file-name.ext'); | |
* const files = await strapi.upload(form, { | |
* headers: form.getHeaders() | |
* }); | |
* ``` | |
* | |
* @param data FormData | |
* @param requestConfig | |
*/ | |
public upload( | |
data: FormData, | |
requestConfig?: AxiosRequestConfig | |
): Promise<object> { | |
return this.request("post", "/upload", { | |
data, | |
...requestConfig, | |
}); | |
} | |
public getToken(): string | null { | |
if (this.isBrowser()) { | |
let existingToken; | |
if (this.storeConfig.cookie) { | |
existingToken = Cookies.get(this.storeConfig.cookie.key); | |
} else if (this.storeConfig.localStorage) { | |
existingToken = JSON.parse( | |
window.localStorage.getItem( | |
this.storeConfig.localStorage.key | |
) as string | |
); | |
} | |
return existingToken; | |
} | |
return null; | |
} | |
/** | |
* Set token on Axios configuration | |
* @param token Retrieved by register or login | |
*/ | |
public setToken(token: string, comesFromStorage?: boolean): void { | |
this.axios.defaults.headers.common.Authorization = "Bearer " + token; | |
if (this.isBrowser() && !comesFromStorage) { | |
if (this.storeConfig.localStorage) { | |
window.localStorage.setItem( | |
this.storeConfig.localStorage.key, | |
JSON.stringify(token) | |
); | |
} | |
if (this.storeConfig.cookie) { | |
Cookies.set( | |
this.storeConfig.cookie.key, | |
token, | |
this.storeConfig.cookie.options | |
); | |
} | |
} | |
} | |
/** | |
* Remove token from Axios configuration | |
*/ | |
public clearToken(): void { | |
delete this.axios.defaults.headers.common.Authorization; | |
if (this.isBrowser()) { | |
if (this.storeConfig.localStorage) { | |
window.localStorage.removeItem(this.storeConfig.localStorage.key); | |
} | |
if (this.storeConfig.cookie) { | |
Cookies.remove( | |
this.storeConfig.cookie.key, | |
this.storeConfig.cookie.options | |
); | |
} | |
} | |
} | |
/** | |
* Check if it runs on browser | |
*/ | |
private isBrowser(): boolean { | |
return typeof window !== "undefined"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment