Skip to content

Commit

Permalink
Merge pull request #1 from providerx/documentation
Browse files Browse the repository at this point in the history
Finished error handling documentation
  • Loading branch information
srinivasayush authored Apr 3, 2021
2 parents 99ccc7d + 5c9b358 commit 5f90f96
Show file tree
Hide file tree
Showing 19 changed files with 139 additions and 356 deletions.
17 changes: 16 additions & 1 deletion react-providerx/src/models/providerReference.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
export type ProviderReference = {
import { throwError } from "rxjs"

export class ProviderReference {
executionError?: any

error(error: any) {
this.executionError = error
return throwError(error)
}
}

export class AutoDisposeProviderReference extends ProviderReference {
maintainState: boolean
constructor(maintainState?: boolean) {
super()
this.maintainState = maintainState ?? true
}
}
25 changes: 11 additions & 14 deletions react-providerx/src/observableProvider/autoDispose.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { BehaviorSubject, from, Observable, Subscription } from "rxjs";
import { ProviderReference } from "../models/providerReference";
import { AutoDisposeProviderReference } from "../models/providerReference";
import { BaseObservableProvider } from "./base";

export class AutoDisposeObservableProvider<T> extends BaseObservableProvider<T> {
_valueSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
_errorSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
observableCreator
ref: ProviderReference
ref: AutoDisposeProviderReference
_observable$: Observable<T>
_internalSubscription?: Subscription

constructor(observableCreator: (ref: ProviderReference) => Observable<T>) {
constructor(observableCreator: (ref: AutoDisposeProviderReference) => Observable<T>) {
super(observableCreator)
this.observableCreator = observableCreator
this.ref = {
maintainState: true
}
this.ref = new AutoDisposeProviderReference(false)
this._observable$ = new Observable()
this._valueSubject$ = new BehaviorSubject(undefined)
this._errorSubject$ = new BehaviorSubject(undefined)
Expand All @@ -26,22 +24,21 @@ export class AutoDisposeObservableProvider<T> extends BaseObservableProvider<T>
}

_compute() {
this.ref = {
...this.ref,
maintainState: true
}
this.ref = new AutoDisposeProviderReference(false)
this._observable$ = this.observableCreator(this.ref)
if(this._observable$ === null) {
throw 'observableCreator cannot return null. It must return an instance of Observable'
}
this._internalSubscription = this._observable$.subscribe(
(val: T) => {
this._valueSubject$.next(val as any)
this._errorSubject$.next(null as any)
if(this.ref.executionError !== undefined) {
this._advanceError(this.ref.executionError)
return
}
this._advanceValue(val)
},
(error: any) => {
this._errorSubject$.next(error as any)
this._valueSubject$.next(null as any)
this._advanceError(error)
}
)
}
Expand Down
13 changes: 13 additions & 0 deletions react-providerx/src/observableProvider/base.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { BehaviorSubject, Observable, Subscription } from 'rxjs'
import { ProviderReference } from '../models/providerReference'

export abstract class BaseObservableProvider<T> {
_valueSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
_errorSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
observableCreator
ref: ProviderReference
_observable$: Observable<T>
_internalSubscription?: Subscription

constructor(observableCreator: any) {
this.observableCreator = observableCreator
this._observable$ = new Observable()
this.ref = new ProviderReference()
this._valueSubject$ = new BehaviorSubject(undefined)
this._errorSubject$ = new BehaviorSubject(undefined)
}
Expand All @@ -25,6 +28,16 @@ export abstract class BaseObservableProvider<T> {
return this._errorSubject$.asObservable() as Observable<T>
}

_advanceValue(value: T) {
this._valueSubject$.next(value as any)
this._errorSubject$.next(null as any)
}

_advanceError(error: any) {
this._errorSubject$.next(error)
this._valueSubject$.next(null as any)
}

subscribe(dataCallback: (value: T) => void, errorCallback: (error: any) => void): Subscription[] {
this._compute()
return [this.observable.subscribe(dataCallback), this.errorObservable.subscribe(errorCallback)]
Expand Down
23 changes: 14 additions & 9 deletions react-providerx/src/observableProvider/index.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,46 @@
import { BehaviorSubject, Observable, Subscription } from 'rxjs'
import { ProviderReference } from '../models/providerReference'
import { ProviderReference, AutoDisposeProviderReference } from '../models/providerReference'
import { AutoDisposeObservableProvider } from './autoDispose'
import { BaseObservableProvider } from './base'


export class ObservableProvider<T> extends BaseObservableProvider<T> {
_valueSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
_errorSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
observableCreator
observableCreator: (ref: ProviderReference) => Observable<T>
_observable$: Observable<T>
ref: ProviderReference
_internalSubscription?: Subscription

constructor(observableCreator: () => Observable<T>) {
constructor(observableCreator: (ref: ProviderReference) => Observable<T>) {
super(observableCreator)
this.observableCreator = observableCreator
this._observable$ = new Observable()
this.ref = new ProviderReference()
this._valueSubject$ = new BehaviorSubject(undefined)
this._errorSubject$ = new BehaviorSubject(undefined)
}

static autoDispose<S>(observableCreator: (ref: ProviderReference) => Observable<S>) {
static autoDispose<S>(observableCreator: (ref: AutoDisposeProviderReference) => Observable<S>) {
return new AutoDisposeObservableProvider<S>(observableCreator);
}

_compute() {
this._observable$ = this.observableCreator()
this.ref = new ProviderReference()
this._observable$ = this.observableCreator(this.ref)
if(this._observable$ === null) {
throw 'observableCreator cannot return null. It must return an instance of Observable'
}
this._internalSubscription = this._observable$.subscribe(
(val: T) => {
this._valueSubject$.next(val as any)
this._errorSubject$.next(null as any)
if(this.ref.executionError !== undefined) {
this._advanceError(this.ref.executionError)
return
}
this._advanceValue(val)
},
(error: any) => {
this._errorSubject$.next(error)
this._valueSubject$.next(null as any)
this._advanceError(error)
}
)
}
Expand Down
4 changes: 2 additions & 2 deletions tests/react-providerx-test-app/src/shared/error.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ObservableProvider } from "react-providerx";
import { from, throwError } from "rxjs";
import { from } from "rxjs";
import { catchError } from "rxjs/operators";

export const errorProvider$ = ObservableProvider.autoDispose((ref) => {
Expand All @@ -13,7 +13,7 @@ export const errorProvider$ = ObservableProvider.autoDispose((ref) => {
catchError((error: Error) => {
console.log('there was an error in fetching the api')
ref.maintainState = false
return throwError(error)
return ref.error(error)
}),
)
})
11 changes: 0 additions & 11 deletions website/blog/2019-05-28-hola.md

This file was deleted.

17 changes: 0 additions & 17 deletions website/blog/2019-05-29-hello-world.md

This file was deleted.

13 changes: 0 additions & 13 deletions website/blog/2019-05-30-welcome.md

This file was deleted.

55 changes: 55 additions & 0 deletions website/docs/concepts/error-handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
title: Error Handling
---

For more information about `ObservableProvider`, [read this](/docs/)

## Error Handling
By default, ProviderX will find errors which occur in our `Observable` and send them to our consumers
in our frontend UI

However...

In many situations we may want to handle errors and run code based on them
Let's use the following example:

```typescript
import { from } from 'rxjs'
import { catchError } from 'rxjs/operators'

const provider = ObservableProvider.autoDispose(() => {
const fetchUser = async () => {
const response = await fetch(
'https://jsonplaceholder.typicode.com/users/1'
)
const json = await response.json()
return json
}
const observable = from(fetchUser()).pipe(
catchError((error: any) => {
ref.maintainState = false
return ref.error(error)
}),
)
return observable
})
```
Points to Note:
- We catch the error using `catchError`
- We set `ref.maintainState` to `false` because we do not want the state of the provider to be kept
even after it has no listeners and we want the provider value to be recomputed once again
- We return `ref.error(error)` which tells ProviderX we have an error

:::danger Return your errors!

```typescript
catchError((error: any) => {
ref.maintainState = false
return ref.error(error)
}),
```

***If*** you use `catchError`, make sure to return `ref.error(error)` otherwise
ProviderX will not know that an error has been received.

:::
25 changes: 0 additions & 25 deletions website/docs/create-a-blog-post.md

This file was deleted.

38 changes: 0 additions & 38 deletions website/docs/create-a-document.md

This file was deleted.

45 changes: 0 additions & 45 deletions website/docs/create-a-page.md

This file was deleted.

Loading

0 comments on commit 5f90f96

Please sign in to comment.