AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Problem bei JSON-Abfrage

Ein Thema von Maekkelrajter · begonnen am 20. Sep 2020 · letzter Beitrag vom 4. Nov 2020
Antwort Antwort
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.656 Beiträge
 
Delphi 12 Athens
 
#1

AW: Problem bei JSON-Abfrage

  Alt 20. Sep 2020, 16:56
Nunja, GetValue gibt einen TJSONValue zurück, welcher eine Klasse ist. Greift man auf den Wert einer nicht instanzierten Klasse zu, macht es eben Rumms, deshalb sind das keine Workarounds, sondern lediglich defensive Programmierung.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#2

AW: Problem bei JSON-Abfrage

  Alt 20. Sep 2020, 17:04
Kannst du mal als Beispiel das JSON für eine funktionierende Antwort hier posten? Das müsste noch wesentlich eleganter gehen.

Auch deine aktuelle Lösung für die Authentifizierung würde ich gerne mal sehen (natürlich ohne echte Daten). Da ist oft auch noch Raum für Vereinfachungen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
157 Beiträge
 
Delphi 12 Athens
 
#3

AW: Problem bei JSON-Abfrage

  Alt 20. Sep 2020, 22:33
Kannst du mal als Beispiel das JSON für eine funktionierende Antwort hier posten? Das müsste noch wesentlich eleganter gehen.

Auch deine aktuelle Lösung für die Authentifizierung würde ich gerne mal sehen (natürlich ohne echte Daten). Da ist oft auch noch Raum für Vereinfachungen.
Ich war ja froh, als ich das Ding endlich am laufen hatte. Ich zweifele auch nicht im geringsten daran dass der Code noch verbesserungsfähig ist. Hier also die Authentifizierungs Routinen, die ich übrigens zum Teil aus dem Beispiel-Programm abgekupfert habe:
Delphi-Quellcode:

{
type
    TSpManager = class(TForm)
    [...]
    IdHTTPServer1: TIdHTTPServer;
    OAuth2Authenticator1: TOAuth2Authenticator;
    RESTClient1: TRESTClient;
    RESTRequest1: TRESTRequest;
    RESTResponse1: TRESTResponse;
    procedure IdHTTPServer1CommandGet(AContext: TIdContext;
      ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
    [...]
}


Procedure TSpManager.SendData(s:string);
 var
    CDStruct: TCopyDataStruct;
    copytext: ansistring;
begin
  copytext:= s;
  begin
    CDStruct.dwData:= 0;
    CDStruct.cbData:= length(Copytext) + 1;
    CDStruct.lpData:= @CopyText[1];
    SendMessage(MainHandle, WM_COPYDATA,1,integer(@CDStruct));
  end;
end;


Procedure TSpManager.AuthorizeSpotifyAccess;
begin
  IdHTTPServer1.Active := True;
  OAuth2Authenticator1.ResetToDefaults;
  OAuth2Authenticator1.ClientID := Stcf.AccessData.clientID; // Bei der Registrierung von Spotify zugeteilt (lokal gespeichert)
  OAuth2Authenticator1.ClientSecret := Stcf.AccessData.ClientSecret; // Bei der Registrierung von Spotify zugeteilt (lokal gespeichert)
  OAuth2Authenticator1.AuthorizationEndpoint := 'https://accounts.spotify.com/authorize';
  // Bereiche, auf die Benutzerzugriff erlaubt sein soll
  OAuth2Authenticator1.Scope := 'playlist-read-private user-read-private user-library-read';
  // Weiterleitungsseite mit dem aktuellen AUTORISIERUNGSCODE
  OAuth2Authenticator1.RedirectionEndpoint := 'http://localhost:9090';
  // Die Definition des URI zum Generieren des AUTORISIERUNGSCODES
  ShellExecute(0, 'OPEN', PChar(Self.OAuth2Authenticator1.AuthorizationRequestURI), '', '', SW_SHOWNORMAL);
end;


procedure TSpManager.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  var s:string;
begin
  // Abfrage-String validiert
  if (ARequestInfo.Params.IndexOfName('code') = -1) then Exit;
  // Definition des ACCESS CODE, den wir von der Weiterleitungsseite abrufen
  OAuth2Authenticator1.AuthCode := ARequestInfo.Params.Values['code'];
  // End-point für die Generierung des ACCESS TOKEN
  OAuth2Authenticator1.AccessTokenEndpoint := 'https://accounts.spotify.com/api/token';
  // Definieren des ACCESS TOKEN aus dem AUTORISIERUNGSCODE
  OAuth2Authenticator1.ChangeAuthCodeToAccesToken;
  // Antwort an den Browser
  AResponseInfo.ContentText := '<html><body><script language=javascript>window.close();</script>Vielen Dank, dass Sie den Zugriff erlaubt haben!</body></html>';
  // Operation erfolgreich!
  s:= OAuth2Authenticator1.AccessToken;
  SendData(s); // Schickt die Daten nur zur Information an das Hauptfenster;
  FAuthorized:= s <> ''; // Boolean als Flag
end;
Im Anhang ein JSON mit Playlist-Daten, das Spotify nach einem Request mit dem accesspoint '/v1/playlists/{playlist_id}' liefert. Für meine Zwecke werden nur wenige Daten ausgelesen und in Zieldateien geschrieben (wenn vorhanden)
Für Anregungen und Verbesserungsvorschläge bin ich ausgesprochen dankbar!

Gruß LP
Angehängte Grafiken
Dateityp: jpg Screenshot200920_2.jpg (123,2 KB, 89x aufgerufen)
Angehängte Dateien
Dateityp: txt RESTResponse_Content.txt (31,8 KB, 28x aufgerufen)

Geändert von Maekkelrajter (20. Sep 2020 um 22:41 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#4

AW: Problem bei JSON-Abfrage

  Alt 20. Sep 2020, 23:53
Ich baue mir da immer anhand der API passende Objektstrukturen zusammen. Dann wird der Abruf nicht nur wesentlich simpler, man bekommt auch gleich die Typsicherheit dazu. Ich habe hier nur einen Teil der Felder deklariert. Alle übrigen werden ignoriert. Das lässt sich relativ leicht erweitern.
Delphi-Quellcode:
uses
  System.JSON, REST.Json;

type
  TArtist = class
  private
    FName: string;
  public
    property Name: string read FName;
  end;

  TAlbum = class
  private
    FArtists: TArray<TArtist>;
    FName: string;
  public
    property Artists: TArray<TArtist> read FArtists;
    property Name: string read FName;
  end;

  TTrack = class
  private
    FAlbum: TAlbum;
    FArtists: TArray<TArtist>;
    FId: string;
    FName: string;
  public
    property Album: TAlbum read FAlbum;
    property Artists: TArray<TArtist> read FArtists;
    property Id: string read FId;
    property Name: string read FName;
  end;

  TUser = class
  private
    FDisplay_name: string;
  public
    property Display_name: string read FDisplay_name;
  end;

  TPlaylistTrack = class
  private
    FAdded_at: TDateTime;
    FAdded_by: TUser;
    FIs_local: Boolean;
    FTrack: TTrack;
  public
    property Added_at: TDateTime read FAdded_at;
    property Added_by: TUser read FAdded_by;
    property Is_local: Boolean read FIs_local;
    property Track: TTrack read FTrack;
  end;

  TPaging<T: class> = class
  private
    FHref: string;
    FItems: TArray<T>;
    FLimit: Integer;
    FNext: string;
    FOffset: Integer;
    FPrevious: string;
    FTotal: Integer;
  public
    property Href: string read FHref;
    property Items: TArray<T> read FItems;
    property Limit: Integer read FLimit;
    property Next: string read FNext;
    property Offset: Integer read FOffset;
    property Previous: string read FPrevious;
    property Total: Integer read FTotal;
  end;

  TPlayList = class
  private
    FName: string;
    FTracks: TPaging<TPlaylistTrack>;
  public
    property Name: string read FName;
    property Tracks: TPaging<TPlaylistTrack> read FTracks;
  end;
Der eigentliche Abrufcode beschränkt auf die im Eingangspost gezeigten Daten sieht dann so aus:
Delphi-Quellcode:
function TSpManager.GetPlaylistTracks(PlaylistID: string; List: TStrings): string; // Liste der Track-IDs aus Playlist holen
var
  playlist: TPlaylist;
  track: TPlaylistTrack;
begin
  result := '';
  RESTRequest1.Resource := 'v1/playlists/{PlaylistID}'; // Accesspoint der Spotify Web-API
  RESTRequest1.AddParameter('PlaylistID', PlaylistID);
  RESTRequest1.Execute;
  if RestResponse1.JSONValue is TJSONObject then begin
    playlist := TJson.JsonToObject<TPlaylist>(TJSONObject(RESTResponse1.JSONValue));
    if playlist <> nil then begin
      Result := playlist.Name;
      if playlist.Tracks <> nil then begin
        for track in playlist.Tracks.Items do begin
          if track.Track <> nil then begin
            List.Add(track.Track.Id);
          end;
        end;
      end;
    end;
  end;
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
157 Beiträge
 
Delphi 12 Athens
 
#5

AW: Problem bei JSON-Abfrage

  Alt 21. Sep 2020, 11:16
Ich baue mir da immer anhand der API passende Objektstrukturen zusammen. Dann wird der Abruf nicht nur wesentlich simpler, man bekommt auch gleich die Typsicherheit dazu. Ich habe hier nur einen Teil der Felder deklariert. Alle übrigen werden ignoriert. Das lässt sich relativ leicht erweitern.
Delphi-Quellcode:
uses
  System.JSON, REST.Json;

type
  TArtist = class
  private
    FName: string;
  public
    property Name: string read FName;
  end;
  ...
Vielen Dank für den ausführlichen Vorschlag. Auf eine solche wirklich elegante Lösung wäre ich als bekennender OOP-Muffel natürlich nie gekommen. Außerdem mache ich mir selten die Mühe, ein solch universelles und wiederverwendbares Konzept zu erstellen. Bei mir steht am Anfang der Wunsch nach einem bestimmten Feature, und das soll dann schnell und mit möglichst geringem (Lern-) Aufwand realisiert werden. Wenn erst mal alles läuft, gehe ich daran, den Code und das Handling zu 'optimieren', immer mit der 'Rohversion' als Rückfalloption. Wie ich schon früher schrieb, betreibe ich das Programmieren als Hobby und fast ausschließlich für den Eigenbedarf, auch gewissermaßen als 'Brain-Jogging' anstelle von Kreuzworträtseln, was in meinem Alter (73) vielleicht 'normal' wäre. Da ist der Workflow wohl etwas anders als bei einem professionellen Entwickler. Aber dennoch habe ich den Ehrgeiz, allzugroße Stümperei zu vermeiden und möglichst kompakte und strukturierte Lösungen zu finden. Da wird mich dieser Code-Happen (von einem 'Schnipsel' kann man ja wohl hier nicht sprechen) mit Sicherheit ein enormes Stück weiter bringen!

Gruß LP
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.629 Beiträge
 
Delphi 12 Athens
 
#6

AW: Problem bei JSON-Abfrage

  Alt 21. Sep 2020, 11:40
Es sollte nicht unerwähnt bleiben, dass der Code alles andere als vollständig ist. So werden die erzeugten Objekt-Instanzen unter non-ARC Plattformen nicht wieder freigegeben. Das müsste man noch im Destructor ergänzen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.656 Beiträge
 
Delphi 12 Athens
 
#7

AW: Problem bei JSON-Abfrage

  Alt 21. Sep 2020, 11:54
Ich mache das übrigens ähnlich, nur dass das bei mir normalerweise keine Klassen, sondern Records sind. Diese verfügen über eine Klassenfunktion FromJSON, welche ein TJSONObject übernimmt und einen befüllten Record zurückgibt.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:59 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz