Day 5 – NativeScript Post Series

How to capture Image and post Image as Base64String to API using Http and Axios Modules

In this post, I will be using NativeScript Vue to capture an image using nativescript-camera plugin and post the image as Base64String to a WebAPI running on Azure Functions using http Module and Axios Module.

I have been monitoring the nativescript community slack channel. Some conversations were around using Axios to send post request to API and how we can send image to API etc… These questions inspired me to try this sample. In the process of developing this sample, I have observed some issues with Axios. You might be already aware of the issue which I noticed, but I thought to have it published here for my self reference.

To start with I created my Azure Function using my azure subscription and created a simple Http Trigger Function which accepts JSON request and returns the same. I have set the authorization level as Anonymous.

Below is the code snippet of my Function.

public static class Function1
{
[FunctionName("Function1")]
public static IActionResult Run([HttpTrigger
(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequest req,
 ILogger log)
{
 log.LogInformation("C# HTTP trigger function processed a request.");
 string requestBody = new StreamReader(req.Body).ReadToEnd();
 dynamic data = JsonConvert.DeserializeObject(requestBody);
 string imageString = data.ImageContent;

 log.LogInformation("Request Content Type");
 log.LogInformation(req.ContentType);           
 log.LogInformation("Received Image Base64 String : "+ imageString);

 var result = JsonConvert.SerializeObject(data.ImageContent);
 JsonResult resx = new JsonResult(result);                       
 return resx;           
 }
}

Once we publish the Function using Visual Studio, we can access the function from Azure Portal and get the Function url.

As part of the Publish Process, I have selected my Existing Function App.

Function1Axios

Next in the Wizard , we need to select the Function App to which we want to publish the function.

FunctionAxios2

Once the Publish, is succeeded Visual Studio displays the below log. The Publish Profile will be set with the Function App which we selected. For subsequent builds we can directly click the Publish button, and an incremental build would be pushed to Azure.

FunctionAxios9

Now we can navigate to the Function in Azure Portal and Get the Function url. This url will be used in our NativeScript Mobile App.

FunctionAxios3

Now that we have our Function url, I can go ahead and use it in my NativeScript Sample App.

The App has two buttons, one button to capture Image and post Image as Base64String to our Function using Http Module and another button performs the same operation using Axios Module.

To use http Module we need to import http using the below snippet.

import * as http from "http";

The below code snippet works perfectly for http Module.

http.request
({
url:"https://testfbc.azurewebsites.net/api/Function1",
method:"POST",
headers: { "Content-Type":"application/json" },
content:JSON.stringify({
ImageContent : this.pictureBase64String
})
}).then(response => {
var result=response.content.toJSON();

}, error => {
console.error(error);
});

When we post the request using Http Module, the base64String is populated to ImageContent field of Json Request.  I can see the request base64String logged in Azure Functions Log. The above snippet works perfectly.

VueImageCapture

Now I had to extend my sample to test with Axios.  I went ahead and created a new button and method to test with Axios.

We have to import Axios using below snippet. It was recommended in NativeScript Community Slack to use Axios/Dist

import * as axios from "axios/dist/axios";

Below is the code snippet I used.

axios({
method:"post",
url:"https://testfbc.azurewebsites.net/api/Function1",
data: {
ImageContent : this.pictureBase64String
},
headers : {"Content-Type":"application/json"}
})
.then(response => {
var result=response.data;
console.log(result);
}, error => {
console.error(error);
});

While testing the above snippet, I noticed that my request content is not reaching my Function App. The Functions Log does not display the base64String.

axios1

So I wanted to figure out, what is going wrong.  I tried to use Vue Developer tools to check the network traffic. I clicked on Toggle Developer Tools. There was no network logs traced. To check how to enable Vue Developer Tools follow the instructions here.

devtools

Thanks to @rigor789 he helped me figure out that we need to use Chrome Developer tools by using the url which we get from tns debug command. Vue Developer Tools only allows to check the values in UI.

Using below command, I was able to grab the chrome developer tools url.

tns debug android --bundle

This command will provide the chrome developer tools url which we can use to verify the network traffic. On launching chrome developer tools I figured out that , the response is returned “null”.

axios6

Now I tried to modify my Axios Post Request similar to my Http Module using below snippet. I replaced my previous data code with JSON.stringify.

axios({
method:"post",
url:"https://testfbc.azurewebsites.net/api/Function1",
data: JSON.stringify({
ImageContent : this.pictureBase64String
}),
headers : {"Content-Type":"application/json"}
})
.then(response => {
var result=response.data;
console.log(result);
}, error => {
console.error(error);
});

On executing the above code, I observed that the response was still returned null. The code in my Function App will receive the request and return the same in response. This means that the request did not have the ImageContent field populated in both scenarios.

axios4

So I decided to debug further, and figured that in the Axios module, the request is not getting populated correctly. So I went ahead to StackOverflow to see if there were any previous issues related to Axios. In one of thread, it was mentioned that Axios would require the request properties always to be in string format.

I changed my code to test as shown in below snippet. I decided to add toString() at the end of my variable.

axios({
method:"post",
url:"https://testfbc.azurewebsites.net/api/Function1",
data: {
ImageContent:this.pictureBase64String.toString()
},
headers : {"Content-Type":"application/json"}
})
.then(response => {
var result=response.data;
console.log(result);
}, error => {
console.error(error);
});

Launched chrome developer tools to check if I had any luck. Now we are able to receive the response from Function App, as the request was received by Function App.

axios8

I can see the ImageContent field is received in my function, from logs of Function App.

axios3

If you are having issues with axios not posting request, then I would suggest to look at the request field formats. What works in http module is not expected to work in Axios module.

While working on this app, I figured that we cannot use the below commands to test our app. These commands works with NativeScript Core where we use plain javascript.

tns build android
tns run android

The above commands would not give any errors with Vue, but when we deploy the app to test ,the app will crash with out loading. The log states that “Frame require ‘file'”.

To test the apps with Vue, we need to use the below commands.

tns build android --bundle
tns run android --bundle 
tns debug android --bundle

I have been exploring all these days NativeScript with Javascript. Coming to explore Vue with NativeScript made me realize that I need to use above bundle commands.

Hope this experience of mine helps others.

The code sample for this sample can be found here.

Happy Reading !!!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s