Napsání rozhraní API banky

Dokončeno

Teď, když jsme vytvořili základní logiku online banky, vytvoříme webové rozhraní API, které ho otestuje z prohlížeče (nebo dokonce z příkazového řádku). Prozatím nebudeme k uchovávání dat používat databázi, takže budeme muset vytvořit globální proměnnou pro uložení všech účtů do paměti.

Kromě toho část testování přeskočíme, aby se zabránilo příliš dlouhému uchovávání tohoto průvodce. V ideálním případě byste postupovali stejně jako při vytváření základního balíčku pro psaní testů před kódem.

Nastavení účtu v paměti

Místo použití databáze k zachování dat použijeme mapu paměti pro účty, které vytvoříme při spuštění programu. Kromě toho použijeme mapu pro přístup k informacím o účtu pomocí čísla účtu.

Přejděte do $GOPATH/src/bankapi/main.go souboru a přidejte následující kód, který vytvoří globální accounts proměnnou a inicializuje ji pomocí účtu. (Tento kód je podobný tomu, co jsme udělali při vytváření testů dříve.)

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

Ujistěte se, že jste v $GOPATH/src/bankapi/umístění. Spusťte program, go run main.go abyste měli jistotu, že nemáte žádné chyby. Program zatím nedělá nic jiného, takže přidáme logiku pro vytvoření webového rozhraní API.

Zveřejnění metody příkazu

Vytvoření webového rozhraní API v Go je snadné, jak jste viděli v předchozím modulu. Budeme balíček dál používat net/http . K zveřejnění koncových bodů a spuštění serveru použijeme HandleFunc ListenAndServe také funkce a funkce. Funkce HandleFunc vyžaduje název cesty URL, kterou chcete zveřejnit, a název funkce s logikou pro daný koncový bod.

Začněme zveřejněním funkce pro tisk příkazu pro účet. Zkopírujte a vložte následující funkci do 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())
        }
    }
}

První zvýraznění funkce statement spočívá v tom, že přijímá objekt k zápisu odpovědi zpět do prohlížeče (w http.ResponseWriter). Přijímá také objekt požadavku pro přístup k informacím z požadavku HTTP (req *http.Request).

Pak si všimněte, že funkci používáme req.URL.Query().Get() ke čtení parametru z řetězce dotazu. Tento parametr je číslo účtu, které budeme posílat prostřednictvím volání HTTP. Tuto hodnotu použijeme pro přístup k mapě účtu a získání jejích informací.

Vzhledem k tomu, že získáváme data od uživatele, měli bychom zahrnout některá ověření, abychom se vyhnuli chybovému ukončení. Když víme, že máme platné číslo účtu, můžeme volání metody provést Statement() a vytisknout řetězec, který se vrátí do prohlížeče (fmt.Fprintf(w, account.Statement())).

Teď upravte funkci main() tak, aby vypadala takto:

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

Pokud se při spuštění programu nezobrazí žádná chyba nebo výstup,go run main.go funguje správně. Otevřete webový prohlížeč a zadejte adresu URL http://localhost:8000/statement?number=1001nebo spusťte následující příkaz v jiném prostředí, když je program spuštěný:

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

Měl by se zobrazit následující výstup:

1001 - John - 0

Zveřejnění metody vkladu

Pojďme dál používat stejný přístup k zveřejnění metody vkladu. V tomto případě chceme přidat peníze na účet, který máme v paměti. Pokaždé, když zavoláme metodu Deposit() , by se měl zůstatek zvýšit.

V hlavním programu přidejte deposit() funkci jako následující. Funkce získá číslo účtu z řetězce dotazu, ověří, že účet v mapě accounts existuje, ověří, že částka k vkladu je platné číslo a pak volá metodu 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())
            }
        }
    }
}

Všimněte si, že tato funkce se řídí podobným přístupem, jak získat a ověřit data, která přijímá od uživatele. Také deklarujeme a používáme proměnné přímo v if příkazu. Nakonec po přidání některých finančních prostředků na účet vytiskneme výpis, abychom viděli zůstatek nového účtu.

Teď byste měli zveřejnit /deposit koncový bod, který volá deposit funkci. Upravte funkci main() tak, aby vypadala takto:

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

Pokud se při spuštění programu nezobrazí žádná chyba nebo výstup,go run main.go funguje správně. Otevřete webový prohlížeč a zadejte adresu URL http://localhost:8000/deposit?number=1001&amount=100nebo spusťte následující příkaz v jiném prostředí, když je program spuštěný:

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

Měl by se zobrazit následující výstup:

1001 - John - 100

Pokud provedete stejný hovor několikrát, zůstatek na účtu se bude dál zvětšovat. Zkuste ověřit, že accounts je mapa v paměti aktualizována za běhu. Pokud program zastavíte, všechny vklady, které jste udělali, se ztratí, ale to se očekává v této počáteční verzi.

Zveřejnění metody odvolání

Nakonec zveřejníme metodu pro výběr peněz z účtu. Znovu vytvoříme withdraw funkci v hlavním programu. Funkce ověří informace o čísle účtu, stáhne a vytiskne všechny chyby, které obdržíte ze základního balíčku. Do hlavního programu přidejte následující funkci:

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

Teď do funkce přidejte /withdraw koncový bod main() , abyste zpřístupnili logiku withdraw() , kterou máte ve funkci. main() Upravte funkci tak, aby vypadala takto:

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

Pokud se při spuštění programu nezobrazí žádná chyba nebo výstup,go run main.go funguje správně. Otevřete webový prohlížeč a zadejte adresu URL http://localhost:8000/withdraw?number=1001&amount=100nebo spusťte následující příkaz v jiném prostředí, když je program spuštěný:

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

Měl by se zobrazit následující výstup:

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

Všimněte si, že chyba, kterou dostáváme, pochází z základního balíčku. Při spuštění programu je zůstatek na účtu nula. Proto nemůžete stáhnout žádnou částku peněz. /deposit Zavolejte koncový bod několikrát, abyste přidali finanční prostředky, a znovu zavolejte /withdraw koncový bod, abyste potvrdili, že funguje:

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"

Měl by se zobrazit následující výstup:

1001 - John - 200

A je to! Vytvořili jste webové rozhraní API, které zpřístupňuje funkce z balíčku, který jste vytvořili úplně od začátku. Přejděte k další části a pokračujte v cvičení. Tentokrát se seznámíte s výzvou, ve které napíšete vlastní řešení.