javascripturlaxiosencodingurlencode

Wrong URL encoding supplied to Axios


This is where I'm doing the encoding before sending the GET request with Axios:

const myOrg = await fetchMyOrg();

const response = await api.get<Resp<Asset>>('/asset/assets', {
  headers: { 'Accept-Version': '0.24.0.0' },
  params: {
    q: encodeURIComponent(
      JSON.stringify({
        organizationId: myOrg.id, // 010a87ba-2e19-4ae7-b64e-a5496eaa825e
        ...(tags.length > 0 && { tags }), // ['Tag 1', 'Router']
      }),
    ),
    page: currentPage,
    size,
    sort: 'lastUpdateDateTime',
    dir: -1,
  },
});

It produces this encoding:

https://agw4web1.dev.hannlync.com/asset/assets?q=%257B%2522organizationId%2522%253A%2522010a87ba-2e19-4ae7-b64e-a5496eaa825e%2522%252C%2522tags%2522%253A%255B%2522Tag%25201%2522%252C%2522Router%2522%255D%257D&page=1&size=10&sort=lastUpdateDateTime&dir=-1

But this is the correct encoding:

https://agw4web1.dev.hannlync.com/asset/assets?q=%7B%20%20%22organizationId%22%3A%20%22010a87ba-2e19-4ae7-b64e-a5496eaa825e%22%2C%20tags%3A%20%5B%22Tag%201%22%2C%20%22Router%22%5D%7D&page=1&size=10&sort=lastUpdateDateTime&dir=-1

How to modify the code so that I get the second encoding?


Solution

  • Axios already encodes the params values with (something similar to) encodeURIComponent() so all you're doing is double-encoding the JSON value.

    This means the server side will receive a URL-encoded JSON string once it decodes the query params.

    Simply omit the encodeURIComponent() call and let Axios do its thing

    const response = await api.get<Resp<Asset>>("/asset/assets", {
      headers: { "Accept-Version": "0.24.0.0" },
      params: {
        q: JSON.stringify({
          organizationId: myOrg.id,
          ...(tags.length > 0 && { tags }),
        }),
        page: currentPage,
        size,
        sort: "lastUpdateDateTime",
        dir: -1,
      },
    });
    

    If you need to customise the parameter encoding, use Axios' paramsSerializer option

    const baseURL = 'https://echo.zuplo.io/'; // just a handy HTTP echo service
    const defaultSerializer = axios.create({ baseURL });
    const standardEncoder = axios.create({
      baseURL,
      paramsSerializer: { encode: encodeURIComponent },
    });
    
    const params = {
      q: JSON.stringify({
        organizationId: '22010a87ba-2e19-4ae7-b64e-a5496eaa825e',
        tags: ['Tag 1', 'Router'],
      }),
      page: 1,
      size: 10,
      sort: 'lastUpdateDateTime',
      dir: -1,
    };
    
    defaultSerializer
      .get('/', { params })
      .then(({ data }) => console.log('defaultSerializer:', data.url));
      
    standardEncoder
      .get('/', { params })
      .then(({ data }) => console.log('standardEncoder:', data.url));
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>