Created
July 31, 2017 14:43
-
-
Save soyuka/c2e89ebf3c7a33f8d059c567aefd471c to your computer and use it in GitHub Desktop.
RxRest in an angular / api-platform context using jsonld and hydra
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 { NgModule, Component, OnInit } from '@angular/core' | |
import { AngularRxRest, AngularRxRestConfiguration } from './rxrest' | |
@Component({ | |
selector: 'prefix-main', | |
template: '<prefix-foo></prefix-foo>' | |
}) | |
export class MainComponent implements OnInit { | |
loading: boolean = false | |
loggedIn: boolean = false | |
constructor( | |
public user: User, | |
private rxrestConfiguration: RxRestConfiguration, | |
) { | |
this.loggedIn = !!this.user.token | |
} | |
ngOnInit() { | |
let pending = 0 | |
const pendingRequest = (add = true) => { | |
pending = add ? pending + 1 : pending - 1 | |
if (pending > 0 && this.loading === false) { | |
this.loading = true | |
} else if (pending === 0) { | |
this.loading = false | |
} | |
} | |
const user = this.user | |
this.rxrestConfiguration.abortCallback = function(req: Request) { | |
pendingRequest(false) | |
} | |
function addHeaders(request: Request) { | |
const headers = (request.headers as Headers) | |
headers.set('Content-Type', 'application/ld+json') | |
headers.set('Accept', 'application/ld+json') | |
headers.set('Authorization', 'Bearer ' + user.token) | |
pendingRequest() | |
return request | |
} | |
this.rxrestConfiguration.requestInterceptors.push(addHeaders) | |
this.rxrestConfiguration.errorInterceptors.push((response: Response) => { | |
this.logger.error(`Request error on ${response.url}, got status ${response.status}`, response) | |
if (response.status < 500) { | |
return | |
} | |
this.messages.add('Une erreur critique est survenue !', 'alert') | |
return response | |
}) | |
} | |
} | |
@NgModule({ | |
bootstrap: [RootComponent], | |
declarations: [ | |
MainComponent, | |
UsageComponent | |
], | |
providers: [ | |
User, | |
{provide: RxRest, useClass: AngularRxRest}, | |
{provide: RxRestConfiguration, useClass: AngularRxRestConfiguration}, | |
], | |
imports: [ | |
BrowserModule, | |
FormsModule, | |
// ... | |
] | |
}) | |
export class RootModule { | |
//DO NOT REMOVE BECAUSE IT CALLS THE CONSTRUCTOR WHICH SETS UP RXREST | |
constructor(private rxrest: RxRest) { | |
console.log('RxRest up', this.rxrest) | |
} | |
} |
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 {RxRestItem} from 'rxrest' | |
import * as moment from 'moment-timezone' | |
import {environment} from '../environments/environment' | |
function unpopulateHref(e: any) { | |
if (Array.isArray(e)) { | |
for (let i = 0; i < e.length; i++) { | |
unpopulateHref(e[i]) | |
} | |
return | |
} | |
if (typeof e !== 'object' || !e) { | |
return | |
} | |
delete e.id | |
delete e.href | |
for (const i in e) { | |
if (i in e) { | |
if (e[i] instanceof Date) { | |
e[i] = moment(e[i]).format(environment.phpDateTimeFormat) | |
} else if (e[i] && moment.isMoment(e[i])) { | |
e[i] = e[i].format(environment.phpDateTimeFormat) | |
} | |
unpopulateHref(e[i]) | |
} | |
} | |
} | |
export function requestBodyHandler(body: any): string|FormData|URLSearchParams { | |
if (!body) { | |
return undefined | |
} | |
if (body instanceof FormData || body instanceof URLSearchParams) { | |
return body | |
} | |
if (!(body instanceof RxRestItem)) { | |
return JSON.stringify(body) | |
} | |
body = body.plain() | |
unpopulateHref(body) | |
return JSON.stringify(body) | |
} |
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 * as moment from 'moment-timezone' | |
/** | |
* Transform data | |
*/ | |
function transformData(data: any) { | |
if (!data) { | |
return data | |
} | |
if (data['@id']) { | |
//@TODO through configuration for prefix /api | |
data.href = data['@id'].replace('/api', '') | |
const id = data['@id'].split('/') | |
data.id = id[id.length - 1] | |
} | |
//data format | |
for (const i in data) { | |
if (~['@id', 'href'].indexOf(i)) { | |
continue | |
} | |
// tslint:disable-next-line:triple-equals | |
if (parseFloat(data[i]) == data[i] || i.indexOf('@') === 0) { | |
continue | |
} | |
if (typeof data[i] === 'boolean') { | |
continue | |
} | |
if (typeof data[i] === 'string') { | |
try { | |
const date = moment(data[i], moment.ISO_8601, true) | |
if (date.isValid()) { | |
data[i] = date | |
continue | |
} | |
} catch (e) {} | |
} | |
if (data[i] instanceof Object && !Array.isArray(data[i])) { | |
transformData(data[i]) | |
} else if (Array.isArray(data[i])) { | |
data[i].forEach((e: any) => transformData(e)) | |
} | |
} | |
return data | |
} | |
export function responseBodyHandler(body: any): Promise<any> { | |
return body.text() | |
.then(text => { | |
if (!text) { | |
return null | |
} | |
text = JSON.parse(text) | |
const metadata = text['hydra:view'] | |
if (text['hydra:member']) { | |
text = text['hydra:member'].map(e => transformData(e)) | |
} else { | |
text = transformData(text) | |
} | |
return {body: text, metadata: metadata} | |
}) | |
} |
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 { RxRest, RxRestConfiguration } from 'rxrest' | |
import { Injectable } from '@angular/core' | |
import { requestBodyHandler } from './requestBodyHandler' | |
import { responseBodyHandler } from './responseBodyHandler' | |
import { environment } from '../../../environments/environment' | |
@Injectable() | |
export class AngularRxRestConfiguration extends RxRestConfiguration { | |
constructor() { | |
super() | |
//@TODO through configuration for prefix /api | |
this.baseURL = environment.baseURL + '/api' | |
this.requestBodyHandler = requestBodyHandler | |
this.responseBodyHandler = responseBodyHandler | |
} | |
} | |
@Injectable() | |
export class AngularRxRest extends RxRest { | |
constructor(config: RxRestConfiguration) { | |
super(config) | |
} | |
} |
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 { Component, OnInit } from '@angular/core' | |
import { RxRest } from 'rxrest' | |
@Component({ | |
selector: 'prefix-foo', | |
template: '<ul><li *ngFor="let foo of foos | async">{{foo.id}}</li></ul>' | |
}) | |
export class UsageComponent implements OnInit { | |
constructor(private rxrest: RxRest) {} | |
ngOnInit() { | |
this.foos = Observable.from(this.rxrest<Foo>.all('foos', true).get()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment