RxJs How to set default request headers?

做~自己de王妃 提交于 2019-12-04 19:21:58

It's not possible to set default headers for all ajax requests using RxJS's ajax utilities.

You can however provide headers in each call, or create your own simple wrapper that provides them by default.

utils/ajax.js

const defaultHeaders = {
  Authorization: 'c7b9392955ce63b38cf090...etc'
};

export const get = (url, headers) =>
  ajax.get(url, Object.assign({}, defaultHeaders, headers));

my-example.js

import * as ajax from './utils/ajax';

// Usage is the same, but now with defaults
ajax.get(`http://localhost/products?${action.q}`;)

I'm using redux-observable but this applies to rxjs; maybe the next answer its too over-engineered, but I needed to get dinamically the headers depending of certain factors, without affecting the unit testing (something decoupled from my epics too), and without changing the sintax of ajax.get/ajax.post etc, this is what I found:

ES6 has proxies support, and after reading this and improving the solution here, I'm using a High Order Function to create a Proxy in the original rxjs/ajax object, and return the proxified object; below is my code:

Note: I'm using typescript, but you can port it to plain ES6.

AjaxUtils.ts

export interface AjaxGetHeadersFn {
    (): Object;
}

// the function names we will proxy
const getHeadersPos = (ajaxMethod: string): number => {
    switch (ajaxMethod) {
        case 'get':
        case 'getJSON':
        case 'delete':
            return 1;
        case 'patch':
        case 'post':
        case 'put':
            return 2;
        default:
            return -1;
    }
};

export const ajaxProxy = (getHeadersFn: AjaxGetHeadersFn) =>
    <TObject extends object>(obj: TObject): TObject => {
        return new Proxy(obj, {
            get(target: TObject, propKey: PropertyKey) {
                const origProp = target[propKey];
                const headersPos = getHeadersPos(propKey as string);

                if (headersPos === -1 || typeof origProp !== 'function') {
                    return origProp;
                }

                return function (...args: Array<object>) {
                    args[headersPos] = { ...args[headersPos], ...getHeadersFn() };
                    // @ts-ignore
                    return origProp.apply(this, args);
                };
            }
        });
    };

You use it this way:

ConfigureAjax.ts

import { ajax as Ajax } from 'rxjs/ajax'; // you rename it

// this is the function to get the headers dynamically
// anything, a function, a service etc.
const getHeadersFn: AjaxGetHeadersFn = () => ({ 'Bearer': 'BLABLABLA' });

const ajax = ajaxProxy(getHeadersFn)(Ajax); // proxified object
export default ajax;

Anywhere in you application you import ajax from ConfigureAjax.ts and use it as normal.

If you are using redux-observable you configure epics this way (injecting ajax object as a dependency more info here):

ConfigureStore.ts

import ajax from './ConfigureAjax.ts'

const rootEpic = combineEpics(
    fetchUserEpic
)({ ajax });

UserEpics.ts

// the same sintax ajax.getJSON, decoupled and
// under the covers with dynamically injected headers
const fetchUserEpic = (action$, state$, { ajax }) => action$.pipe(
  ofType('FETCH_USER'),
  mergeMap(({ payload }) => ajax.getJSON(`/api/users/${payload}`).pipe(
    map(response => ({
      type: 'FETCH_USER_FULFILLED',
      payload: response
    }))
  )
);

Hope it helps people looking for the same :D

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!