Recent

Author Topic: Accessing JSON data from Open Weater Maps API  (Read 3864 times)

CieloInvernale

  • Newbie
  • Posts: 5
Accessing JSON data from Open Weater Maps API
« on: December 19, 2016, 10:41:53 pm »
I'm trying to interface with OpenWeaterMaps API (http://openweathermap.org/). All API options and parameters are fully explained, anyway I've got troubles when I came to the Lazarus part (sorry, I'm a newbye with Lazarus...).

The application is simple: retrieve JSON data from the appropriate URL then parse each part as a simple string.

My program 'till now tries to retrieve the "main" data in JSON structure ("Clouds" in the following example JSON code - notice that there are 2 different "main" nodes in the response, I'm trying to access the first one nested within "weather" or, in other words, "weather->main:Clouds").

JSON API's response sample:

Code: Text  [Select][+][-]
  1. {"coord":
  2. {"lon":145.77,"lat":-16.92},
  3. "weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],
  4. "base":"cmc stations",
  5. "main":{"temp":293.25,"pressure":1019,"humidity":83,"temp_min":289.82,"temp_max":295.37},
  6. "wind":{"speed":5.1,"deg":150},
  7. "clouds":{"all":75},
  8. "rain":{"3h":3},
  9. "dt":1435658272,
  10. "sys":{"type":1,"id":8166,"message":0.0166,"country":"AU","sunrise":1435610796,"sunset":1435650870},
  11. "id":2172797,
  12. "name":"Cairns",
  13. "cod":200}
  14.  

My code so far (MYCITYID and MYAPPID are placeholders for the real keys, obviously not to be published here...):

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, fphttpclient,
  9.   fpjson, jsonparser;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Memo1: TMemo;
  17.     procedure FormCreate(Sender: TObject);
  18.   private
  19.     { private declarations }
  20.   public
  21.     { public declarations }
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.   jData : TJSONData;
  27.   jObject : TJSONObject;
  28.   wheater_main : String;
  29.  
  30. implementation
  31.  
  32. {$R *.lfm}
  33.  
  34. { TForm1 }
  35.  
  36. procedure TForm1.FormCreate(Sender: TObject);
  37. begin
  38.   jData := GetJSON(TFPHTTPClient.SimpleGet('http://api.openweathermap.org/data/2.5/weather?id=MYCITYID&appid=MYAPPID'));
  39.  
  40.   wheater_main := jData.FindPath('main').AsString;
  41.  
  42.   Memo1.Lines.Clear;
  43.  
  44.   Memo1.Lines.Add(wheater_main);
  45.  
  46. end;
  47.  
  48. end.
  49.  

Code compiles correctly and an executable is produced, anyway when I launch it it returns the following error:

Quote
Cannot convert data from object value.

Any idea about what's wrong with my code??

Thanks in advance for your time and attention.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Accessing JSON data from Open Weater Maps API
« Reply #1 on: December 20, 2016, 01:15:49 am »
The path main is not a complete end path, rather a path to a more complex (sub)structure in json format.

Either access the full path directly by supplying that full path (e.g. "main.pressure") or retrieve path "main" into a separate JSONData structure (jData2 := jData.FindPath('main')) and then search for the path e.g. "pressure").

edit: if your aim is really to get a string representation of the main json data structure then you can use jData.FindPath('main').AsJSon;
« Last Edit: December 20, 2016, 01:39:58 am by molly »

bytebites

  • Hero Member
  • *****
  • Posts: 589
Re: Accessing JSON data from Open Weater Maps API
« Reply #2 on: December 20, 2016, 05:10:17 am »
Code: Pascal  [Select][+][-]
  1. jData.FindPath('weather').Items[0].FindPath('main').AsString

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Accessing JSON data from Open Weater Maps API
« Reply #3 on: December 20, 2016, 05:31:10 am »
Ah, good point bytebites.

 I overlooked that there were multiple "main"'s  :-[

In that case:
Code: Pascal  [Select][+][-]
  1. Writeln('weather[0].main = ' , jData.FindPath('weather[0].main').AsString);

magleft

  • Full Member
  • ***
  • Posts: 102
Re: Accessing JSON data from Open Weater Maps API
« Reply #4 on: September 29, 2023, 12:06:21 pm »
I tried downloading data from openweathermap. The raw data is in the form shown below:
Code: Pascal  [Select][+][-]
  1. {"cod":"200","message":0,"cnt":40,"list":[{"dt":1695988800,"main":{"temp":300.37,"feels_like":300.12,"temp_min":300.37,"temp_max":301.04,"pressure":1018,"sea_level":1018,"grnd_level":1015,"humidity":39,"temp_kf":-0.67},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":31},"wind":{"speed":3.12,"deg":231,"gust":2.49},"visibility":10000,"pop":0.22,"rain":{"3h":0.17},"sys":{"pod":"d"},"dt_txt":"2023-09-29 12:00:00"},{"dt":1695999600,"main":{"temp":297.16,"feels_like":297.13,"temp_min":295.72,"temp_max":297.16,"pressure":1018,"sea_level":1018,"grnd_level":1016,"humidity":58,"temp_kf":1.44},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":41},"wind":{"speed":2.08,"deg":357,"gust":4.8},"visibility":10000,"pop":0.71,"rain":{"3h":1.47},"sys":{"pod":"d"},"dt_txt":"2023-09-29 15:00:00"},{"dt":1696010400,"main":{"temp":291.93,"feels_like":292,"temp_min":291.93,"temp_max":291.93,"pressure":1019,"sea_level":1019,"grnd_level":1017,"humidity":82,"temp_kf":0},"weather":[{"id":501,"main":"Rain","description":"moderate rain","icon":"10n"}],"clouds":{"all":54},"wind":{"speed":2.85,"deg":15,"gust":4.62},"visibility":10000,"pop":0.9,"rain":{"3h":3.45},"sys":{"pod":"n"},"dt_txt":"2023-09-29 18:00:00"},{"dt":1696021200,"main":{"temp":292.09,"feels_like":292.02,"temp_min":292.09,"temp_max":292.09,"pressure":1019,"sea_level":1019,"grnd_level":1017,"humidity":76,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":38},"wind":{"speed":1.82,"deg":57,"gust":2.37},"visibility":10000,"pop":0.6,"rain":{"3h":0.16},"sys":{"pod":"n"},"dt_txt":"2023-09-29 21:00:00"},{"dt":1696032000,"main":{"temp":292.82,"feels_like":292.72,"temp_min":292.82,"temp_max":292.82,"pressure":1018,"sea_level":1018,"grnd_level":1016,"humidity":72,"temp_kf":0},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"clouds":{"all":68},"wind":{"speed":1.55,"deg":21,"gust":1.54},"visibility":10000,"pop":0.34,"sys":{"pod":"n"},"dt_txt":"2023-09-30 00:00:00"},{"dt":1696042800,"main":{"temp":292.45,"feels_like":292.32,"temp_min":292.45,"temp_max":292.45,"pressure":1017,"sea_level":1017,"grnd_level":1015,"humidity":72,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":100},"wind":{"speed":1.55,"deg":35,"gust":1.52},"visibility":10000,"pop":0.37,"rain":{"3h":0.11},"sys":{"pod":"n"},"dt_txt":"2023-09-30 03:00:00"},
  2.  

I tried the following code without success:

Code: Pascal  [Select][+][-]
  1.   Http := TFPHTTPClient.Create(nil);
  2.    try
  3.      Http.IOTimeout := 1000;
  4.      Http.AllowRedirect := True;
  5.      jData := GetJSON(Http.Get(urltext));
  6.      Memo1.Lines.Add(jData.FindPath('list.items[0].main.items.temp').AsString);
  7.     Json.Free;
  8.    finally
  9.      Http.Free;
  10.    end;
  11.  
  12.  

Can anyone help?
windows 10 64

paweld

  • Hero Member
  • *****
  • Posts: 852
Re: Accessing JSON data from Open Weater Maps API
« Reply #5 on: September 29, 2023, 12:25:21 pm »
In your case, the path should look like this:
Code: Pascal  [Select][+][-]
  1. Memo1.Lines.Add(jData.FindPath('list[0].main.temp').AsString);
clearer example:
Code: Pascal  [Select][+][-]
  1. uses
  2.   fpjson;
  3.  
  4. procedure TForm1.Button1Click(Sender: TObject);
  5. const
  6.   json = '{"cod":"200","message":0,"cnt":40,"list":[{"dt":1695988800,"main":{"temp":300.37,"feels_like":300.12,"temp_min":300.37,"temp_max":301.04,"pressure":1018,"sea_level":1018,"grnd_level":1015,"humidity":39,"temp_kf":-0.67},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":31},"wind":{"speed":3.12,"deg":231,"gust":2.49},"visibility":10000,"pop":0.22,"rain":{"3h":0.17},"sys":{"pod":"d"},"dt_txt":"2023-09-29 12:00:00"},{"dt":1695999600,"main":{"temp":297.16,"feels_like":297.13,"temp_min":295.72,"temp_max":297.16,"pressure":1018,"sea_level":1018,"grnd_level":1016,"humidity":58,"temp_kf":1.44},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":41},"wind":{"speed":2.08,"deg":357,"gust":4.8},"visibility":10000,"pop":0.71,"rain":{"3h":1.47},"sys":{"pod":"d"},"dt_txt":"2023-09-29 15:00:00"},{"dt":1696010400,"main":{"temp":291.93,"feels_like":292,"temp_min":291.93,"temp_max":291.93,"pressure":1019,"sea_level":1019,"grnd_level":1017,"humidity":82,"temp_kf":0},"weather":[{"id":501,"main":"Rain","description":"moderate rain","icon":"10n"}],"clouds":{"all":54},"wind":{"speed":2.85,"deg":15,"gust":4.62},"visibility":10000,"pop":0.9,"rain":{"3h":3.45},"sys":{"pod":"n"},"dt_txt":"2023-09-29 18:00:00"},{"dt":1696021200,"main":{"temp":292.09,"feels_like":292.02,"temp_min":292.09,"temp_max":292.09,"pressure":1019,"sea_level":1019,"grnd_level":1017,"humidity":76,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":38},"wind":{"speed":1.82,"deg":57,"gust":2.37},"visibility":10000,"pop":0.6,"rain":{"3h":0.16},"sys":{"pod":"n"},"dt_txt":"2023-09-29 21:00:00"},{"dt":1696032000,"main":{"temp":292.82,"feels_like":292.72,"temp_min":292.82,"temp_max":292.82,"pressure":1018,"sea_level":1018,"grnd_level":1016,"humidity":72,"temp_kf":0},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"clouds":{"all":68},"wind":{"speed":1.55,"deg":21,"gust":1.54},"visibility":10000,"pop":0.34,"sys":{"pod":"n"},"dt_txt":"2023-09-30 00:00:00"},{"dt":1696042800,"main":{"temp":292.45,"feels_like":292.32,"temp_min":292.45,"temp_max":292.45,"pressure":1017,"sea_level":1017,"grnd_level":1015,"humidity":72,"temp_kf":0},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":100},"wind":{"speed":1.55,"deg":35,"gust":1.52},"visibility":10000,"pop":0.37,"rain":{"3h":0.11},"sys":{"pod":"n"},"dt_txt":"2023-09-30 03:00:00"}]}';
  7. var
  8.   jd: TJSONData;
  9.   ja: TJSONArray;
  10.   jo: TJSONObject;
  11.   i: Integer;
  12. begin
  13.   jd := GetJSON(json);
  14.   if jd.FindPath('list') <> nil then
  15.   begin
  16.     ja := TJSONArray(jd.FindPath('list'));
  17.     if ja.Count > 0 then
  18.     begin
  19.       jo := TJSONObject(ja.Items[0]);
  20.       if jo.FindPath('main.temp') <> nil then
  21.         Memo1.Lines.Add(Format('%5d     %f', [i, jo.FindPath('main.temp').AsFloat]));
  22.     end;
  23.     ////or all items
  24.     //for i := 0 to ja.Count - 1 do
  25.     //begin
  26.     //  jo := TJSONObject(ja.Items[i]);
  27.     //  if jo.FindPath('main.temp') <> nil then
  28.     //    Memo1.Lines.Add(Format('%5d     %f', [i, jo.FindPath('main.temp').AsFloat]));
  29.     //end;
  30.   end;
  31.   jd.Free;
  32. end;
  33.  
Best regards / Pozdrawiam
paweld

TRon

  • Hero Member
  • *****
  • Posts: 1872
Re: Accessing JSON data from Open Weater Maps API
« Reply #6 on: September 29, 2023, 12:31:30 pm »
Also note that you get a list of 40! entries. It is a forecast based upon this. I have no idea if the data in the list is sorted in a particular order (I assume it is returned with a sort on dt values).

magleft

  • Full Member
  • ***
  • Posts: 102
Re: Accessing JSON data from Open Weater Maps API
« Reply #7 on: September 29, 2023, 01:39:20 pm »
Indeed, it concerns 40 registrations. I modified the example paweld sent a bit, but it doesn't work. What am I doing wrong;

Code: Pascal  [Select][+][-]
  1. procedure TFwheather.Button2Click(Sender: TObject);
  2. var
  3.   Http: TFPHTTPClient;
  4.   info, Content: string;
  5.   Json: TJSONData;
  6.   JsonObject: TJSONObject;
  7.   wheater_main : String;
  8.   jdata:TJSONData;
  9.   enum: TJSONEnum;
  10.   jd: TJSONData;
  11.   ja: TJSONArray;
  12.   jo: TJSONObject;
  13.   i: Integer;
  14.   urltext :String;
  15. begin
  16.   urltext:='api.openweathermap.org/data/2.5/forecast?lat=39.1520282768&lon=20,9768486023&APPID=45a17f4586f55c714ae04d9c36e8a834' ;//{API key}
  17.   try
  18.   Http.IOTimeout := 1000;
  19.   Http.AllowRedirect := True;
  20.   jd := GetJSON(Http.Get(urltext));
  21.   if jd.FindPath('list') <> nil then
  22.   begin
  23.     ja := TJSONArray(jd.FindPath('list'));
  24.     if ja.Count > 0 then
  25.  {   begin
  26.       jo := TJSONObject(ja.Items[0]);
  27.       if jo.FindPath('main.temp') <> nil then
  28.         Memo1.Lines.Add(Format('%5d     %f', [i, jo.FindPath('main.temp').AsFloat]));
  29.     end;
  30. }    ////or all items
  31.     for i := 0 to ja.Count - 1 do
  32.     begin
  33.       jo := TJSONObject(ja.Items[i]);
  34.       if jo.FindPath('main.temp') <> nil then
  35.         Memo1.Lines.Add(Format('%5d     %f', [i, jo.FindPath('main.temp').AsFloat]));
  36.     end;
  37.   end;
  38.  
  39.   finally
  40.   jd.Free;
  41.   end;
  42. end;
  43.  
  44.  
windows 10 64

rvk

  • Hero Member
  • *****
  • Posts: 5652
Re: Accessing JSON data from Open Weater Maps API
« Reply #8 on: September 29, 2023, 01:48:23 pm »
Indeed, it concerns 40 registrations. I modified the example paweld sent a bit, but it doesn't work. What am I doing wrong;
Well. The first thing you are doing wrong is not telling us what the problem is  ;)
Error message????? Crash????
What does happen?

Second... looking at your code... I see a http declaration in the procedure but I don't see you creating the object itself.
So you are missing a
Code: Pascal  [Select][+][-]
  1. http := TFPHTTPClient.Create(nil);
  2. try
  3.   //...
  4. finally
  5.   http.free;
  6. end;
  7.  

Also... urltext needs to contain a protocol (so https:// in front of it).

And don't forget to include opensslsockets in your uses.
« Last Edit: September 29, 2023, 01:54:08 pm by rvk »

paweld

  • Hero Member
  • *****
  • Posts: 852
Re: Accessing JSON data from Open Weater Maps API
« Reply #9 on: September 29, 2023, 02:11:59 pm »
First of all, don't share your API key - they can block your access.
Code: Pascal  [Select][+][-]
  1. uses
  2.   fpjson, fphttpclient, opensslsockets;
  3.  
  4. procedure TForm1.Button1Click(Sender: TObject);
  5. const
  6.   url = 'https://api.openweathermap.org/data/2.5/forecast?lat=39.1520282768&lon=20,9768486023&APPID={yourAPPID}';
  7. var
  8.   jd: TJSONData;
  9.   ja: TJSONArray;
  10.   jo: TJSONObject;
  11.   i: Integer;
  12.   hc: TFPHttpClient;
  13.   json: String;
  14. begin
  15.   hc := TFPHttpClient.Create(nil);
  16.   hc.AllowRedirect := True;
  17.   try
  18.     json := hc.Get(url);
  19.     if json <> '' then
  20.     begin
  21.       jd := GetJSON(json);
  22.       if jd.FindPath('list') <> nil then
  23.       begin
  24.         ja := TJSONArray(jd.FindPath('list'));
  25.         for i := 0 to ja.Count - 1 do
  26.         begin
  27.           jo := TJSONObject(ja.Items[i]);
  28.           if jo.FindPath('main.temp') <> nil then
  29.             Memo1.Lines.Add(Format('%5d     %f', [i, jo.FindPath('main.temp').AsFloat]));
  30.         end;
  31.       end;
  32.       jd.Free;
  33.     end
  34.     else
  35.       ShowMessage('Empty response');
  36.   finally
  37.     hc.Free;
  38.   end;
  39. end;    
« Last Edit: September 29, 2023, 02:16:18 pm by paweld »
Best regards / Pozdrawiam
paweld

magleft

  • Full Member
  • ***
  • Posts: 102
Re: Accessing JSON data from Open Weater Maps API
« Reply #10 on: September 29, 2023, 02:22:30 pm »
I would like to apologize as the code was not working due to my mistake. Due to an error in the url I didn't have the prefix ' https://'. Now all works.
Thank you all for your help.
windows 10 64

 

TinyPortal © 2005-2018