‼️ Steemit API - DIY ⚒ Liste der zuletzt erhaltenen Upvotes! ⬆️

in #deutsch6 years ago

Die Verwendung der Steemit API geht in die 2. Runde

Dieses Mal zeige ich euch, wie ihr eine Liste der zuletzt erhaltenen Upvotes angezeigt bekommt. Dazu nutzen wir die Steemit API auf die wir mit JavaScript zugreifen. Viel Spaß!

work-731198_1920_2.png

1. Das Grundgerüst

Bevor wir in die vollen gehen, brauchen wir erstmal ein Grundbaustein, auf dem wir aufsetzen können. Dazu legen wir eine HTML-Datei an und fügen die bekannten Basis-Tags <html>, <head> und <body> ein. Zusätzlich binden wir die API von Steemit in das <head>-Tag ein. Weiterhin brauchen wir Platz für unseren Code. Deswegen öffnen und schließen wir im <head>-Tag ein <script>-Bereich. Im body-Bereich bauen wir ein <div>ein, dass die ID "output" trägt. Hier wird später unsere Ausgabe erfolgen.

<html>

  <head>
    <script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>

    <script language="JavaScript">

      // Unser Code

    </script>
  </head>

  <body>

    <div style="white-space: pre;" id="output"></div>

  </body>

</html>

2. Erster Aufruf der API-Funktion

Alle Funktionen der JavaScript-Steemit-API findet ihr hier. Auf dieser Seite findet ihr auch die Funktion steem.api.getAccountHistory(account, from, limit, function(err, result) {});, die wir für unser Vorhaben benötigen.

Wir sehen an dieser Stelle schon, dass die Übergabeparameter account, from und limit erwartet werden. Doch was steckt hinter diesen Werten. Hier eine tabellarische Übersicht:

VariableTypVerwendungszweck
account   stringBenutzer, dessen Historie abgerufen werden soll.
fromuint32_tDer früheste Zeitpunkt, von dem die Daten abgeholt werden sollen als Zahl.
limituint32_tDie Anzahl der Einträge, die maximal abgerufen werden sollen (API interne Grenze bei 10.000)

Also fügen wir in unseren Codebereich folgendes Script inkl. Variablen ein:

var account = "cuby";
var from = Date.parse('2015-01-01T00:00:00');
var limit = 10; //max. 10.000

steem.api.getAccountHistory(account, from, limit, function(err, result) {
  console.log(err, result);
});

 
Date.parse('2015-01-01T00:00:00') ist eine Funktion, die uns die Zeit, seit dem übergebenen Datum, als uint32_t zurückgibt. Jetzt können wir die HTML-Datei im Browser öffnen und uns die ersten Ergebnisse in der Konsole anschauen (hier eine Erklärung, wie man zur Konsole des jeweiligen Browsers kommt). Die Ausgabe sollte in etwa so aussehen:

vote-note-img-1.png


3. Aus der Konsole in den Browser

Da die Ausgabe in der Konsole nicht allzu übersichtlich ist, wollen wir nun die Daten auf der Browseroberfläche (im body-Tag) anzeigen lassen. Was müssen wir dazu tun? Zu allererst brauchen wir ein paar Prüfungen, um sicher zu gehen, dass der API-Call sauber verlaufen ist und wir auch Daten haben, mit den wir arbeiten können. Wir ersetzen console.log(err, result); durch folgenden Code:

if(!err && result != undefined && result.length > 0){

     document.getElementById("output").textContent = JSON.stringify(result, null, "\t");

}

 
Da wir jetzt sicher sein können, dass bei der weiteren Arbeit, Daten zu Verfügung stehen, können wir diese auf der Oberfläche bringen. Dazu holen wir uns das Ausgabe-Element mit der ID "output" und fügen seinem Textinhalt das Ergebnis des API-Calls hinzu. Um das Ergebnis lesbarer zu machen, jagen wir es vorher durch die Methode JSON.stringify(result, null, "\t"), die für uns die Zeichenkette formatiert. Bei erneutem Aufruf der HTML-Datei sollte euer Browser etwa so aussehen:

vote-note-img-2.png


4. Analyse der Ausgabe

Das erste was auffällt ist, dass jeder Eintrag mit einer ID behaftet ist, an der ein Objekt mit den eigentlich interessanten Daten hängt. Im Objekt finden wir zum einen den timestamp, der uns mitteilt, wann der Eintrag entstanden ist und zum anderen das Objekt op.

Das erste Element von op signalisiert uns, um welche Art Eintrag es sich handelt. Wir wollen nur jene Einträge berücksichtigen, die "votes" beinhalten. Weiterhin ist im op-Objekt der Author des gevoteten Inhalts, der "Permlink" zum Inhalt und der Voter selbst angegeben. Abschließend wird die Gewichtung des Votes unter weightfestgehalten.

Was heißt das jetzt für uns? Wir können über die gewonnen Erkenntnisse eine Filterung auf die erzielten Ergebnisse anwenden, um dem gesetzten Ziel einen Schritt näher zu kommen: Die Auflistung der erhaltenen Upvotes.


5. Filterung der Daten

Um die Filterung der Daten umsetzen zu können, müssen wir zuerst eine Schleife einbauen, die über die Ergebnisse geht. Dann können wir je Ergebnis die enthaltenen Daten prüfen und aussortieren (Nur "vote" und nicht den Benutzer aus der Variable account als Voter). Wo wir gerade bei der Sortierung sind: die Ergebnisse werden aus dem API-Call von alt nach neu zurückgegeben. Um das zu ändern, laufen wir in der Schleife vom letzten Element bis zum Ersten:

for (var i = result.length - 1; i >= 0; i--) {

  if (result[i][1].op[0] == "vote" && result[i][1].op[1].voter != account) {

    var type = (result[i][1].op[1].permlink.includes("re-")) ? "Kommentar" : "Post";

    var datum = new Date(result[i][1].timestamp).toLocaleDateString("de-DE", { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });

    document.getElementById("output").textContent += JSON.stringify(result[i], null, "\t");

  }

}

 
Die Ausgabe des ausgeführten Scripts hat sich nun nur minimal geändert. Statt der ältesten Einträge bekommen wir nun die neusten zuerst angezeigt. Weiterhin sind alle Einträge nicht ausgegeben worden, die keine Upvotes für den angegebenen Account sind. Hinweis: Das in der Codezeile document.getElementById("output").textContent += JSON.stringify(result[i], null, "\t"); vorhandene += sorgt dafür, dass nicht nur das letzte verarbeitete Ergebnis auf der Seite angezeigt wird, sondern dass es zu den bereits vorhandenen hinzugefügt wird. Dies wird auch konkatenieren genannt.

In der Variable typespeichern wir, ob es sich um einen Upvote für einen Kommentar oder einen Post handelt. Das können wir daran erkenne, dass im permlinkdes Votes ein vorangestelltes "re-" steht, das auf die Antwort eines Posts via Kommentar hindeutet.

Damit der Zeitpunkt, an dem der Vote getätigt wurde nicht in der unschön formatierten Art und Weise auf unserer Oberfläche angezeigt wird, speichern wir das Ergebnis der formatierten Ausgabe in der Variable datum.


6. Bootstrap anbinden

Das bis hierhin erreichte Ergebnis ist schon ganz nett, aber die Lesbarkeit der JSON-Strings ist im Vergleich zu gestyltem HTML nur ausreichend. Deswegen ist der nächste Schritt, den wir machen werden, die Anbindung des Frameworks Bootstrap (Hier geht es zur Webseite).

http://getbootstrap.com/assets/img/bootstrap-stack.png

Für die Anbindung benötigen wir zum einen die CSS-Datei und die JS-Dateien des Frameworks. Alles fügen wir dem head-Tag hinzu:

<html>

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

[...]

 
An dieser Stelle sollte sich auf unserer Oberfläche nur die Schriftart geändert haben. Alles andere bleibt vorerst so wie es ist.


7. Die Daten aufbereiten

Damit unsere Einträge nicht einfach als Text auf die Webseite geworfen werden, müssen wir die für uns relevanten Daten raussuchen und in einem HTML-Element verpacken, das wir danach der Oberfläche hinzufügen.

var vote = {
  voter: result[i][1].op[1].voter,
  timestamp: datum,
  weight: result[i][1].op[1].weight / 100,
  typ: type
}

 
Das Objekt vote ermöglicht uns einen super einfachen Zugriff auf die enthaltenen Daten. Das HTML-Element legen wir als einfach String-Variable an und konkatenieren die Werte aus vote mit hinein. Anschließend fügen wir das HTML-Element dem div-Tag mit der ID "output" hinzu:

var htmlElement = '<div><p>@' + vote.voter + ' hat deinen ' + vote.typ + ' mit ' + vote.weight + '% gevoted!' + '</p>' +
              '<p>' + vote.timestamp + '</p></div>';

$("#output").append(htmlElement);

 
Nach diesen Änderungen sieht unsere Webseite schon wesentlich lesbarer aus. Auch wenn sie noch sehr spartanisch wirkt. Aber darum kümmern wir uns im nächsten Schritt.

vote-note-img-3.png


8. Es darf ruhig hübsch aussehen

Zwar haben wir bereits in Schritt 6 das Framework Bootstrap angebunden, aber wir verwenden noch keine Klassen, um auf die bereitgestellten Elemente zugreifen zu können. Ich habe mich für die Komponente "Alert" entschieden, um unsere Einträgen auf der Oberfläche zu visualisieren.

vote-note-img-4.png

Was müssen wir dafür machen, damit unserer Votes so aussehen, wie die Alert-Komponente von Bootstrap? Zuerst kopieren wir uns den auf der Webseite von Bootstrap und fügen ihn unserem Code hinzu. Anschließend schieben wir unsere Daten in die HTML-Struktur und fügen das alles je Eintrag dem div-Tag mit der ID "output" hinzu. Fertig!

var htmlElement = '<div class="alert alert-info role="alert">' +
                    '<strong>@' + vote.voter + ' </strong> hat deinen ' + vote.typ + ' mit ' + vote.weight + '% gevoted!' +
                    '<hr>' +
                    '<p class="mb-0">' + vote.timestamp + '</p>' +
                  '</div>';

$("#output").append(htmlElement);

 
Ein erneuter Aufruf der Webseite und: Wow! Das sieht doch schon gar nicht mal so schlecht aus. Jetzt wollen wir noch die Anzahl der Vote-Einträge bestimmen können.

9. Zeige die letzen 25 Votes

Zu allererst setzen wir die Variable limit auf 1000 und fügen zwei weitere Variablen hinzu. Die Variable MAX speichert die Anzahl der maximal anzuzeigenden Vote-Einträge (in unserem Fall 25). counter hilft uns dabei zu zählen, wie viele Einträge wir bereits zusammen haben.

var limit = 1000;  //max. 10.000

var MAX = 25;
var counter = 0;

 
Kommen wir dazu diese beiden neuen Variablen auch zu verwenden. Wir müssen unseren Quellcode an ein paar Stellen anpassen:

$("#output").append(htmlElement);

counter++;

if(counter >= MAX){
  break;
}

 
Nachdem wir einen Eintrag der Oberfläche hinzugefügt haben zählen wir counterum einen hoch. Danach prüfen wir, ob counter bereits >= MAX ist. Wenn dem so ist, verlassen wir die for-Schleife durch einen break.

9. Das Ergebnis

vote-note-img-5.png

Was lässt sich zu dem Ergebnis sagen? Wir haben eine Oberfläche, die beim Aktualisieren die neusten Upvotes für den im Code hinterlegten Account anzeigt. Die Upvotes werden von neu nach alt sortiert und es wird zwischen Kommentar und Post unterschieden. So weit so gut.


10. Fazit und Verbesserungen

Es gibt viele Stellen an denen sich der Code noch optimieren lässt.

Das erste was mir einfällt wäre die Oberfläche. Auf dieser könnte, wenn es um einen Upvote für einen Post geht, ebenfalls der Titel des Posts angezeigt werden. Das habe ich versucht umzusetzen. Allerdings war ich mit der Art der Umsetzung sehr unzufrieden und habe mich deswegen dagegen entschieden, diese Lösung mit in diesen Beitrag einzubringen.

Weiterhin hat man keine Möglichkeit von der Oberfläche den Accountnamen, das Limit oder andere Stellschrauben zu verändern. Eine einfache Eingabemaske würde an diese Stelle vermutlich schon Abhilfe schaffen. Vielleicht ein Thema für meinen nächsten Beitrag.

Außerdem muss man die Seite manuell neu laden, um die Daten zu aktualisieren. Ein Listener darauf, ob es etwas neues gibt, ist hier noch nicht vorhanden. Auch eine Sache die sich im Nachhinein noch umsetzen lässt.

girl-1064659_1920.jpg

Zum Schluss aber der größte Kritikpunkt: Die Ladezeit. Prinzipiell funktioniert der Code so wie er dort steht, ABER wenn ein Account eingetragen wird, der im Bereich der limit Variable weniger als 25 Upvotes erhalten hat, dann werden auch keine 25 Upvotes angezeigt. Klingt erstmal logisch. Klar könnte man dem entgegen wirken und zuerst den Account aus der API ziehen, das Eintrittsdatum feststellen, das in die Variable from laden und die limit Variable auf das Maximum von 10.000 setzen, aber ist das wirklich die brauchbarste Lösung? Ich denke nicht ;)


Danke fürs Lesen

CuBy

PS: Fehler bei der Rechtschreibung und Grammatik sind stilistische Mittel und vom Autor bewusst platziert worden. :-D

Das Bild konnte nicht geladen werden :( [Hier](https://i.imgur.com/GiapkPg.gif) geht es zur Quelle!


Der gesamte Code

<html>

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

    <script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>

    <script language="JavaScript">

      var account = "cuby";
      var from = Date.parse('2015-01-01T00:00:00');
      var limit = 200; //max. 10.000

      var MAX = 25;
      var counter = 0;

      steem.api.getAccountHistory(account, from, limit, function(err, result) {

        if(!err && result != undefined && result.length > 0){

          for (var i = result.length - 1; i >= 0; i--) {

            if (result[i][1].op[0] == "vote" && result[i][1].op[1].voter != account) {

              var type = (result[i][1].op[1].permlink.includes("re-")) ? "Kommentar" : "Post";

              var datum = new Date(result[i][1].timestamp).toLocaleDateString("de-DE", { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });

              var vote = {
                voter: result[i][1].op[1].voter,
                timestamp: datum,
                weight: result[i][1].op[1].weight / 100,
                typ: type
              }

              var htmlElement = '<div class="alert alert-info role="alert">' +
                                  '<strong>@' + vote.voter + ' </strong> hat deinen ' + vote.typ + ' mit ' + vote.weight + '% gevoted!' +
                                  '<hr>' +
                                  '<p class="mb-0">' + vote.timestamp + '</p>' +
                                '</div>';

              $("#output").append(htmlElement);

              counter++;

              if(counter >= MAX){
                break;
              }

            }

          }



        }

      });

    </script>
  </head>

  <body>

    <div style="white-space: pre;" id="output"></div>

  </body>

</html>
Sort:  

Seufz....
Lieber, lieber @cuby, ich bemühe mich sehr und lese immer brav zu Ende...
😘 Chriddi

Dieses Tutorial ist dir besonders gut gelungen @cuby. Schoen das du es auch front end maessig die Votes schoen ausgibst.

Ein weiterer Highlight ist das du fuer die Console auf eine Google-Suche verweist :D

Ich freue mich auf viele weitere Tutorials von dir!

Vielen Dank für dein Feedback 😁

Hey coole Einführings ins Thema! Vorallem Bootstrap sieht echt gut aus.
Ich bin selber mit js und html am programmieren und vorallem das stylen der website bereitet mir mühe. Bootstrap könnte eine gute lösung sein.
Danke für den Artikel.

Danke! Das finde ich auch so toll an Bootstrap. Man kann sich von Anfang an auf die Funktionalitäten der Anwendung konzentrieren, ohne direkt an die Gestaltung der UI denken zu müssen. Alles was temporär ausgegeben wird, sieht vorerst schon schick aus und dann nach und nach angepasst werden 👍🏻

@resteem.bot
Resteemed to over 12100 followers and 100% upvoted. Thank you for using my service!

Send 0.200 Steem or 0.200 Steem Dollar and the URL in the memo to use the bot.
Read here how the bot from Berlin works.

We are happy to be part of the APPICS bounty program. APPICS is a new social community based on Steem. The presale was sold in 26 minutes. The ICO will start soon. You can get a account over our invite link: https://ico.appics.com/login?referral=1fRdrJIW

@resteem.bot

Coole Reihe für Einsteiger. Gut geschrieben.

Nur zwei Anmerkungen:

  1. Würde ich den Javascript Code auslagern und genauso einbinden wie die Steemit API
  2. Würde ich JQuery einbinden, da damit einiges einfacher wird, vor allem die a
    Adressierung von HTML Elementen

Lernt natives js. Query selectors können mittlerweile alle Browser. Den jquery Overhead kannst komplett meiden.

Kannst du das etwas mehr ausführen? Ich komme da nicht ganz mit 😁

Oh ja natürlich. manchmal erscheinen mir solche Sachen recht klar. sorry.

Folgendes, jQuery ist ja locker 10 Jahre alt, damals war es nicht in jedem Browser möglich Query Selektoren auszuführen.

Query Selektoren sind ".css-class .css-class"

Mittlerweile ist das aber nativ in jedem Browser möglich.
Erklärung:
https://developer.mozilla.org/de/docs/Web/API/Document/querySelector

Nun, d.h. anstatt $('.css-class .css-class') kannst du auch document.querySelectorAll('.css-class .css-class') machen.
Unter dem Mozilla Link findest du weitere Beispiele.

Wie du siehst ist querySelector und oder querySelectorAll mittlerweile überall unterstützt:
https://caniuse.com/#search=querySelector

Wieso native nutzen?

Das ist einfach, es ist schneller. jQuery hat einige Abfragen ob die API unterstützt wird, hat eigene Selektoren eingeführt wofür extra Parser gebaut sind. Wenn du nun jQuery weglässt nutzt du die direkte Browser Engine ohne weitere JavaScript Schicht.
Zusätzlich hast du natürlich die Ladezeit von jQuery nicht. jQuery ist einmal nicht klein und zweitens registriert es ja auch Events. Das ganze onload, domready etc ... all das kostet Zeit.

Ich hoffe das hilft ein wenig zum Verständnis ;-)

An die Query Selektoren hatte ich gar nicht gedacht...
Davon ab denke ich nicht dass Performance irgendeine Rolle spielt in diesem Fall.
Unbestritten bin ich langsamer, wenn ich jquery als libary nutze. In diesem Fall dürfte das aber keine Rolle spielen.

Ich nutze Libaries grundsätzlich um mir die Programmierung zu erleichtern. Ich könnte mir ja schließlich auch die Funkionalität nachbauen. Nativ bin ich immer schneller.

Außerdem wird hier ebenfalls bootstrap genutzt womit 10 tausende Zeilen CSS geladen werden müssen. Nicht gerade performance optimiert.

Performance spielt immer eine Rolle. Vor allem wenn man ohne eine Bibliothek das gleiche hinbekommt ohne zusätzliche Zeilen Code zu schreiben.

Mit dem Bootstrap hast du natürlich recht. Das Teil ist überladen, aber das hat wenigstens noch heute einen Sinn. Bei jQuery ist das so eine Sache. Events und CSS Selektoren kannst du native mit gleichen Codezeile machen ... und falls nicht sind Polyfills für deinen gewünschten Fall wahrscheinlich besser.

Die Sache ist halt die, wenn man nicht darauf hinweist dann bleibt dieses jQuery bestehen obwohl es mittlerweile nicht mehr nötig ist. Zusätzlich halten die sich nicht wirklich an irgendwelche Standards oder mixen die wild durcheinander.

Manche Techniken sollte man halt auch sein lassen wenn die Zeit dazu gekommen ist :-)

Ohja! Vielen Dank 😊

Danke für deine Kritik.

Da das Tutorial einen gesamten Überblick über die Anwendung geben sollte, habe ich mich dazu entschieden den Code direkt mit in die HTML Datei zu platzieren. Wenn es (so wie bei dieser Anwendung) zu viel Code werden sollte, lager ich diesen dann natürlich auch in eine separate Datei aus 👍🏻

Persönlich finde ich jQuery auf wesentlich angenehmer zu Programmieren, jedoch ist der Einstieg mit JavaScript meines Erachtens nach deutlich einfacher.

This post has received a 0.42 % upvote from @drotto thanks to: @peppermint24.

Ich sehe schon...
Du bist genau mein Mann!

This post has received a 5.83 % upvote from @kittybot thanks to: @chriddi.

Hi cuby, Thanks for Using our Service!


Your Post has been upvoted and resteem to our blog who have 6371 Followers!.

to use our service send 0.1 SBD or STEEM and the URL of post provided in the memo to use our bot.

Someone Call Us scammer Here our Proof

@bot4resteem

This post was resteemed by @steemvote and received a 24.77% Upvote

Coin Marketplace

STEEM 0.28
TRX 0.13
JST 0.032
BTC 60625.76
ETH 2898.84
USDT 1.00
SBD 3.62