A Go developer working on a service that requires a third-party API integration and that integration has a webhook or something similar that returns a changing response body structure depending on the event sent to and through the hook.
A lot of people do not essentially know how to handle this scenario in Go at least using the gracious and glorious JSON package to handle something simple yet overly complicated task in Go.
Today, we will have a walkthrough on handling dynamic API responses in Go using the JSON package.
Prerequisite
It is crucial to understand that dynamic API responses take different forms, some are events triggered in response to an activity in the service. Whether it is a FinTech API using a webhook to notify the system of an event or a user triggering a notification to an admin dashboard on a specific event.
These dynamic APIs hold a means of identification that can be used to identify them and separate them into their different predefined structure in most cases.
let's get into the fun part of this article [the coding part]
To get started with this tutorial, you will need:
- Go installed and set up
- An IDE or test editor
- Practical Knowledge of Go
- Postman
Initial stage [ Setup your project repo ]
Open the terminal and set up our project repo using the command below. (This of course works on Linux and macOS)
mkdir Documents/dynamic-API && touch Documents/dynamic-API/
main.go && code Documents/dynamic-API
go mod init [your-github-name]/handling-dynamic-api
Create our main function and setup for development.
package main
import "log/slog"
func main() {
// setup a logger using slog
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info("Hello Terminal 👋", "user", os.Getenv("USER"))
}
Build the function that handles the API response for the service.
func HandleDynamicAPI(l *slog.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l.Info("This API is connected", "user", os.Getenv("USER"))
}
}
This function will hold the entire logic that handles the response from the webhook.
Since we are handling this without a third-party library or framework, we will be using the built-in Go http library to handle this bit which will require importing net/http while also defining a logger of type *slog.Logger as an argument to the HandleDynamicAPI function
random fun fact: if you are not a VIM / Nano user, you might not need to worry about importation cause your text editor probably have it handled
Hence; your current code should look something like this
package main
import (
"log/slog"
"net/http"
)
func main() {
// setup a logger using slog
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info("Hello Terminal 👋", "user", os.Getenv("USER"))
}
func HandleDynamicAPI(l *slog.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l.Info("This API is connected", "user", os.Getenv("USER"))
}
}
Catch And Identify The Response Event Or Identifier (in case of an API with events or identifiers)
- Event Identifier Structure
//this will be used to identify the event type
//
//We care about just the event head
type eventIdentfier struct {
Event string `json:"event"`
}
- Logic To Catch And Identify Event
func HandleDynamicAPI(l *slog.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
l.Info("This API is connected", "user", os.Getenv("USER"))
var (
eventIdentfier eventIdentfier
jsonData json.RawMessage
)
if err := json.NewDecoder(r.Body).Decode(&jsonData); err != nil {
l.Error("error decoding json response", "error context", err)
return
}
if err := json.Unmarshal(jsonData, &eventIdentfier); err != nil {
l.Error("error unmarshalling json data message", "error context", err)
return
}
}
}
What the written code above does is it catches the API response body data and decodes it into the jsonData variable which is a type of json.RawMessage and that jsonData value is unmarshalled into the eventIdentifier variable to be used in the later stage of development.
How the json.RawMessage works are it delays json decoding of the body making it flexible to use for re-unmarshalling as I will call it and in our case used for event identification and eventually decoding into a defined json structure.
Using Event To Identify Execution Case
In this part, we will be going deeper into Go using control flow to execute logic and many cases functions after identification of the event that should be executed.
firstly, we want to know what the event value will be, which will be used to handle the control flow of the program.
These are usually found in the API / webhook documentation and our case we are using paystack.
For information about Paystack's webhooks, check out their API documentation and visit
paymentrequest.pending event response
SOCIAL SHARE CARD GENERATOR