Implementing ETag in Angular 2

Implementing the odata standard which utilizes ETag has presented a challenge for me, particularly with PATCH requests. Each PATCH request requires sending the ETag in the header as If-None-Match. A HTTP status of 200 indicates that the change was successfully applied, while a status of 412 signifies that the data on the server has been modified and needs to be fetched again for merging (which is beyond the scope of this question).

I've managed to create a working solution so far, where adding data and Etag to cache is done in the implementation of the get() method:

export const HEADER_ETAG_MATCH = 'If-None-Match';
export const ODATA_ETAG_PROPERTY = '@odata.etag';
export interface CacheRecordStructure {
    etag: string;
    response: Response;
}
export class CachingService {
    cache: { [key: string]: CacheRecordStructure } = {};
    constructor(private http: Http) { }
    patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        let stream$ = new Subject<Response>();
        this.http[type](url, body, this.addEtagHeader(url, options)).subscribe(response => {
            if (response.status === 412) {
                delete this.cache[url];
                this.get(url, options).subscribe(response2 => {
                    response2.status = 412;
                    stream$.next(response2);
                });
            } else {
                this.cache[url].etag = response.json()[ODATA_ETAG_PROPERTY];
                this.cache[url].response = response;
                stream$.next(response);
            }
        });
        return stream$.asObservable();
    }
}

Question 1: How can I alter this code to use Rx-only without having to define stream$?

Question 2: I would like to throw an error instead of returning status 412. Is it possible to include the newly fetched object from the server along with this error?

Answer №1

To achieve a minimally invasive solution, one approach could involve implementing the use of switchMap. Here is an example implementation:

export const HEADER_ETAG_MATCH = 'If-None-Match';
export const ODATA_ETAG_PROPERTY = '@odata.etag';
export interface CacheRecordStructure {
    etag: string;
    response: Response;
}
export class CachingService {
    cache: { [key: string]: CacheRecordStructure } = {};
    constructor(private http: Http) { }
    patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        return this.http[type](url, body, this.addEtagHeader(url, options))
            .switchMap(response => {
                if (response.status === 412) {
                    delete this.cache[url];
                    return this.get(url, options)
                        .switchMap(response2 => {
                            response2.status = 412;
                            return Observable.throw(response2);
                        });
                } else {
                    this.cache[url].etag = response.json()[ODATA_ETAG_PROPERTY];
                    this.cache[url].response = response;
                    return Observable.of(response);
                }
            });
    }
}

Finally, you can utilize it like this:

myCachingService.patch("myurl...", someBody)
    .subscribe(
        response => console.log(response),
        errorWithNewObj => console.error(errorWithNewObj),
        () => console.info("Done!")
    );

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Anticipating the outcome of various observables within a loop

I'm facing a problem that I can't seem to solve because my knowledge of RxJs is limited. I've set up a file input for users to select an XLSX file (a spreadsheet) in order to import data into the database. Once the user confirms the file, v ...

Combining the `vuex-typex` npm package's `dist/index.js` for optimal performance with Jest testing framework

I initially raised this question as an open issue on GitHub. My experience with Vue.js, Vuex, TypeScript, and vuex-typex has led me to encounter syntax errors during Jest testing. I am relatively new to working with Vue.js, TypeScript, and Jest. It is wo ...

Angular 9: Chart.js: Monochromatic doughnut chart with various shades of a single color

My goal is to display a monochromatic doughnut chart, with each segment shaded in varying tones of the same color. I have all the necessary graph data and just need to implement the color shading. ...

Exploring TypeScript Compiler Options for ensuring code compliance beyond the confines of strict mode

Our goal is to set up TypeScript Compiler (TSC) with a command line option that can identify errors when developers declare class fields using implicit type expressions instead of explicit ones as illustrated below. class Appliance { //Desired coding ...

Error Encountered: Visual Studio cannot locate the file 'COMPUTE_PATHS_ONLY.ts' during the build process

Upon fixing my visual studio 2015, an error was thrown that I haven't encountered before. Error Build: File 'COMPUTE_PATHS_ONLY.ts' not found. I did not add COMPUTE_PATHS_ONLY.ts to my Git repository. The other files in the repo rema ...

`AngularJS Voice Recognition Solutions`

In my quest to implement voice recognition in an AngularJS application I'm developing for Android and Electron, I've encountered some challenges. While I've already discovered a suitable solution for Android using ng-speech-recognition, fin ...

How can I assign a type to an array object by utilizing both the 'Pick' and '&' keywords simultaneously in TypeScript?

As a beginner in TypeScript, I am looking to declare a type for an array object similar to the example below. const temp = [{ id: 0, // number follower_id: 0, // number followee_id: 0, // number created_at: '', // string delete_at: &ap ...

Is there a method to restrict the scope of identical components appearing multiple times on a single page in Angular 7?

I have a scenario where I need to place multiple instances of the same component on a page, but when one of them receives input and refreshes, all other components also refresh. Is there a way to prevent this from happening? <tr *ngFor="let map of imgs ...

Misunderstanding the concept of always being right

Here is a code snippet that raises an error in TypeScript: class Status { constructor(public content: string){} } class Visitor { private status: Status | undefined = undefined; visit(tree: Tree) { if (tree.value > 7) { this.status = new ...

Received corrupted file during blob download in Angular 7

When using Angular 7, I am making an API call by posting the URL file and attempting to download it using the 'saveAs' function from the fileSaver library. The file is successfully downloading, but it appears to be corrupted and cannot be opened. ...

The element is inferred to have an 'any' type due to the inability to use a 'string' type expression to index the 'Palette' type

Encountering an issue: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Palette'. No index signature with a parameter of type 'string' was found on type &ap ...

Utilizing various filters and sorting options on API response within Angular 8

Upon receiving the following API response: [ { "imgPaths":[ "gallery/products/55ccb60cddb4d9bded02accb26827ce4" ], "_id":"5f3e961d65c6d591ba04f3d3", "productName":" ...

angular2 and ionic2 encounter issues when handling requests with observable and promises

I am attempting to trigger an action once a promise request has been resolved, but I'm having trouble figuring out how to achieve this. After doing some research, I learned that Ionic2 storage.get() returns a promise, and I would like to make an HTTP ...

What is the most effective way to utilize getStaticPaths in a dynamic manner within next.js

There is a need to paginate static pages for each of the 3 blog categories, but the problem lies in the variable number of pages and the inability to access which category needs to be fetched in getStaticPaths. The project folder structure appears as foll ...

The jspdf tool tries to cram my extensive data into a single page, resulting in an overcrowded and barely visible PDF document

My PDF generated using Jspdf is being forced to fit in one page, making it difficult to see all the data because there is a huge amount of information present. To view the issue, please visit this link: https://jsfiddle.net/frost000/04qt7gsm/21/ var pdf ...

Exploring the use of generic types in TypeScript interfaces

I have the following two interfaces: export interface TestSchema<S> { data: S; description: string; } export type someType = 'option1' | 'option2'; export interface AnotherInterface { primary: string; secondary: someType; ...

Error in Visual Studio with Angular 2 build: 'Promise' name not found

I recently started exploring Angular2 and followed the instructions provided in this quickstart guide: https://angular.io/guide/quickstart Everything seems to be working well after running npm install, but now I want to work on it within Visual Studio usi ...

I am experiencing difficulties with TypeORM connecting to my Postgres database

Currently, I am utilizing Express, Postgres, and TypeORM for a small-scale website development project. However, I am encountering challenges when it comes to establishing a connection between TypeORM and my Postgres database. index.ts ( async ()=>{ ...

Monitoring Object Changes in Angular 4

ETA: I am aware of different methods for monitoring my form for alterations. However, that is not the focus of my inquiry. As indicated by the title, my question pertains to observing changes within an object. The application displayed below is solely for ...

Adding files to an Angular ViewModel using DropzoneJS

I am facing a challenge in extracting file content and inserting it into a specific FileViewModel. This is necessary because I need to bundle all files with MainViewModel which contains a list of FileViewModel before sending it from the client (angular) to ...