Skip to content

Instantly share code, notes, and snippets.

@glemiere
Last active April 10, 2019 18:49
Show Gist options
  • Save glemiere/426e2ada35a775d22a92819122798c5e to your computer and use it in GitHub Desktop.
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
/**********
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