Last active
April 10, 2019 18:49
-
-
Save glemiere/426e2ada35a775d22a92819122798c5e to your computer and use it in GitHub Desktop.
Simple class written in TypeScript to connect a ionic v2+ app to a Sails.js API v0.X (using JWT based auth). Requires SailsJS client : https://sailsjs.com/documentation/reference/web-sockets/socket-client
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
/********** | |
SailsApiCall.ts | |
--------------- | |
Simple class written in TypeScript. | |
Connects a ionic v2+ app to a Sails.js API v0.X (using JWT based auth). | |
--------------- | |
Requires SailsJS client : | |
https://sailsjs.com/documentation/reference/web-sockets/socket-client | |
**********/ | |
import { Injectable } from '@angular/core'; | |
import { Platform } from 'ionic-angular'; | |
import { SpinnerDialog } from '@ionic-native/spinner-dialog'; | |
import { SplashScreen } from '@ionic-native/splash-screen'; | |
import { NativeStorage } from '@ionic-native/native-storage'; | |
import { FileTransfer, FileUploadOptions, FileTransferObject } from '@ionic-native/file-transfer'; | |
import 'rxjs/add/operator/map'; | |
declare var io:any; | |
@Injectable() | |
export class SailsApiCall { | |
private baseUrl :string; | |
private associations :Array<Object>; | |
public token :string; | |
private bearer :string; | |
public socket :Object; | |
public sails :Object; | |
constructor(private platform: Platform, | |
private nativeStorage:NativeStorage, | |
private spinnerDialog: SpinnerDialog, | |
private splashScreen: SplashScreen, | |
private transfer: FileTransfer) { | |
/** Default value for base Url. Can be set using setBaseUrl(url). **/ | |
this.baseUrl = "//api.mydomain.com"; | |
/** Default value for token bearer. Can be set using setBearer(bearer). **/ | |
this.bearer = 'MyBearer'; | |
/** Configuring sails **/ | |
this.socket = io.socket; | |
this.sails = io.sails; | |
this.sails.connect(); | |
// Tell user when the connection to the server has been lost. | |
this.socket.on('disconnect', this.onDisconnect()); | |
// Enable user to interract with UI. | |
this.socket.on('connect', this.onConnect()); | |
// Defines token if not already set. | |
if (!this.token) | |
this.setToken(); | |
} | |
public setBaseUrl(url:string):string { | |
return this.baseUrl = url; | |
} | |
public setBearer(bearer:string):string { | |
return this.bearer = bearer; | |
} | |
private onConnect():void { | |
this.splashScreen.hide(); | |
this.spinnerDialog.hide(); | |
} | |
private onDisconnect():void { | |
this.splashScreen.show(); | |
this.spinnerDialog.show('Attempting to reconnect', 'The connexion to the server has been interrupted. Please, check your internet connexion.', true, { | |
overlayOpacity: 0.8 | |
}); | |
} | |
/* | |
SailsApiCall.uploadMedia | |
Uploads a media (photo or video) to a specified endpoint of the API with user id. | |
*/ | |
public uploadMedia(userId:number, endPoint:string, picUrl:string, fileKey:string, type:string):Promise<any> { | |
let format; | |
let options:FileUploadOptions; | |
// Set file format. | |
type == 'photo' ? format = 'image/jpeg' : format = 'video/mp4'; | |
// Set upload parameters. | |
options = { | |
fileKey: fileKey, | |
fileName: 'default', | |
headers: { | |
Authorization:this.bearer + ' ' + this.token | |
}, | |
httpMethod:'POST', | |
mimeType:format, | |
params:{ | |
id:userId | |
} | |
} | |
// Tell user that the file is being transfered. | |
this.spinnerDialog.show('Sending', 'Please, be patient while your file is getting transfered.', true, { | |
overlayOpacity: 0.8 | |
}); | |
// Uploading the file. | |
return new Promise((resolve, reject) => { | |
this.transfer.create().upload(picUrl, this.baseUrl + endPoint, options) | |
.then((data) => { | |
// Resolving API response and dismissing message. | |
this.spinnerDialog.hide(); | |
resolve(JSON.parse(data.response)) | |
}, (err) => { | |
this.spinnerDialog.hide(); | |
reject(false); | |
}); | |
}); | |
} | |
/* | |
SailsApiCall.put | |
Request the API to UPDATE : | |
- a model entry "what" | |
- with id or query "where" | |
- with the following "data" | |
Example : SailsApiCall.put('Car', 1, {brand: "Honda"}).then... | |
*/ | |
public put(what:string, where:any, data:Object):Promise<any> { | |
let endPoint; | |
//Making sure "where" is a string. | |
if (!where || !isNaN(where)) | |
endPoint = this.getEndPoint(where, what); | |
else | |
endPoint = this.getEndPoint(JSON.stringify(where), what); | |
return new Promise((resolve, reject) => { | |
this.socket.request({ | |
method:'PUT', | |
url: endPoint, | |
data: data, | |
headers:{ | |
Authorization:this.bearer + ' ' + this.token | |
} | |
}, (resData, jwres) =>{ | |
if (jwres.body.name == "Error" || jwres.error || jwres.body.error) | |
reject(jwres.error); | |
else | |
resolve(jwres.body); | |
}); | |
}); | |
} | |
/* | |
SailsApiCall.post | |
Request the API to POST : | |
- a model entry "what" | |
- with the following "data" | |
Example : SailsApiCall.post('Car', {brand: "Honda"}).then... | |
*/ | |
public post(what:string, data:Object):Promise<any> { | |
let endPoint = this.getEndPoint(false, what); | |
let request:any = { | |
method:'POST', | |
url: endPoint, | |
data: data, | |
} | |
if (what !='Auth') { | |
request.headers = { | |
Authorization:this.bearer + ' ' + this.token | |
} | |
} | |
return new Promise((resolve, reject) => { | |
this.socket.request(request, (resData, jwres) =>{ | |
if (jwres.body.name == "Error" || jwres.error || jwres.body.error) | |
reject(jwres.body); | |
else | |
resolve(jwres.body); | |
}); | |
}); | |
} | |
/* | |
SailsApiCall.get | |
Request the API to GET : | |
- a model entry "what" | |
- with id or query "where" | |
Examples : | |
- SailsApiCall.post('Car', {brand: "Honda"}).then... | |
- SailsApiCall.post('Car', 1).then... | |
*/ | |
public get(what:string, where:any):Promise<any> { | |
let endPoint; | |
if (!where || !isNaN(where)) | |
endPoint = this.getEndPoint(where, what); | |
else | |
endPoint = this.getEndPoint(JSON.stringify(where), what); | |
return this.getRequest(endPoint); | |
} | |
/* | |
SailsApiCall.remove | |
Request the API to REMOVE : | |
- a model entry "what" | |
- with id or query "where" | |
- as well as the associated models "associations" | |
Examples : | |
- SailsApiCall.remove('Car', 15, [ | |
{ | |
what: 'CarReviews', | |
where: { | |
carId: 15 | |
} | |
} | |
]).then... | |
- SailsApiCall.remove('Car', 1, null).then... | |
*/ | |
public remove(what:string, where:any, associations:Array<Object>):Promise<any>{ | |
return new Promise((resolve, reject) => { | |
// Get endpoint | |
this.getRemoveEndPoint(where, what).then((removeEndPoint) => { | |
if (associations) { | |
// Removing associatated records | |
this.removeAssociations(associations).then(() => { | |
// Removing main record | |
this.removeRequest(removeEndPoint).then((data) => { | |
resolve(data) | |
}, () => { | |
reject(false); | |
}); | |
}, () => { | |
reject(false); | |
}) | |
} | |
else { | |
// Removing record | |
this.removeRequest(removeEndPoint).then((data) => { | |
resolve(data) | |
}, () => { | |
reject(false); | |
}); | |
} | |
}, (err) => { | |
reject(false); | |
}) | |
}); | |
} | |
/* | |
SailsApiCall.getRemoveEndPoint | |
Finds the record to remove using the provided query (where) and returns the | |
required endpoint. | |
*/ | |
private getRemoveEndPoint(where:any, what:string):Promise<any>{ | |
let endPoint; | |
return new Promise((resolve, reject) => { | |
if (!where || !isNaN(where)){ | |
endPoint = this.getEndPoint(where, what); | |
resolve(endPoint); | |
} | |
else { | |
endPoint = this.getEndPoint(JSON.stringify(where), what); | |
this.getRequest(endPoint).then((result:any) => { | |
if (result[0]){ | |
endPoint = this.getEndPoint(result[0].id, what); | |
resolve(endPoint); | |
} | |
else | |
reject(false); | |
}, (err) => { | |
reject(false); | |
}); | |
} | |
}); | |
} | |
/* | |
SailsApiCall.removeAssociations | |
Finds and removes the associated records. | |
*/ | |
private removeAssociations(associations:Array<Object>):Promise<any>{ | |
let promises_array:Array<any> = []; | |
for (let association of associations) { | |
promises_array.push( | |
new Promise((resolve, reject) => { | |
this.getAssociatedRecords(JSON.stringify(association.where), association.what).then((records) => { | |
this.removeAssociatedRecords(association.what, records).then((success) => { | |
resolve(true); | |
}, (err) => { | |
reject(false); | |
}) | |
}, (err) => { | |
if (err == 'NO_ASSOCIATION') | |
resolve(true); | |
else | |
resolve(false); | |
}); | |
}); | |
) | |
} | |
return Promise.all(promises_array); | |
} | |
/* | |
SailsApiCall.getAssociatedRecords | |
Get the associated records. | |
*/ | |
private getAssociatedRecords(where:any, what:string):Promise<any>{ | |
return new Promise((resolve, reject) => { | |
this.getRequest(this.getEndPoint(where, what)).then((data: any) => { | |
if (data[0]) | |
resolve(data); | |
else | |
reject('NO_ASSOCIATION'); | |
}, () => { | |
reject(false); | |
}) | |
}); | |
} | |
/* | |
SailsApiCall.removeAssociatedRecords | |
Removes the associated records. | |
*/ | |
private removeAssociatedRecords(what:string, records:Object):Promise<any>{ | |
let promises_array:Array<any> = []; | |
for (let record of records) { | |
promises_array.push( | |
new Promise((resolve, reject) => { | |
this.removeRequest(this.getEndPoint(record.id ,what)).then(() => { | |
resolve(true) | |
}, () => { | |
reject(false); | |
}); | |
}) | |
) | |
} | |
return Promise.all(promises_array); | |
} | |
/* | |
SailsApiCall.removeRequest | |
Send a remove request to a given endpoint. | |
*/ | |
private removeRequest(endPoint:string):Promise<any>{ | |
return new Promise((resolve, reject) => { | |
this.socket.request({ | |
method:'DELETE', | |
url: endPoint, | |
headers:{ | |
Authorization:this.bearer + ' ' + this.token | |
} | |
}, (resData, jwres) =>{ | |
if (jwres.body.name == "Error" || jwres.error) | |
reject(false); | |
else | |
resolve(resData); | |
}); | |
}); | |
} | |
/* | |
SailsApiCall.getRequest | |
Send a get request to a given endpoint. | |
*/ | |
private getRequest(endPoint:string):Promise<any> { | |
return new Promise((resolve, reject) => { | |
this.socket.request({ | |
method:'GET', | |
url: endPoint, | |
headers:{ | |
Authorization:this.bearer + ' ' + this.token | |
} | |
}, (resData, jwres) =>{ | |
if (jwres.body.name == "Error" || jwres.error) | |
reject(jwres.error); | |
else | |
resolve(jwres.body); | |
}); | |
}); | |
} | |
/* | |
SailsApiCall.getEndPoint | |
Returns needed API endpoint to achieve the request. | |
*/ | |
private getEndPoint(where:any, what:string):string { | |
//If where is a valid string, then it's a query. | |
if (where && (typeof where === 'string' || where instanceof String)) | |
return ('/api/' + what + '/?where=' + where); | |
// These endpoints are not prefixed by 'api'. | |
else if (what == 'Auth/signin' | |
|| what == 'Auth/signup' | |
|| what == 'Auth/facebook' | |
|| what == 'Auth/google') | |
return ('/' + what); | |
// Endpoint when given "where" is an id. | |
else if (where) | |
return ('/api/' + what + '/' + where); | |
// No valid "where" provided. | |
else if (!isNaN(where)) | |
return ('/api/' + what) | |
} | |
/* | |
SailsApiCall.setToken | |
Retrieves stored token, and set class token. | |
*/ | |
private setToken():void { | |
this.platform.ready().then(() => { | |
this.nativeStorage.getItem('token') | |
.then((data) => { | |
this.token = data | |
}, (error) => { | |
this.setToken(); | |
}); | |
}); | |
} | |
public requestToken():string { | |
return this.token; | |
} | |
/* | |
SailsApiCall.setToken | |
Stores the token in user's device. | |
*/ | |
public storeToken(token:string):Promise<any> { | |
return new Promise((resolve, reject) => { | |
this.nativeStorage.setItem('token', token) | |
.then( | |
() => { | |
this.token = token; | |
resolve(true) | |
}, | |
error => reject(false) | |
); | |
}) | |
} | |
/* | |
SailsApiCall.hasToken | |
Checks if a token exists in storage. | |
*/ | |
public hasToken():Promise<any> { | |
return new Promise(resolve => { | |
this.nativeStorage.getItem('token') | |
.then((data) => { | |
resolve(data); | |
}, | |
error => reject(false) | |
); | |
}); | |
} | |
/* | |
SailsApiCall.isTokenValid | |
Sends a request to see if the token is still valid. | |
*/ | |
public isTokenValid(token:string):Promise<any> { | |
let endPoint = '/api/User' //any endpoint is fine. | |
return new Promise((resolve, reject) => { | |
this.socket.request({ | |
method:'GET', | |
url: endPoint, | |
headers:{ | |
Authorization:this.bearer + ' ' + this.token | |
} | |
}, (resData, jwres) =>{ | |
if (jwres.body.name == "Error" || jwres.error) | |
reject(false); | |
else | |
resolve(true); | |
}); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment