Go Gorilla Mux

To integrate APIToolkit with golang web services, we employ an SDK named the golang client for APIToolkit. This SDK oversees the incoming traffic, bundles the requests, and then forwards them to the APItoolkit servers. In this guide, we’ll delve into a detailed procedure to integrate the APIToolkit within our Go Gorilla mux web service.

Design Considerations

  • Internally, the SDK leverages google cloud pubsub via grpc, ensuring that your data is efficiently relayed to APIToolkit for processing.
  • Managing live traffic in this fashion enables:
    1. APIToolkit to conduct real-time analysis, anomaly detection, and monitoring of your APIs.
    2. Users to actively inspect their API through the api log explorer.

Create an Account or Sign In to APIToolkit to Generate Key

  1. Sign up / Sign in to the API dashboard
    sign up/sign in
  2. Create a project
  3. Generate an API key for your project, and include a brief description of your work. And to prevent losing your key after it has been generated, remember to make a copy of it.
    api key generation

Integrate with Gorilla Mux in Go

Assuming you’ve already set up Go and wish to integrate with Gorilla Mux:

a. Install necessary packages:

go get -u github.com/gorilla/mux

b. Create a new Go file, for instance, main.go

c. Set up your Gorilla Mux router:

package main

import (
	"github.com/gorilla/mux"
	"net/http"
)

func main() {
	r := mux.NewRouter()

	// Define your routes here...

	http.Handle("/", r)
	http.ListenAndServe(":8080", r)
}

d. Integrate with APITOOLKIT:
Let’s go ahead and write the code to initialize apitoolkit with gorilla/mux:

package main

import (
	"context"
	"net/http"
	"github.com/gorilla/mux"
	apitoolkit "github.com/apitoolkit/apitoolkit-go"
)

func main() {
	ctx := context.Background()

	// Initialize the client using your generated apikey
	apitoolkitClient, err := apitoolkit.NewClient(ctx, apitoolkit.Config{APIKey: "<APIKEY>"})
	if err != nil {
		panic(err)
	}

	r := mux.NewRouter()
	// Register middleware
	r.Use(apitoolkitClient.GorillaMuxMiddleware)
	r.HandleFunc("/{slug}/test",func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("ok"))
	})

	http.ListenAndServe(":8080", r)
}

Replace "YOUR_GENERATED_API_KEY" with your actual API key.

Test the Integration
This code sets up a basic HTTP server using gorilla/mux and integrates the apitoolkit middleware. When you run this code and make a request to http://localhost:8080/{some_slug}/test, it should go through the apitoolkit middleware before responding with “ok”.

Redacting Sensitive Fields with Gorilla Mux and APIToolkit

It’s possible to mark fields as redacted directly on the API Toolkit dashboard. However, you also have the option to handle redaction on the client side. By opting for client-side redaction, you’re ensuring these sensitive fields won’t leave your server, enhancing data privacy.

Suppose you’re dealing with a request body like:

{
  "user": {
    "id": 123456789,
    "name": "Precious John",
    "password": "secretpassword123",
    "creditCard": {
      "number": "1234567890123456",
      "expiry": "12/25"
    }
  }
}

To redact the password and credit card number fields, you would configure the apitoolkit config struct in this manner:

package main

import (
	"net/http"
	"github.com/gorilla/mux"
	apitoolkit "github.com/apitoolkit/apitoolkit-go"
)

func main() {
	r := mux.NewRouter()

	apitoolkitCfg := apitoolkit.Config{
        RedactHeaders: []string{"Content-Type", "Authorization", "Cookies"}, // Redacting both request and response headers
        RedactRequestBody: []string{"$.user.password", "$.user.creditCard.number"},
        RedactResponseBody: []string{"$.message.error"},
        APIKey: "<APIKEY>",
    }

	// Initialize the APIToolkit client using your generated API key
	apitoolkitClient, _ := apitoolkit.NewClient(apitoolkitCfg)

	r.Use(apitoolkitClient.GorillaMuxMiddleware)

	r.HandleFunc("/:slug/test", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok"))
	}).Methods("POST")

	http.Handle("/", r)
	http.ListenAndServe(":8080", r)
}

It’s pivotal to note that while the RedactHeaders config field will take the header names (which are case insensitive), RedactRequestBody and RedactResponseBody work with JSONPath strings.

Using JSONPath allows for flexibility when determining which fields in your responses are sensitive. This configuration is global and impacts all endpoint requests and responses. To get a better grasp of JSONPath and how to draft these queries, look into: JSONPath Cheatsheet

Outgoing Requests

To monitor outgoing HTTP requests from your Go application, you can replace the default HTTP client transport with a custom roundtripper. This allows you to capture and send copies of all incoming and outgoing requests to an apitoolkit server for monitoring and analysis.

Example

package main

import (
	"net/http"
	"github.com/gorilla/mux"
  	 apitoolkit "github.com/apitoolkit/apitoolkit-go"
)

func main() {

 	apitoolkitClient, err := apitoolkit.NewClient(context.Background(), apitoolkit.Config{APIKey: "<API KEY>"})
	if err != nil {
		panic(err)
	}

	handlerFn := func(w http.ResponseWriter, r *http.Request) {
		HTTPClient := http.DefaultClient
		HTTPClient.Transport = client.WrapRoundTripper(
			r.Context(), HTTPClient.Transport,
			WithRedactHeaders([]string{}),
		)
		_, _ = HTTPClient.Get("http://localhost:3000/test-outgoing")

		w.WriteHeader(http.StatusAccepted)
		w.Write([]byte("Hello world"))
	}
	r := mux.NewRouter()
	r.Use(client.GorillaMuxMiddleware)
	r.HandleFunc("/:slug/test", handlerFn).Methods(http.MethodPost)
}

The provided code demonstrates how to set up the custom roundtripper to replace the default HTTP client’s transport. The resulting HTTP client, HTTPClient, is configured to send copies of all incoming and outgoing requests to the apitoolkit servers. You can use this modified HTTP client for any HTTP requests you need to make from your server, ensuring they are monitored by apitoolkit.

Report Errors

If you’ve used sentry, or bugsnag, or rollbar, then you’re already familiar with this usecase.
But you can report an error to apitoolkit. A difference, is that errors are always associated with a parent request, and helps you query and associate the errors which occured while serving a given customer request. To request errors to APIToolkit use call the ReportError method of apitoolkit not the client returned by apitoolkit.NewClient with the request context and the error to report
Example:

Gorilla mux

import (
   //... other imports
  	apitoolkit "github.com/apitoolkit/apitoolkit-go"
)

func main() {
	r := mux.NewRouter()
	ctx := context.Background()

	apitoolkitClient, err := apitoolkit.NewClient(ctx, apitoolkit.Config{APIKey: "<API_KEY>"})
	if err != nil {
		panic(err)
	}
	r.Use(apitoolkitClient.GorillaMuxMiddleware)
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, err := os.Open("non-existing-file.json")
		if err != nil {
			// Report the error to apitoolkit
			apitoolkit.ReportError(r.Context(), err)
		}
		fmt.Fprintln(w, "Hello, World!")
	})

	server := &http.Server{Addr: ":8080", Handler: r}
	err = server.ListenAndServe()
	if err != nil {
		fmt.Println(err)
	}
}

Next Steps

  1. Deploy your application or initiate test HTTP requests to your service.
  2. Visit the API log explorer or the Endpoints tab on the APIToolkit dashboard. Here, you can confirm if your test request was handled properly.
  3. Enjoy having our API comanage your backends and APIs with you.