Schreiben der Bank-API
Nachdem wir die Kernlogik der Onlinebank erstellt haben, lassen Sie uns eine Web-API erstellen, um sie über einen Browser (oder sogar über die Befehlszeile) zu testen. Im Moment werden wir keine Datenbank verwenden, um die Daten beizubehalten. Daher müssen wir eine globale Variable erstellen, um alle Konten im Arbeitsspeicher zu speichern.
Außerdem überspringen wir den Testteil, um diesen Leitfaden nicht zu lang werden zu lassen. Idealerweise folgen Sie demselben Ansatz, den wir beim Erstellen des Kernpakets verfolgt haben, um Tests vor dem Code zu schreiben.
Einrichten eines Kontos im Arbeitsspeicher
Anstatt eine Datenbank zu verwenden, um die Daten beizubehalten, werden wir eine Arbeitsspeicherzuordnung für die Konten verwenden, die wir beim Programmstart erstellen. Zusätzlich verwenden wir eine Zuordnung, um mithilfe der Kontonummer auf die Kontoinformationen zuzugreifen.
Wechseln Sie zur Datei $GOPATH/src/bankapi/main.go
, und fügen Sie den folgenden Code hinzu, um die globale accounts
-Variable zu erstellen und sie mit einem Konto zu initialisieren. (Dieser Code ähnelt dem, den wir zuvor beim Erstellen der Tests verwendet haben.)
package main
import (
"github.com/msft/bank"
)
var accounts = map[float64]*bank.Account{}
func main() {
accounts[1001] = &bank.Account{
Customer: bank.Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
}
}
Stellen Sie sicher, dass Sie sich am $GOPATH/src/bankapi/
-Standort befinden. Führen Sie das Programm mit go run main.go
aus, um sicherzustellen, dass keine Fehler vorliegen. Das Programm macht im Moment nichts anderes, sodass wir die Logik zum Erstellen einer Web-API hinzufügen.
Verfügbar machen der Auszugsmethode
Das Erstellen einer Web-API in Go ist einfach, wie Sie in einem früheren Modul gesehen haben. Wir verwenden weiterhin das net/http
-Paket. Außerdem verwenden wir die Funktionen HandleFunc
und ListenAndServe
, um Endpunkte verfügbar zu machen und den Server zu starten. Die HandleFunc
-Funktion erfordert einen Namen für den URL-Pfad, den Sie verfügbar machen möchten, und den Namen einer Funktion mit der Logik für diesen Endpunkt.
Beginnen wir damit, die Funktionalität zum Drucken des Auszugs für ein Konto verfügbar zu machen. Kopieren Sie die folgende Funktion und fügen Sie sie in main.go
ein:
func statement(w http.ResponseWriter, req *http.Request) {
numberqs := req.URL.Query().Get("number")
if numberqs == "" {
fmt.Fprintf(w, "Account number is missing!")
return
}
if number, err := strconv.ParseFloat(numberqs, 64); err != nil {
fmt.Fprintf(w, "Invalid account number!")
} else {
account, ok := accounts[number]
if !ok {
fmt.Fprintf(w, "Account with number %v can't be found!", number)
} else {
fmt.Fprintf(w, account.Statement())
}
}
}
Das erste Highlight der statement
-Funktion ist, dass sie das Objekt empfängt, um eine Antwort für den Browser zu schreiben (w http.ResponseWriter
). Sie empfängt auch das Anforderungsobjekt, um auf die Informationen der HTTP-Anforderung zuzugreifen (req *http.Request
).
Beachten Sie dann, dass wir die req.URL.Query().Get()
-Funktion verwenden, um einen Parameter aus der Abfragezeichenfolge zu lesen. Bei diesem Parameter handelt es sich um die Kontonummer, die über den HTTP-Aufruf gesendet wird. Wir verwenden diesen Wert, um auf die Kontozuordnung zuzugreifen und ihre Informationen abzurufen.
Da wir Daten vom Benutzer erhalten, sollten wir einige Validierungen einbeziehen, um einen Absturz zu vermeiden. Wenn wir wissen, dass wir über eine gültige Kontonummer verfügen, können wir die Statement()
-Methode aufrufen und die Zeichenfolge ausgeben, die an den Browser zurückgegeben wird (fmt.Fprintf(w, account.Statement())
).
Ändern Sie jetzt Ihre main()
-Funktion, sodass sie wie folgt aussieht:
func main() {
accounts[1001] = &bank.Account{
Customer: bank.Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
}
http.HandleFunc("/statement", statement)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
Wenn Sie beim Ausführen des Programms (go run main.go
) keine Fehler oder Ausgaben sehen, funktioniert es ordnungsgemäß. Öffnen Sie einen Webbrowser, und geben Sie die URL http://localhost:8000/statement?number=1001
ein, oder führen Sie den folgenden Befehl in einer anderen Shell aus, während Ihr Programm ausgeführt wird:
curl http://localhost:8000/statement?number=1001
Die folgende Ausgabe wird angezeigt.
1001 - John - 0
Verfügbar machen der Einzahlungsmethode
Lassen Sie uns denselben Ansatz verwenden, um die Einzahlungsmethode verfügbar zu machen. In diesem Fall möchten wir Geld zu dem Konto hinzufügen, das im Arbeitsspeicher vorliegt. Jedes Mal, wenn wir die Deposit()
-Methode aufrufen, sollte sich der Saldo erhöhen.
Fügen Sie im Hauptprogramm eine deposit()
-Funktion wie die folgende hinzu. Die Funktion ruft die Kontonummer aus der Abfragezeichenfolge ab und prüft, ob das Konto in der accounts
-Zuordnung vorhanden. Dann prüft sie ob der einzuzahlende Betrag eine gültige Zahl ist und ruft dann die Deposit()
-Methode auf.
func deposit(w http.ResponseWriter, req *http.Request) {
numberqs := req.URL.Query().Get("number")
amountqs := req.URL.Query().Get("amount")
if numberqs == "" {
fmt.Fprintf(w, "Account number is missing!")
return
}
if number, err := strconv.ParseFloat(numberqs, 64); err != nil {
fmt.Fprintf(w, "Invalid account number!")
} else if amount, err := strconv.ParseFloat(amountqs, 64); err != nil {
fmt.Fprintf(w, "Invalid amount number!")
} else {
account, ok := accounts[number]
if !ok {
fmt.Fprintf(w, "Account with number %v can't be found!", number)
} else {
err := account.Deposit(amount)
if err != nil {
fmt.Fprintf(w, "%v", err)
} else {
fmt.Fprintf(w, account.Statement())
}
}
}
}
Beachten Sie, dass diese Funktion einen ähnlichen Ansatz verfolgt, um die Daten abzurufen und zu prüfen, die sie vom Benutzer erhält. Wir deklarieren und verwenden Variablen auch direkt in der if
-Anweisung. Nachdem wir schließlich etwas Geld auf das Konto eingezahlt haben, drucken wir den Kontoauszug aus, um den neuen Kontostand zu sehen.
Nun sollten Sie einen /deposit
-Endpunkt verfügbar machen, der die deposit
-Funktion aufruft. Ändern Sie die main()
-Funktion so, dass sie wie folgt aussieht:
func main() {
accounts[1001] = &bank.Account{
Customer: bank.Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
}
http.HandleFunc("/statement", statement)
http.HandleFunc("/deposit", deposit)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
Wenn Sie beim Ausführen des Programms (go run main.go
) keine Fehler oder Ausgaben sehen, funktioniert es ordnungsgemäß. Öffnen Sie einen Webbrowser, und geben Sie die URL http://localhost:8000/deposit?number=1001&amount=100
ein, oder führen Sie den folgenden Befehl in einer anderen Shell aus, während Ihr Programm ausgeführt wird:
curl "http://localhost:8000/deposit?number=1001&amount=100"
Die folgende Ausgabe wird angezeigt.
1001 - John - 100
Wenn Sie denselben Aufruf mehrmals tätigen, wird der Kontostand weiter erhöht. Probieren Sie es aus, um zu bestätigen, dass die accounts
-Zuordnung im Arbeitsspeicher zur Laufzeit aktualisiert wird. Wenn Sie das Programm beenden, gehen alle getätigten Einzahlungen verloren, aber das ist in dieser ersten Version zu erwarten.
Verfügbar machen der Auszahlungsmethode
Abschließend möchten wir die Methode zum Abheben von Geld von einem Konto verfügbar machen. Wir erstellen zunächst die withdraw
-Funktion im Hauptprogramm. Die Funktion prüft die Kontonummerninformationen, die Auszahlung und gibt alle Fehler aus, die Sie vom Kernpaket erhalten. Fügen Sie die folgende Funktion zu Ihrem Hauptprogramm hinzu:
func withdraw(w http.ResponseWriter, req *http.Request) {
numberqs := req.URL.Query().Get("number")
amountqs := req.URL.Query().Get("amount")
if numberqs == "" {
fmt.Fprintf(w, "Account number is missing!")
return
}
if number, err := strconv.ParseFloat(numberqs, 64); err != nil {
fmt.Fprintf(w, "Invalid account number!")
} else if amount, err := strconv.ParseFloat(amountqs, 64); err != nil {
fmt.Fprintf(w, "Invalid amount number!")
} else {
account, ok := accounts[number]
if !ok {
fmt.Fprintf(w, "Account with number %v can't be found!", number)
} else {
err := account.Withdraw(amount)
if err != nil {
fmt.Fprintf(w, "%v", err)
} else {
fmt.Fprintf(w, account.Statement())
}
}
}
}
Fügen Sie jetzt den /withdraw
-Endpunkt in der main()
-Funktion hinzu, um die Logik in der withdraw()
-Funktion verfügbar zu machen. Ändern Sie die main()
-Funktion so, dass sie wie folgt aussieht:
func main() {
accounts[1001] = &bank.Account{
Customer: bank.Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
}
http.HandleFunc("/statement", statement)
http.HandleFunc("/deposit", deposit)
http.HandleFunc("/withdraw", withdraw)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
Wenn Sie beim Ausführen des Programms (go run main.go
) keine Fehler oder Ausgaben sehen, funktioniert es ordnungsgemäß. Öffnen Sie einen Webbrowser, und geben Sie die URL http://localhost:8000/withdraw?number=1001&amount=100
ein, oder führen Sie den folgenden Befehl in einer anderen Shell aus, während Ihr Programm ausgeführt wird:
curl "http://localhost:8000/withdraw?number=1001&amount=100"
Die folgende Ausgabe wird angezeigt.
the amount to withdraw should be greater than the account's balance
Beachten Sie, dass der Fehler, den wir erhalten, vom Kernpaket stammt. Wenn das Programm startet, ist der Kontostand Null. Daher können Sie keinen Geldbetrag abheben. Rufen Sie den /deposit
-Endpunkt ein paar Mal auf, um Geld hinzuzufügen, und rufen Sie den /withdraw
-Endpunkt erneut auf, um zu bestätigen, dass das funktioniert:
curl "http://localhost:8000/deposit?number=1001&amount=100"
curl "http://localhost:8000/deposit?number=1001&amount=100"
curl "http://localhost:8000/deposit?number=1001&amount=100"
curl "http://localhost:8000/withdraw?number=1001&amount=100"
Die folgende Ausgabe wird angezeigt.
1001 - John - 200
Das ist alles! Sie haben eine Web-API erstellt, um die Funktionalität eines Pakets, das Sie von Grund auf erstellt haben, verfügbar zu machen. Wechseln Sie zum nächsten Abschnitt, um weiter zu üben. Diesmal werden Sie vor eine Aufgabe gestellt, für die Sie eine eigene Lösung schreiben sollen.