rxjs icon indicating copy to clipboard operation
rxjs copied to clipboard

Ajax config & intercept

Open vimniky opened this issue 7 years ago • 17 comments

Is there a way to create a pre configured ajax instance, so that I don't need to configure it over and over again ?

For example:


import ajax from 'rxjs/Observable/dom/ajax'

const myAjax = ajax.create({url: '/api/xxx',  header: {widthCredential: true, ...}})

// Now myAjax will setup widthCredential = true for all the related outgoing ajax request
// so that  I can just:
myAjax.get('/api/xxx')
myAjax.post('/api/xxx', body)

// Instead of
ajax.get({url: '/api/xxx', header: {widthCredential: true, ...}})
ajax.post({url: '/api/xxx', body: data, header: {widthCredential: true, ...}})

BTW how can I intercept all http requests or responses in a single place using rxjs' ajax api ?

Here's how the axios library intercepts http requests and responses:


// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });

Thanks !

vimniky avatar Jun 20 '17 23:06 vimniky

I'm also interested in how this is solved?

macnibblet avatar Feb 13 '18 17:02 macnibblet

I'm planning on writing a simple http wrapper singleton service around ajax to solve this issue. Will share when I have it completed

evanjmg avatar May 28 '18 13:05 evanjmg

I am also very interested in this. I am really wondering if there's an ongoing plan for this issue. I am interested in contributing to adding this functionality. I might have a simple solution to it, and I can work on it very soon :)

Cheers!

Shehats avatar Aug 24 '18 05:08 Shehats

So I am currently using Rxjs in one of my projects and I was using rxjs/ajax. However I realized that rxjs/ajax doesn't have interceptors. So out of curiosity I forked rxjs and implemented interceptors. The usage that I came up with (from my project :D) was that I added an operator ajaxInterceptors which can be called using array of (request interceptor array or a request interceptor or none), and (response interceptor array or a response interceptor or none), also more interceptors can be added using few methods for each request (interceptors for GET requests and so on).

My question is:

Is is an ideal implementation for ajax interceptors for rxjs and if so, will it be accepted, once unit tests and performance tests are complete?

Shehats avatar Aug 27 '18 13:08 Shehats

update?

kedwin avatar Oct 31 '18 15:10 kedwin

Would be great to have an ability to hook to/intercept all the ajax requests. Is there any way to do it now?

maxevilmind avatar Nov 02 '18 04:11 maxevilmind

No luck?

shobishani avatar Apr 11 '19 05:04 shobishani

any update on this?

tohbansoon avatar May 27 '19 08:05 tohbansoon

any update on this? is there a plan to add interceptors ?

Yene-Me avatar Dec 30 '19 21:12 Yene-Me

My application is using react + redux-observable... Here is my workaround see if it help...

import { createStore, applyMiddleware } from 'redux'
import { ajax } from 'rxjs/ajax'
import { createEpicMiddleware } from 'redux-observable'

const myConfig = {
   X-Platform: 'desktop',
   X-Session-Id: 'xxxxxxx'
}

const epicMiddleware = createEpicMiddleware({
    dependencies: {
        ajax: config => {
            const customConfig = {
                ...config,
                headers: {
                    ...myConfig,
                    ...config.headers
                }
            }
            return ajax({ ...customConfig })
        }
    }
})

...
......

 store = createStore(
            rootReducer,
            initialState,
            applyMiddleware(epicMiddleware)
        )

Epics:

export const addToFavorites = (action$, state$, { ajax }) =>
    action$.pipe(
        ofType(actionsTypes.ADD_TO_FAVORITES),
        mergeMap(action => {
            const currentUserAccessToken =
                state$.value.userReducer.currentUserAccessToken
            const userId = state$.value.userReducer.currentUserData.id
            return ajax({
                method: 'PUT',
                headers: {
                    Authorization: `Bearer ${currentUserAccessToken}`,
                    'Content-Type': 'application/json'
                },
                url:
                    API_USER_ENDPOINT +
                    `/users/${userId}/favorite_restaurant_ids/${
                        action.restaurantId
                    }`
            }).pipe(
                map(() => {
                    const userId = state$.value.userReducer.currentUserData.id
                    return actions.getFavorites(userId)
                }),
                catchError(err =>
                    of(actions.epicErrorHandler(err, action.type))
                )
            )
        })
    )

By doing this, all the request i send will automatically insert X-Platform and X-Session-Id into the header

tohbansoon avatar Dec 31 '19 02:12 tohbansoon

maybe using more pipe to make more interception..

0length avatar Jan 16 '20 04:01 0length

You can still use Axios with interceptor and use fromPromise to create an Observable.

gugadev avatar May 05 '20 19:05 gugadev

In my case i created a function for that.

export function ajaxObs(params: {
  [key: string]: any;
  url: string;
  method?: string;
  body?: any;
  headers?: { [key: string]: string };
  responseType?: string;
}) {
  const {
    url,
    method,
    body,
    headers = {
      "Content-Type": "application/json",
      ...(Cookies.get("accessToken") && {
        Authorization: `Bearer ${Cookies.get("accessToken")}`,
      }),
    },
    responseType,
  } = params;

  const apiBaseUrl: string = https://mycustomurl.com/

  // creation observable
  const ajax$: Observable<AjaxResponse | Observable<AjaxError>> = ajax({
    url: `${apiBaseUrl}${url}`,
    method: method ? method : "GET",
    async: true,
    headers: headers,
    body: body,
    ...(responseType && { responseType: responseType }),
  })

  return ajax$;
}

I hope this will help you

Vincent-Alibert avatar Sep 03 '20 06:09 Vincent-Alibert

I'm on the fence about this feature. I've seen interceptors be useful, however, it also means introducing global, mutable state (at least in the proposed solution, or in existing prior art). In other words, if a third party adds an interceptor like ajax.request.interceptors.push(fn), then your code, and worse, other third party code that wants to use ajax is now being intercepted.

I'm more inclined to say a better design would be to have a factory that creates an instance of ajax that allows users to register interceptors. However, then we're in a situation where maybe it's desirable to intercept ajax requests from third party libraries (perhaps to proxy them or something) and now you can't. I suppose a service worker might be a solution there.

If we had use cases we all agreed on, then perhaps we could implement something. In the mean time, as a workaround, I'd recommend just wrapping it in your own function that amended the request/response as necessary.

benlesh avatar Jan 12 '22 16:01 benlesh

Core Team: General lack of interest in this feature as of right now.

@benlesh: I'll think about the problem though, since it seems like something a lot of people are asking for.

benlesh avatar Jan 12 '22 21:01 benlesh

I'm more inclined to say a better design would be to have a factory that creates an instance of ajax that allows users to register interceptors.

I tend to prefer these interceptors capable factories instead of a global solution.

What could be provided instead is a generator of such factories.

grimly avatar Feb 03 '22 11:02 grimly

I have created a sample wrapper for both functional and class-based HTTP services over rxjs ajax to have both before and after interceptors.

https://gist.github.com/maxgaurav/48e1f309fd2afb2ab55c558c3e63d1dc

Hope this helps.

maxgaurav avatar Jun 10 '22 11:06 maxgaurav