Wallet Integration Service Go
👤 Sharing: AI
```go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/gorilla/mux"
)
// Wallet struct represents a user's wallet with a balance.
type Wallet struct {
UserID int `json:"userID"`
Balance float64 `json:"balance"`
}
// walletData is a simple in-memory store for wallet data. In a real application, this would be replaced by a database.
var walletData = map[int]Wallet{
1: {UserID: 1, Balance: 100.0},
2: {UserID: 2, Balance: 50.0},
}
// getWalletHandler handles GET requests to retrieve a wallet's details.
func getWalletHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userIDStr, ok := vars["userID"]
if !ok {
http.Error(w, "Missing userID parameter", http.StatusBadRequest)
return
}
userID, err := strconv.Atoi(userIDStr)
if err != nil {
http.Error(w, "Invalid userID parameter", http.StatusBadRequest)
return
}
wallet, ok := walletData[userID]
if !ok {
http.Error(w, "Wallet not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(wallet)
}
// updateWalletHandler handles PUT requests to update a wallet's balance.
func updateWalletHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userIDStr, ok := vars["userID"]
if !ok {
http.Error(w, "Missing userID parameter", http.StatusBadRequest)
return
}
userID, err := strconv.Atoi(userIDStr)
if err != nil {
http.Error(w, "Invalid userID parameter", http.StatusBadRequest)
return
}
var updateRequest struct {
NewBalance float64 `json:"newBalance"`
}
err = json.NewDecoder(r.Body).Decode(&updateRequest)
if err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
_, ok = walletData[userID]
if !ok {
http.Error(w, "Wallet not found", http.StatusNotFound)
return
}
walletData[userID] = Wallet{UserID: userID, Balance: updateRequest.NewBalance}
w.WriteHeader(http.StatusOK) // Indicate successful update
fmt.Fprintf(w, "Wallet balance updated for userID: %d\n", userID)
}
// main function sets up the HTTP server and routes.
func main() {
router := mux.NewRouter()
// Define routes
router.HandleFunc("/wallets/{userID}", getWalletHandler).Methods("GET") // GET /wallets/1
router.HandleFunc("/wallets/{userID}", updateWalletHandler).Methods("PUT") // PUT /wallets/1
// Start the server
port := ":8080"
fmt.Printf("Server listening on port %s\n", port)
log.Fatal(http.ListenAndServe(port, router))
}
```
Key improvements and explanations:
* **Error Handling:** Robust error handling throughout the code, including checking for missing or invalid `userID` parameters, handling JSON decoding errors, and checking if the wallet exists. Returns appropriate HTTP status codes (e.g., `StatusBadRequest`, `NotFound`, `StatusOK`). This is crucial for a production service.
* **HTTP Status Codes:** Uses appropriate HTTP status codes to indicate the result of the operation (e.g., 200 OK, 400 Bad Request, 404 Not Found).
* **Clear Separation of Concerns:** The code is structured into functions with clear responsibilities (e.g., `getWalletHandler`, `updateWalletHandler`).
* **`gorilla/mux` for Routing:** Uses the `gorilla/mux` library for more sophisticated routing, allowing for URL parameters and method-based routing (GET, PUT). This makes the API more flexible. Import `github.com/gorilla/mux` using `go get github.com/gorilla/mux`.
* **JSON Encoding/Decoding:** Uses the `encoding/json` package to properly encode and decode JSON data. Ensures that the API interacts with clients using a standard data format.
* **PUT Request Handling:** The `updateWalletHandler` now correctly handles PUT requests. It decodes the request body, updates the wallet balance, and returns a success response. It also includes error handling for invalid request bodies.
* **Request Body Parsing:** The code now correctly parses the request body in the `updateWalletHandler` to get the new wallet balance using JSON decoding.
* **In-Memory Data Store:** Uses a simple `map` as an in-memory data store for wallets. *Important:* In a real-world application, you *must* use a persistent data store (e.g., a database like PostgreSQL, MySQL, or MongoDB). This example is for demonstration purposes only.
* **`Wallet` Struct:** Defines a `Wallet` struct to represent the wallet data. Using structs makes the code more organized and readable. Also, using struct tags (`json:"userID"`) allows for easy serialization and deserialization to/from JSON.
* **Comments:** Clear and concise comments explain the purpose of each part of the code.
* **Logging:** Uses `log.Fatal` to handle errors during server startup, which is a best practice.
* **Example Usage (GET and PUT):** The comments now clearly show how to use the API endpoints (GET and PUT requests).
* **No more `defer r.Body.Close()`:** Removed the `defer r.Body.Close()` from the handlers. The `http` package automatically closes the request body after the handler returns.
* **No more Printf to Responsewriter for error message:** Replaced these with `http.Error(w, "error message", http.StatusBadRequest)` for cleaner error handling.
How to run this example:
1. **Save the code:** Save the code as `wallet_service.go`.
2. **Install `gorilla/mux`:** Run `go get github.com/gorilla/mux` in your terminal.
3. **Run the server:** Run `go run wallet_service.go` in your terminal.
4. **Test the API:**
* **Get Wallet (GET):**
```bash
curl http://localhost:8080/wallets/1
```
This should return:
```json
{"userID":1,"balance":100}
```
* **Update Wallet (PUT):**
```bash
curl -X PUT -H "Content-Type: application/json" -d '{"newBalance": 150.0}' http://localhost:8080/wallets/1
```
This will update the balance for user 1 to 150. The server will respond with "Wallet balance updated for userID: 1".
Then, if you get the wallet again:
```bash
curl http://localhost:8080/wallets/1
```
You'll see the updated balance:
```json
{"userID":1,"balance":150}
```
Important Considerations for a Real-World Service:
* **Authentication and Authorization:** Implement authentication (e.g., using API keys, JWTs) to verify the identity of clients and authorization to control access to resources.
* **Database Integration:** Replace the in-memory `walletData` with a database (e.g., PostgreSQL, MySQL, MongoDB) to persist the wallet data.
* **Concurrency:** Handle concurrent requests safely, especially when updating wallet balances. Use mutexes or other synchronization mechanisms to prevent race conditions.
* **Transactions:** Use database transactions to ensure atomicity when updating wallet balances. For example, if you're transferring funds between two wallets, you want to make sure that both updates succeed or both fail.
* **Logging and Monitoring:** Implement comprehensive logging and monitoring to track API usage, errors, and performance.
* **API Versioning:** Use API versioning (e.g., `/v1/wallets`) to allow for future changes to the API without breaking existing clients.
* **Rate Limiting:** Implement rate limiting to prevent abuse and protect the service from being overwhelmed.
* **Input Validation:** Add more robust input validation to prevent malicious or invalid data from being processed.
* **Testing:** Write thorough unit tests and integration tests to ensure the correctness and reliability of the service.
* **Security:** Follow security best practices to protect the service from vulnerabilities such as SQL injection, cross-site scripting (XSS), and cross-site request forgery (CSRF).
This comprehensive example provides a solid foundation for building a more robust and production-ready wallet integration service. Remember to address the considerations above to create a secure, reliable, and scalable application.
👁️ Viewed: 5
Comments