DEV Community

Cover image for Best Practices for Building Fintech Apps in Go 🚀💰
Bruno Ciccarino λ for learn go

Posted on

11 1 1 2 1

Best Practices for Building Fintech Apps in Go 🚀💰

Hey there, Gophers! 🐹 If you're diving into the world of fintech, you're probably looking to build robust, secure, and efficient applications. In this article, we’ll explore some best practices for fintech development in Go, touching on everything from handling money 🏦 to securing your API endpoints 🔒. We'll include practical examples along the way. Let's get to it! 💪

1 Handling Money Properly 💵

One of the biggest mistakes you can make in fintech is handling money values incorrectly. A common pitfall is using float64 for monetary calculations. Why? Because floating-point numbers can introduce rounding errors, which can be disastrous in the world of finance 💣.

The Problem with Floats

package main

import "fmt"

func main() {
    var balance float64 = 10.0
    balance -= 9.99
    fmt.Println(balance) // Output: 0.009999999999999787
}
Enter fullscreen mode Exit fullscreen mode

Did you see that? 🤯 What should have been 0.01 turned into a weird floating-point mess. Imagine this happening with your customers' bank balances! 💸

The Solution: Use a Decimal Library 📐
To avoid these issues, use a library like github.com/shopspring/decimal, which handles arbitrary precision.

package main

import (
    "fmt"
    "github.com/shopspring/decimal"
)

func main() {
    balance := decimal.NewFromFloat(10.0)
    balance = balance.Sub(decimal.NewFromFloat(9.99))
    fmt.Println(balance) // Output: 0.01
}
Enter fullscreen mode Exit fullscreen mode

No more floating-point shenanigans! 🎉 Decimal ensures precise calculations, which is a must in the fintech world.

2 Use Strings for JSON APIs 🌐

When transmitting monetary values via HTTP, avoid sending numbers directly. Why? JSON doesn’t have a decimal type, so your carefully crafted decimal values could get mangled when converted to float64.

Bad Approach: Sending Decimals as Floats 😬

{
    "amount": 9.99
}
Enter fullscreen mode Exit fullscreen mode

This might look fine, but depending on the client's implementation, it could lead to rounding issues again. Instead, send monetary values as strings. ✅

Good Approach: Sending Decimals as Strings 📧

{
    "amount": "9.99"
}
Enter fullscreen mode Exit fullscreen mode

And here’s how you can handle it in Go:

type Transaction struct {
    Amount string `json:"amount"`
}

func main() {
    tx := Transaction{Amount: decimal.NewFromFloat(9.99).String()}
    jsonStr, _ := json.Marshal(tx)
    fmt.Println(string(jsonStr)) // Output: {"amount":"9.99"}
}
Enter fullscreen mode Exit fullscreen mode

By using strings, you ensure that the value remains accurate when parsed by different clients.

3 Use Time Properly 🕰️

Financial systems often involve scheduling, timestamps, and time zones. If you mess up time handling, you can end up with delayed transactions or incorrect reports 📉. The time package in Go is powerful but requires careful usage.

Always Use time.Time for Timestamps 🗓️

type Payment struct {
    Amount   decimal.Decimal `json:"amount"`
    DateTime time.Time       `json:"datetime"`
}
Enter fullscreen mode Exit fullscreen mode

When dealing with timestamps, always store them in UTC to avoid time zone headaches 🌍.

now := time.Now().UTC()
fmt.Println(now.Format(time.RFC3339)) // Output: 2024-11-13T15:04:05Z
Enter fullscreen mode Exit fullscreen mode

Use Parse and Format Correctly ⏳
Make sure you're using the correct layout for formatting/parsing time strings. Go uses a reference date 2006-01-02 15:04:05 as the layout.

layout := "2006-01-02 15:04:05"
t, err := time.Parse(layout, "2024-11-13 14:00:00")
if err != nil {
    fmt.Println("Error parsing time:", err)
}
fmt.Println(t)
Enter fullscreen mode Exit fullscreen mode

4 Protect Your API Endpoints 🔐

In fintech, security is non-negotiable 🚨. You’re dealing with sensitive financial data, so you need to protect your API endpoints against potential threats.

Use HTTPS Everywhere 🌍🔒
Make sure all your endpoints are served over HTTPS to encrypt data in transit. Let's Encrypt provides free SSL certificates if you're on a budget 💸.

Use Authentication & Authorization 🛡️

  • JWT Tokens: Great for stateless authentication.
  • API Keys: Simple but can be less secure if not handled properly.
  • OAuth2: The gold standard for user authentication.

Example: Securing Endpoints with JWT

package main

import (
    "github.com/golang-jwt/jwt/v5"
    "time"
)

func generateJWT() (string, error) {
    claims := jwt.MapClaims{
        "user": "gopher",
        "exp":  time.Now().Add(time.Hour * 24).Unix(),
    }
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString([]byte("supersecretkey"))
}

func main() {
    token, err := generateJWT()
    if err != nil {
        panic(err)
    }
    fmt.Println("JWT:", token)
}
Enter fullscreen mode Exit fullscreen mode

Don't forget to validate tokens on every request! ✅

5 Be Mindful of Concurrency 🧵

Go's goroutines are great for handling concurrency, but when it comes to fintech, be cautious! 🛑

Use Mutexes for Shared Data 🔄

var balance decimal.Decimal
var mu sync.Mutex

func updateBalance(amount decimal.Decimal) {
    mu.Lock()
    balance = balance.Add(amount)
    mu.Unlock()
}
Enter fullscreen mode Exit fullscreen mode

Use Channels for Safe Communication 📡

func main() {
    transactions := make(chan decimal.Decimal)

    go func() {
        transactions <- decimal.NewFromFloat(100.50)
    }()

    tx := <-transactions
    fmt.Println("Transaction received:", tx)
}
Enter fullscreen mode Exit fullscreen mode

6 Test Everything, Especially Edge Cases 🧪

Testing is crucial in fintech, where bugs can have costly consequences 💰. Make sure to cover edge cases like:

  • Large values 💸
  • Rounding issues 🧮
  • Time zone handling 🌐
  • High concurrency scenarios 🕹️

Example: Table-Driven Tests

func TestAddMoney(t *testing.T) {
    tests := []struct {
        amount1, amount2, expected string
    }{
        {"9.99", "0.01", "10.00"},
        {"100.50", "0.50", "101.00"},
    }

    for _, test := range tests {
        a1, _ := decimal.NewFromString(test.amount1)
        a2, _ := decimal.NewFromString(test.amount2)
        expected, _ := decimal.NewFromString(test.expected)

        result := a1.Add(a2)
        if !result.Equal(expected) {
            t.Errorf("expected %s but got %s", expected, result)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Wrapping Up 🎁
Building fintech applications in Go can be a lot of fun, but it also comes with its own set of challenges. From handling money properly with decimals to securing your API endpoints, every detail matters.

Hopefully, these tips will help you build fintech apps that are precise, secure, and performant. Now go forth and create something awesome! 🚀🐹

Happy coding! 💻🎉

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (7)

Collapse
 
hafidhfikri profile image
Hafidh Fikri

good content, thank you for sharing this!

Collapse
 
brunociccarino profile image
Bruno Ciccarino λ

Thank you for the feedback bro

Collapse
 
mbugua profile image
Lee Mbugua

superb content, very timely for some cool project I am working that involves Money!

Collapse
 
brunociccarino profile image
Bruno Ciccarino λ

Thanks for the feedback and good luck with the project bro

Collapse
 
rlgino profile image
Gino Luraschi

I liked your post, it's absolutely complete and contains real-world cases that are better for understanding 👏👏👏

Collapse
 
brunociccarino profile image
Bruno Ciccarino λ

Thanks for the feedback bro 🤜🤛

Collapse
 
briskt profile image
Steve

Good, comprehensive list of potential gotchas. Thanks!

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay