TypeError: Failed to fetch. CAPACITOR CORS

I am trying to make a fetch to google maps api

this is my httprequest controller

import { CapacitorHttp, HttpResponse, HttpHeaders } from '@capacitor/core';
import { Preferences } from '@capacitor/preferences';

export interface ApiRequest<T = any> {
  url: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  data?: T;
  extraHeaders?: { [key: string]: string };
  params?: { [key: string]: string };
  responseType?: 'arraybuffer' | 'blob' | 'json' | 'text' | 'document';
  auth?: boolean;
}

export interface ApiResponse<T = any> {
  data: T;
  status: number;
  headers: HttpHeaders;
}

const request = async (call: ApiRequest): Promise<ApiResponse> => {
  try {
    
    const options : any = {
      url: call.url,
      method: call.method,
     
      params: call.params,
      headers: {
        'Content-Type': 'application/json',
        ...call.extraHeaders,
      },
    };


    
    const response: HttpResponse = await makeCapacitorHttpCall(options);
    console.log(response)
    return {
      data: response.data,
      status: response.status,
      headers: response.headers,
    };
} catch (error: any) {
  console.log(error)
    throw {
      data: error.response?.data,
      status: error.response?.status,
      headers: error.response?.headers,
    };
  }
};

const makeCapacitorHttpCall = async (options: any): Promise<HttpResponse> => {
  switch (options.method) {
    case 'GET':
      return await CapacitorHttp.get(options);
    case 'POST':
      return await CapacitorHttp.post(options);
    case 'PUT':
      return  await CapacitorHttp.put(options);
    case 'PATCH':
      return await CapacitorHttp.patch(options);
    case 'DELETE':
      return await CapacitorHttp.delete(options);
    default:
      throw new Error(`Unsupported HTTP method: ${options.method}`);
  }
};

export default request;

I am calling in this place

export const geoposicionar = async (lat: string, lng: string) => {
  try {

    const response = await request({
      url: 'https://maps.googleapis.com/maps/api/geocode/json',
      method: 'GET',
      // @ts-ignore
      params: {
        latlng: `${lat},${lng}`,
        key: 'MyKey'
      }
    })

    return response.data

  } catch (error) {
    
    console.error('Error al obtener información de la ubicación:', error);
  }
};

and when I make the fetch i get this error


if I use axios, work all well, but when i use capacitor i have this problem.

It’s interesting that Axios works. The CapacitorHttp plugin’s web implementation uses fetch. I would think they would both fail due to CORS if Google doesn’t allow that.

As an FYI, you don’t have to use the CapacitorHttp plugin directly. You can use standard fetch or XMLHttpRequest (either by themselves or through Axios) and the Capacitor plugin will patch the requests through to the native libraries circumventing CORS all together. This patching is disabled by default. To enable, see the documentation.

Now obviously when testing in the web browser and not on an actual device (or emulator), you are always going to run into the CORS issue.

What does the Request look like when using Axios?

Yes, i am using http capacitor for my app work in web and android. Http Capacitor work well when i request to my backend, but no with google, only axios

Wouldn’t it be a header problem? Which axios configures correctly and http capacitor does not?

this is my axios config

import axios, {
    AxiosError,
    AxiosRequestConfig,
    AxiosResponse,
    AxiosResponseHeaders,
    ResponseType
} from 'axios';
import { Preferences } from '@capacitor/preferences';

export interface ApiRequest<T = any> {
    url: string;
    method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
    data?: T;
    extraHeaders?: { [key: string]: string };
    params?: URLSearchParams;
    responseType?: ResponseType;
    auth?: boolean
}

export interface ApiResponse<T = any> {
    data: T;
    status: number;
    statusText: string;
    headers: AxiosResponseHeaders;
}

const instance = axios.create({ baseURL: process.env.API_BASE_URL || 'http://localhost:10002/' });

const request = (call: ApiRequest): Promise<ApiResponse> => {
    return new Promise(async (resolve, reject) => {
        const onSuccess = (response: AxiosResponse) => {
            resolve({
                data: response.data,
                status: response.status,
                statusText: response.statusText,
                headers: response.headers
            });
        };

        const onError = (err: AxiosError) => {
            console.log(err)
            reject({
                data: err.response?.data,
                status: err.response?.status,
                statusText: err.response?.statusText,
                headers: err.response?.headers
            });
        };

        const axiosCall: AxiosRequestConfig = {
            url: call.url,
            method: call.method,
            data: call.data,
            params: call.params as any,
            responseType: call.responseType,
            headers: {
                'Content-Type': 'application/json',
                ...call.extraHeaders
            }
        };
        if(call.auth){
            let tokenAutenticado = await Preferences.get({ key: "_token" });

            if (tokenAutenticado.value && axiosCall.headers) {
                axiosCall.headers['Authorization'] = `Bearer ${tokenAutenticado.value}`;
            }
        }

        instance(axiosCall).then(onSuccess).catch(onError);
    });
};

export default request;

![cap4|685x499](upload://vvmhuUzcMkTaSg48GZB0qJt0g4R.png)
![cap3|574x500](upload://oRp7ZikvQzfBYuFlXProypm0amq.png)

Looking at the error in more detail, it says the Content-Type is invalid. Check the Axios request and see what Content-Type that is sending.



they are completly different the headers they sent

What matters is Content-Type / Accept. Axios is everything vs. Capacitor is just JSON. Try setting responseType to text in HttpOptions.

this worked

const options : any = {
      url: call.url,
      method: call.method,
      data: call.data,
      params: call.params,
      headers: {
        'Accept': 'application/json, text/plain, */*',
        ...call.extraHeaders,
      },
      responseType: 'text'
    
    };

work with Accept option

But this new configuration hurt my other post requests hahaha. It should make it dynamic. But it’s not very practical, isn’t it?

Because with google api maps it works with accept, but when I go to my backend with post it doesn’t work?

so, work accep with get, and content-type with post. its right?

can it be a valid solution?

const options : any = {
      url: call.url,
      method: call.method,
      data: call.data,
      params: call.params,
      headers: {
        [call.method === 'GET' ? 'Accept' : 'Content-type']: 'application/json, text/plain, */*',
        ...call.extraHeaders,
      },
    };

Glad to hear it works with Accept! That could work or try to make it more dynamic so it can be set on a case by case basis. Or can you just set both - Accept and Content-Type?

It seems though Accept is usually used in a Request and Content-Type in the Response (source). Any reason your backend server doesn’t use Accept?