Capacitor HTTP not passing data on mobile device and simulator

Hi, So just finished developing an app which was previously using angular http for requests. I have opted for capacitor http and works really well on the browser. When i use a simulator or install app on my device it seems to not pass the data. Not sure why because on the browser everything works like it should.

Ionic:

Ionic CLI : 7.1.1 (/usr/local/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 7.0.14
@angular-devkit/build-angular : 16.1.0
@angular-devkit/schematics : 16.1.0
@angular/cli : 16.1.0
@ionic/angular-toolkit : 9.0.0

Capacitor:

Capacitor CLI : 5.0.5
@capacitor/android : 5.0.5
@capacitor/core : 5.0.5
@capacitor/ios : not installed

Utility:

cordova-res : not installed globally
native-run : 1.7.2

System:

NodeJS : v18.16.0 (/usr/local/Cellar/node@18/18.16.0/bin/node)
npm : 9.5.1
OS : macOS Unknown

Here is my code for the login page:

  async login(){

    const {email, password } = this
    let body = {
      "email": email.trim(),
      "password": password.trim()
    };  

    const options = {
      url: 'https://usersauth.example.com/Auth/login',
      data: body,
    };

    const response: HttpResponse = await CapacitorHttp.post(options);


  if(response['status'] == 400){
    var data = response['data'];
    var output='';
    var errorhead = "Ooops";
    for(var key in data) { 
         output+= data[key] + '<br>';

    }

    this.showAlert(errorhead,output);

    }
    if(response['status'] == 200){
     
      this.credentials = {
        email: email.trim(),
        password: password.trim()
      };
      this.loginFirebase(this.credentials);
      this.setSessionObject(response['data']);
      this.router.navigate(['tabs']);
    }

  }

Then on the Server side I’m using this function

public function login()
    {
        header( 'Access-Control-Allow-Origin: *' );
        

    if ( $_SERVER[ 'REQUEST_METHOD' ] == "OPTIONS" )
    {
        
        header( 'Access-Control-Allow-Credentials: true' );
        header( 'Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS' );
        header( 'Access-Control-Allow-Headers: ACCEPT, ORIGIN, X-REQUESTED-WITH, CONTENT-TYPE, AUTHORIZATION' );
        header( 'Access-Control-Max-Age: 86400' );
        header( 'Content-Length: 0' );
        header( 'Content-Type: application/json; charset=utf-8' );
        die ;
    }
    
        $rules = [
            'email' => 'required|min_length[6]|max_length[50]|valid_email',
            'password' => 'required|min_length[8]|max_length[255]|validateUser[email, password]',
            
            
        ];

        $errors = [
            'password' => [
                'validateUser' => 'Invalid login credentials provided'
            ],
            'cpassword' => [
                'matches' => 'Password does not match'
            ]
        ];

$input = $this->getRequestInput($this->request);


        if (!$this->validateRequest($input, $rules, $errors)) {
            return $this
                ->getResponse(
                    $this->validator->getErrors(),
                    ResponseInterface::HTTP_BAD_REQUEST
                );
        }
        $model = new UserModel();
        $user = $model->findUserByEmailAddress($input['email']);
        if($user['status'] == 'Pending'){
            
            return $this
            ->getResponse(
                [
                    'error' => 'Your email is not verified',
                ],
                ResponseInterface::HTTP_BAD_REQUEST
            );
        }



       return $this->getJWTForUser($input['email']);

       
    }

   

So what happens is that its returns validation errors say i have not inputed anything even if i did. This is only happening on device and simulator on browsers it works as it should. Any help on what am missing thanks

What does your capacitor.config.ts file look like? I think you have to add a few lines there too:

import { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  appId: "com.sample.app",
  appName: "App Name",
  webDir: "dist",
  bundledWebRuntime: false,
  plugins: {
    CapacitorHttp: {
      enabled: true,
    },
  },
};

export default config;
import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'io.ionic.starter',
  appName: '*******',
  webDir: 'www',
  server: {
    androidScheme: 'https'
  },
  plugins: {
    CapacitorHttp: {
      enabled: false,
    },
  },
};

export default config;

Tried this on false and true. Still get the same results

Are you using the built-in Http in Capacitor now or @capacitor/http? I know they changed this in Capacitor 4 or 5.

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

Thats what I am using. WORKS on browser

Dang. I’m out of ideas.

This is what I am getting on the log.

[AUX]GuiExtAuxCheckAuxPath:674: Null anb
2023-06-20 11:19:51.897 14951-14951 Capacitor/Plugin io.ionic.starter V To native (Capacitor plugin): callbackId: 31180578, pluginId: CapacitorHttp, methodName: post
2023-06-20 11:19:51.897 14951-14951 Capacitor io.ionic.starter V callback: 31180578, pluginId: CapacitorHttp, methodName: post, methodData: {“url”:“https://usersauth.example.co.za/api/register”,“data”:{“user_id":“8909056141082”,“first_name”:“Cold”,“last_name”:“fire”,“contact”:“0834726482”,“email”:"fine@gmail.com”,“password”:“8909056141082”,“cpassword”:“cold”,“push_token”:“”,“player_id”:“”}}
2023-06-20 11:19:51.900 14951-17557 System.out io.ionic.starter I [okhttp]:check permission begin!
2023-06-20 11:19:51.900 14951-17557 System.out io.ionic.starter I [okhttp]:not MMS!
2023-06-20 11:19:51.900 14951-17557 System.out io.ionic.starter I [okhttp]:not Email!
2023-06-20 11:19:51.902 14951-17557 System.out io.ionic.starter I [OkHttp] sendRequest>>
2023-06-20 11:19:51.902 14951-17557 System.out io.ionic.starter I [OkHttp] sendRequest<<

[AUX]GuiExtAuxCheckAuxPath:674: Null anb
tagSocket(212) with statsTag=0xffffffff, statsUid=-1

This is hella confusing coz i honestly dont want to change from capacitor http because of how it works on the browser. It does exactly what i need it too, problem starts on device. Any Help!

From that log it appears it is at least seeing the data and sending it. Have you tried dumping the REQUEST server side before it hits any of the validation?

It doesn’t look like you shared what $this->getRequestInput($this->request) does, so there is a possibility that one way it is sending as form data and another as JSON and that method doesn’t handle both?

A side note, you don’t need to replace the Angular HTTP code with specific Capacitor HTTP code. By just enabling Capacitor HTTP, it is supposed to patch standard fetch and XMLHttpRequest through to the native layer eliminating the need to rewrite your code.

Another side note, are you using a PHP framework or are you rolling your own? I highly recommend Laravel :smile:

1 Like

Yes i do dump Request before validating it. For some reason i cant seem to get the data when using $this->getRequestInput($this->request) or $this->request->getPost(). On the browser i was able to dump data to see if it works using $this->request->getJSON(). I’m using latest version of Codeigniter 4. I wish i had started project with Lara but I’m already into deep to turn back now. Previously i was using angluar/http/common and it was working great change to capacitor coz i just like the syntax and how its so efficient when on browser. I will revert to angular. I just throught capacitor would perform better

When i use the following code it works. Can someone please edit this code for me to not require subscribe as its said it will deprecate in v8. If you can just modify it for me to current usage. I will follow and keep trying capacitor http but for now i need to upload the app.

 async login(){

    const {email, password } = this
    let body = {
      "email": email.trim(),
      "password": password.trim()
    };  
   
      
        this.http.post('https://usersauth.example.co.za/api/login', body)
        .subscribe(data => {
          this.credentials = {
            email: email.trim(),
            password: password.trim()
          };
          this.loginFirebase(this.credentials);
          this.setSessionObject(data);
          this.router.navigate(['tabs']);
         }, error => {

           var response = error['error'];
          var output='';
          var errorhead = "Ooops";
          for(var key in response) { 
               output+=response[key]+'<br>';
          }

          this.showAlert(errorhead,output);


          });
     
  }

What is the request status, 200? Because if it is 302 you lose your data in the redirect.

Yes status was 203, I dont understand when you say redirect. Coz seems like data does not get to the API, But when using browser it did. So is there any config that i missed for mobile

Actually not 100% sure what the status code was on the device. But it was just not passing input data to the API. This is because i would click login but an empty data array would get passed. Thus i would get validation errors even when i have inputted something

I faced the same issue and solved it using FormData

Try to replace this code:

let body = {
“email”: email.trim(),
“password”: password.trim()
}

With this code:

Let body = new FormData()
body.append("email ", email.trim());
body.append(“password”, password.trim());

Thanks will test it out later today and revert

Hi, Tried your method. Does not pass data at all.

    console.log('test email', email);

    console.log('test uid', uid);

    const formData = new FormData();
    const dataJson = {
      'email': email,
      'uid': uid
    };
    console.log('dataJson:', dataJson);


    formData.append('data',JSON.stringify(dataJson));
    console.log('formData: ', formData.getAll('data'));

    let body = new FormData()
    body.append("email", email.trim());
    body.append("uid", uid.trim());

    const options = {
      url: 'https://usersauth.example.co.za/api/updateuid',
      data: formData
    };

    console.log('Post Data',options);


    const response: HttpResponse = await CapacitorHttp.post(options); 
    
    console.log('UiD Update',response);

Line 1 - Msg: test email flex@gmail.com
Line 1 - Msg: test uid y3TYPRrQvhWIS9QdF7MzGNOpgiC2
Line 1 - Msg: dataJson: [object Object]
Line 1 - Msg: formData: {“email":"flex@gmail.com”,“uid”:“y3TYPRrQvhWIS9QdF7MzGNOpgiC2”}
Line 1 - Msg: Post Data [object Object]
native (Capacitor plugin): callbackId: 28578401, pluginId: CapacitorHttp, methodName: post
pluginId: CapacitorHttp, methodName: post, methodData: {“url”:“https://usersauth.example.co.za/api/updateuid”,“data”:{“email":"flex@gmail.com”,“uid”:“y3TYPRrQvhWIS9QdF7MzGNOpgiC2”}}

tried all the following only dataJson is successfuly on browser but nothing happens on device. it still does not pass data

For me it worked by setting the Content-Type header, without it I was just getting an empty payload on the server:

const options = {
  url: 'https://example.com/api',
  headers: {
    'Authorization': 'Token asdf',
    'Content-Type': 'application/json',
  },
  data: {
    "key1": "value1",
    "key2": "value2",
  },
};

CapacitorHttp.post(options).then((response) => {})
1 Like

Thank you!!!
Including headers content-type worked for me