Android Question How to enter a curl command as an HTTPS request

Colin Evans

Active Member
Licensed User
Longtime User
Hi

I want to retrieve JSON data from my electricity supplier, they have an API which I have a API_Key for but the examples they give are using the CURL tool at the CMD prompt, something I can't get my head around.

In some of my previous amateur apps I have issued a browser request which then returns the JSON data which I can work on but I don't know how I would convert their example to a simple HTTPS:// request

Below is their example with the API_Key removed

curl -u "API KEY" "https://api.octopus.energy/v1/electricity-meter-points/1460001714995/meters/15P0459914/consumption/"

I have tried the company but I think due to the Covid situation I don't think any one is working in their support team

Don't know if someone can help but its worth a shout out, thanks
 

MarcoRome

Expert
Licensed User
Longtime User
Your api key most likely has the following syntax "xxxx: yyyy"

Put your first part ( xxxx ) in j.Username
and the second part ( yyyy ) in j.Password

B4X:
    Dim j As HttpJob
    j.Initialize("", Me)
    j.Username = "xxxx"
    j.Password = "yyyy"
    j.Download("https://api.octopus.energy/v1/electricity-meter-points/1460001714995/meters/15P0459914/consumption/")
    Wait For (j) JobDone(j As HttpJob)
    If j.Success = True  Then
        Log(j.GetString)
    Else
        Log(j.ErrorMessage)
    End If
    j.Release

Now, of course without credential right i have this message:
ResponseError. Reason: Unauthorized, Response: {"detail":"Authentication credentials were not provided."}
{"detail":"Authentication credentials were not provided."}
 
Upvote 0

Colin Evans

Active Member
Licensed User
Longtime User
Hi MarcoRome
Many thanks for the quick reply, I don't suppose you have the full code so I could try it, I am a novice at most things to do with B4A so just having your snippet isn't much use to me to get the full understanding

I believe the Curl -U bypasses the need for a password and whilst the API is structured as you say "xxxxxxxxxxxxxxxxxx:" there's nothing after the colon, I have tried but getting major java errors

Hope you can help and I thank you for your patience
 
Upvote 0

MarcoRome

Expert
Licensed User
Longtime User
Do yo have a link with documentation ? & in attachment ( as say Erel ) paste the Error pls
 
Upvote 0

Colin Evans

Active Member
Licensed User
Longtime User
yes that's how I've done the j.username j.password the errors I'm getting are ass follows, as I've stated many times I'm a novice please be gentle

** Activity (main) Create, isFirst = true **
main$ResumableSub_Activity_Createresume (java line: 374)
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/client/methods/HttpGet;
at anywheresoftware.b4a.http.HttpClientWrapper$HttpUriRequestWrapper.InitializeGet(HttpClientWrapper.java:342)
at anywheresoftware.b4a.samples.httputils2.httpjob._download(httpjob.java:71)
at b4a.example.multipartpost.main$ResumableSub_Activity_Create.resume(main.java:374)
at b4a.example.multipartpost.main._activity_create(main.java:341)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:196)
at b4a.example.multipartpost.main.afterFirstLayout(main.java:104)
at b4a.example.multipartpost.main.access$000(main.java:17)
at b4a.example.multipartpost.main$WaitForLayout.run(main.java:82)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6694)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.ClassNotFoundException: Didn't find class "org.apache.http.client.methods.HttpGet" on path: DexPathList[[zip file "/data/app/b4a.example.multipartpost-vvyGCWDGVpUE0hZXepJEsg==/base.apk"],nativeLibraryDirectories=[/data/app/b4a.example.multipartpost-vvyGCWDGVpUE0hZXepJEsg==/lib/arm64, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 16 more
main$ResumableSub_Activity_Createresume (java line: 374)
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/client/methods/HttpGet;
at anywheresoftware.b4a.http.HttpClientWrapper$HttpUriRequestWrapper.InitializeGet(HttpClientWrapper.java:342)
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Failed resolution of: Lorg/apache/http/client/methods/HttpGet;


- 28 - The old http SDK is not available by default. This will cause problems with native libraries such as Google Maps who rely on the old SDK. To enable it: https://www.b4x.com/android/forum/t...ar-error-in-android-9-pie.103247/#post-649875
 
Upvote 0

Colin Evans

Active Member
Licensed User
Longtime User
Thanks Erel that seems to work (ish)
I now don't get any errors but the following

ResponseError. Reason: , Response: {"detail":"Authentication credentials were not provided."}
{"detail":"Authentication credentials were not provided."}

So I'm obviously doing something wrong here's my code, the only thing I've missed out is the API_Key

Dim j As HttpJob
j.Initialize("", Me)
j.Username = "sk_live_xxxxxxxxxxxxxxxxxxxx"
j.Password = ""
j.Download("https://api.octopus.energy/v1/electricity-meter-points/1460001714995/meters/15P0459914/consumption/")
Wait For (j) JobDone(j As HttpJob)
If j.Success = True Then
Log(j.GetString)
Else
Log(j.ErrorMessage)
End If
j.Release
 
Upvote 0

Colin Evans

Active Member
Licensed User
Longtime User
Hi Sandman
That works as expected, thanks, as my meters aren't connected yet I'm getting null values back as I'd expected

What I want to extract using the API is the consumption api, and then a view of every 30 minute period throughout the day as my kwh price changes each half hour and anything I may find useful

The Developer Docs can be found here

 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Looks like the current (as is) HttpUtils2Service.bas allows only for two configurations when sending username/password combos:
1) Both username AND password are set, pass along username and password credentials (via ExecuteCredentials)
2) Otherwise pass no username/passwords via Execute

Looking at the Git source Execute calls ExecuteCredentials with both username and password set to Null.

Solutions:
1) Don't use the OkHttpUtils2 library. Download source here https://www.b4x.com/android/forum/t...putils2-httputils2-source-code.82632/#content and modify to allow blank password (in HttpUtils2Service.bas, in the SubmitJob method, change the And evaluation to an Or)
2) Make a wish to allow blank password and still process request via ExecuteCredentials (with password set to Null) and see if Anywhere Software provides a permanent solution to the issue (that can be enjoyed by everyone in future B4X versions). Note: This depends on the underlying technology used to allow for a blank password. Otherwise the only option left is solution#1.

Update: Solution #3. Do both 1 and 2.
 
Upvote 0

MarcoRome

Expert
Licensed User
Longtime User
Try

B4X:
Dim basicAuth as string = "YOUR KEY"
Dim j As HttpJob
j.Initialize("", Me)
j.Download("https://api.octopus.energy/v1/electricity-meter-points/1460001714995/meters/15P0459914/consumption/")
j.GetRequest.SetHeader("Authorization", "Basic " & basicAuth)
Wait For (j) JobDone(j As HttpJob)
If j.Success = True Then
Log(j.GetString)
Else
Log(j.ErrorMessage)
End If
j.Release
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Or Solution#4, wait for someone smarter to come up with a work around that is a lot simpler (no library fudging required). Now it just needs Base64 encoding
B4X:
Dim basicAuth As String = "YOUR KEY:" ' I'm pretty sure you need the colon here at the end of you API key. If you get an error message, take it out and see what happens
Dim su As StringUtils ' requires StringUtils library to be checked
Dim authInfo = su.EncodeBase64(basicAuth.GetBytes("UTF8"))
Dim j As HttpJob
j.Initialize("", Me)
j.Download("https://api.octopus.energy/v1/electricity-meter-points/1460001714995/meters/15P0459914/consumption/")
j.GetRequest.SetHeader("Authorization", $"Basic ${authInfo}"$) '<--- only other change (using right variable and, well,  SmartStrings)
Wait For (j) JobDone(j As HttpJob)
If j.Success = True Then
Log(j.GetString)
Else
Log(j.ErrorMessage)
End If
j.Release
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
Looks like the current (as is) HttpUtils2Service.bas allows only for two configurations when sending username/password combos:
1) Both username AND password are set, pass along username and password credentials (via ExecuteCredentials)
2) Otherwise pass no username/passwords via Execute

In that case it might work to not supply the username and password and instead modify the url like I did above.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
In that case it might work to not supply the username and password and instead modify the url like I did above.
It's worth a try to see if the underlying OkHttp3 library properly parses that type of URL. If it does, that would be a really easy work-around. If not, @MarcoRome's solution (with my slight modification) should definitely work (and would work on all platforms, no matter what underlying library is used). BTW, this forum rocks and I need more coffee.
 
Upvote 0

Colin Evans

Active Member
Licensed User
Longtime User
Hi, I have got an query as to why when i ask for local rates (without having to pass the username) I can 'parser the data but when I have to add the extra code to pass the username (API_Key) it gets the data but does enter my parser routine.

Sub Download
Dim Job As HttpJob
Dim httpText As String
httpText="https://api.octopus.energy/v1/produ...fs/E-1R-AGILE-18-02-21-E/standard-unit-rates/"
Job.Initialize("job1", Me)
Job.Download(httpText)
End Sub

Sub JobDone(job As HttpJob)
If job.Success = True Then
Select job.JobName
Case "job1"
Dim parser As JSONParser
parser.Initialize(job.GetString)
Dim from As String
Dim tim0 As String
Dim tim1 As String
Dim exV As String
Dim inV As String
Dim root As Map = parser.NextObject
Dim results As List = root.Get("results")

The above works and I can put the data in my table okay, whereas the following gets the data but doesn't enter the Sub routine Sub JoneDone(job as HttpJob)

Sub Download
Dim basicAuth As String = "sk_live_xxxxxxxxxxxxxxxxxxxx:" '
Dim su As StringUtils
Dim authInfo = su.EncodeBase64(basicAuth.GetBytes("UTF8"))
Dim job As HttpJob
job.Initialize("", Me)
job.Download("https://api.octopus.energy/v1/electricity-meter-points/1411105400005/meters/16P0547786/consumption/")
job.GetRequest.SetHeader("Authorization", $"Basic ${authInfo}"$)
Wait For (job) JobDone(job As HttpJob)
If job.Success = True Then
Log(job.GetString)
Else
Log(job.ErrorMessage)
End If
'job.Release
End Sub

Sub JobDone(job As HttpJob)
If job.Success = True Then
Select job.JobName
Case "job1"
Dim parser As JSONParser
parser.Initialize(job.GetString)
Dim from As String
Dim tim0 As String
Dim tim1 As String
Dim cons As String
Dim root As Map = parser.NextObject
Dim results As List = root.Get("results")
'
 
Upvote 0
Top