Last active
July 28, 2023 20:29
-
-
Save SavinaRoja/a434844c51cc62b3e3b86addad58f13e to your computer and use it in GitHub Desktop.
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
// Code sample demonstrating use of Rust-style Result for an API Service in Angular + Typescript | |
// Posted: 2023-07-24 | |
// Paul Barton | |
// Released to the public domain | |
import { Injectable } from '@angular/core'; | |
import { environment } from '../environments/environment'; | |
import { | |
HttpClient, | |
HttpErrorResponse, | |
HttpParams, | |
HttpResponse, | |
} from '@angular/common/http'; | |
import { catchError, map, Observable, of } from 'rxjs'; | |
export enum ResultType { | |
Ok, | |
Err, | |
} | |
export type Ok<T> = { | |
type: ResultType.Ok; | |
value: T; | |
}; | |
export type Err<E> = { | |
type: ResultType.Err; | |
error: E; | |
}; | |
export type Result<T, E> = Ok<T> | Err<E>; | |
export enum CreateUserError { | |
EmailAlreadyExists, | |
Other, | |
} | |
export interface NewUser { | |
email: string; | |
name: string; | |
age: number; | |
} | |
export interface User { | |
id: number; | |
email: string; | |
name: string; | |
age: number; | |
} | |
@Injectable() | |
export class ApiService { | |
constructor(private http: HttpClient) {} | |
createUser(newUser: NewUser): Observable<Result<User, CreateUserError>> { | |
const uri = environment.backend_uri + `users/create`; | |
return this.http.post<any>(uri, newUser, { observe: 'response' }) | |
.pipe( | |
// This handles the conversion from HttpResponse to Result. | |
// It needs to come before the catchError. | |
map((data: HttpResponse<any>): Ok<User> => { | |
return { type: ResultType.Ok, value: data.body }; | |
}) | |
) | |
.pipe( | |
// This should be the last thing to happen in the pipeline | |
catchError( | |
( | |
err: HttpErrorResponse, | |
caught: Observable<any> | |
): Observable<Err<CreateUserError>> => { | |
if (err.status === 400 && err.error.detail === 'Invalid email') { | |
return of<Err<CreateUserError>>( | |
{ | |
type: ResultType.Err, | |
error: CreateUserError.EmailAreadyExists, | |
} | |
) | |
} else { | |
return of<Err<CreateUserError>>( | |
{ | |
type: ResultType.Err, | |
error: CreateUserError.Other, | |
} | |
) | |
} | |
} | |
) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment