Pisanie interfejsu API banku

Ukończone

Teraz, gdy utworzyliśmy podstawową logikę banku online, skompilujmy internetowy interfejs API, aby przetestować go z przeglądarki (a nawet wiersza polecenia). Na razie nie będziemy używać bazy danych do utrwalania danych, więc musimy utworzyć zmienną globalną do przechowywania wszystkich kont w pamięci.

Ponadto pominiemy część testowania, aby uniknąć zbyt długiego przechowywania tego przewodnika. W idealnym przypadku należy postępować zgodnie z tym samym podejściem, które wykonaliśmy podczas kompilowania pakietu podstawowego w celu pisania testów przed kodem.

Konfigurowanie konta w pamięci

Zamiast używać bazy danych do utrwalania danych, użyjemy mapy pamięci dla kont, które utworzymy podczas uruchamiania programu. Ponadto użyjemy mapy, aby uzyskać dostęp do informacji o koncie przy użyciu numeru konta.

Przejdź do $GOPATH/src/bankapi/main.go pliku i dodaj następujący kod, aby utworzyć zmienną globalną accounts i zainicjować ją przy użyciu konta. (Ten kod jest podobny do tego, co zrobiliśmy podczas tworzenia testów wcześniej).

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,
    }
}

Upewnij się, że jesteś w $GOPATH/src/bankapi/lokalizacji. Uruchom program za pomocą polecenia go run main.go , aby upewnić się, że nie masz żadnych błędów. Na razie program nie robi nic innego, więc dodajmy logikę w celu utworzenia internetowego interfejsu API.

Uwidaczniaj metodę instrukcji

Tworzenie internetowego interfejsu API w języku Go jest łatwe, jak pokazano w poprzednim module. Będziemy nadal korzystać z net/http pakietu. Użyjemy również HandleFunc funkcji i ListenAndServe , aby uwidocznić punkty końcowe i uruchomić serwer. Funkcja HandleFunc wymaga nazwy ścieżki adresu URL, którą chcesz uwidocznić, oraz nazwy funkcji z logiką dla tego punktu końcowego.

Zacznijmy od ujawnienia funkcji drukowania instrukcji dla konta. Skopiuj i wklej następującą funkcję w pliku main.go:

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())
        }
    }
}

Pierwszym wyróżnieniem statement funkcji jest to, że otrzymuje obiekt w celu zapisania odpowiedzi z powrotem do przeglądarki (w http.ResponseWriter). Otrzymuje on również obiekt żądania w celu uzyskania dostępu do informacji z żądania HTTP (req *http.Request).

Następnie zwróć uwagę, że używamy req.URL.Query().Get() funkcji do odczytywania parametru z ciągu zapytania. Ten parametr jest numerem konta, który wyślemy za pośrednictwem wywołania HTTP. Użyjemy tej wartości, aby uzyskać dostęp do mapy konta i uzyskać jej informacje.

Ponieważ otrzymujemy dane od użytkownika, należy uwzględnić pewne weryfikacje, aby uniknąć awarii. Gdy wiemy, że mamy prawidłowy numer konta, możemy wykonać wywołanie Statement() metody i wyświetlić ciąg, który powróci do przeglądarki (fmt.Fprintf(w, account.Statement())).

Teraz zmodyfikuj main() funkcję tak, aby wyglądała następująco:

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))
}

Jeśli nie widzisz żadnego błędu lub danych wyjściowych podczas uruchamiania programu (go run main.go), działa on poprawnie. Otwórz przeglądarkę internetową i wprowadź adres URL http://localhost:8000/statement?number=1001lub uruchom następujące polecenie w innej powłoce, gdy program jest uruchomiony:

curl http://localhost:8000/statement?number=1001

Powinny zostać wyświetlone następujące dane wyjściowe:

1001 - John - 0

Uwidaczniaj metodę depozytu

Kontynuujmy korzystanie z tego samego podejścia, aby uwidocznić metodę depozytu. W tym przypadku chcemy dodać pieniądze na konto, które mamy w pamięci. Za każdym razem, gdy wywołujemy metodę Deposit() , należy zwiększyć saldo.

W głównym programie dodaj funkcję podobną deposit() do poniższej. Funkcja pobiera numer konta z ciągu zapytania, sprawdza, czy konto istnieje na accounts mapie, sprawdza, czy kwota depozytu jest prawidłową liczbą, a następnie wywołuje metodę Deposit() .

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())
            }
        }
    }
}

Zwróć uwagę, że ta funkcja jest zgodna z podobnym podejściem, aby pobrać i zweryfikować dane odbierane od użytkownika. Deklarujemy również zmienne i używamy ich bezpośrednio w instrukcji if . Na koniec, po dodaniu niektórych środków na konto, drukujemy zestawienie, aby zobaczyć nowe saldo konta.

Teraz należy uwidocznić /deposit punkt końcowy wywołujący deposit funkcję. Zmodyfikuj funkcję main() tak, aby wyglądała następująco:

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))
}

Jeśli nie widzisz żadnego błędu lub danych wyjściowych podczas uruchamiania programu (go run main.go), działa on poprawnie. Otwórz przeglądarkę internetową i wprowadź adres URL http://localhost:8000/deposit?number=1001&amount=100lub uruchom następujące polecenie w innej powłoce, gdy program jest uruchomiony:

curl "http://localhost:8000/deposit?number=1001&amount=100"

Powinny zostać wyświetlone następujące dane wyjściowe:

1001 - John - 100

Jeśli wykonasz to samo wywołanie kilka razy, saldo konta będzie nadal wzrastać. Spróbuj potwierdzić, że accounts mapa w pamięci jest aktualizowana w czasie wykonywania. Jeśli zatrzymasz program, wszystkie depozyty, które zrobiłeś, zostaną utracone, ale jest to oczekiwane w tej początkowej wersji.

Uwidacznij metodę wycofywania

Na koniec uwidocznijmy metodę wypłaty pieniędzy z konta. Ponownie utwórzmy withdraw funkcję w głównym programie. Funkcja zweryfikuje informacje o numerze konta, wycofa i wyświetli wszelkie błędy otrzymane z pakietu podstawowego. Dodaj następującą funkcję do głównego programu:

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())
            }
        }
    }
}

Teraz dodaj /withdraw punkt końcowy w main() funkcji, aby uwidocznić logikę withdraw() , która jest dostępna w funkcji. Zmodyfikuj funkcję tak main() , aby wyglądała następująco:

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))
}

Jeśli nie widzisz żadnego błędu lub danych wyjściowych podczas uruchamiania programu (go run main.go), działa on poprawnie. Otwórz przeglądarkę internetową i wprowadź adres URL http://localhost:8000/withdraw?number=1001&amount=100lub uruchom następujące polecenie w innej powłoce, gdy program jest uruchomiony:

curl "http://localhost:8000/withdraw?number=1001&amount=100"

Powinny zostać wyświetlone następujące dane wyjściowe:

the amount to withdraw should be greater than the account's balance

Zwróć uwagę, że błąd, który otrzymujemy, pochodzi z podstawowego pakietu. Po uruchomieniu programu saldo konta wynosi zero. W związku z tym nie można wycofać żadnej kwoty pieniędzy. Wywołaj /deposit punkt końcowy kilka razy, aby dodać fundusze, a następnie ponownie wywołaj /withdraw punkt końcowy, aby potwierdzić, że działa:

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"

Powinny zostać wyświetlone następujące dane wyjściowe:

1001 - John - 200

I już! Utworzono internetowy interfejs API umożliwiający uwidacznianie funkcji z pakietu utworzonego od podstaw. Przejdź do następnej sekcji, aby kontynuować ćwiczenia. Tym razem zostanie wyświetlone wyzwanie, w którym napiszesz własne rozwiązanie.