Building a Simple Token Quote API with Go, Gin, and 1inch
Rodrigo Burgos
Posted on October 17, 2024
Prerequisites
Before diving in, ensure you have the following installed on your machine:
Go (version 1.16 or later)
Git
A code editor (e.g., VSCode, GoLand)
Additionally, you'll need a 1inch API key. You can obtain one by signing up on the 1inch API portal.
Project Structure
We'll organize our project with the following structure:
orders-api/
├── main.go
├── go.mod
├── pkg/
│ ├── config/
│ │ └── config.go
│ └── oneinch/
│ └── oneinch.go
- main.go: The entry point of our application.
- pkg/config/config.go: Handles environment configuration.
- pkg/oneinch/oneinch.go: Contains the logic to interact with the 1inch API.
Setting Up the 1inch Client
First, let's create a package to interact with the 1inch API. We'll use the fasthttp library for making HTTP requests due to its performance benefits over the standard net/http package.
- Initialize the Project
mkdir orders-api
cd orders-api
go mod init orders-api
- Install Dependencies
go get github.com/valyala/fasthttp
go get github.com/gin-gonic/gin
- Configuration Handling Create a configuration package to load environment variables, such as the 1inch API key.
// pkg/config/config.go
package config
import (
"log"
"os"
"github.com/joho/godotenv"
)
// Config holds the configuration values
type Config struct {
ApiKey string
}
// LoadEnv loads environment variables from a .env file and returns a Config struct
func LoadEnv() (*Config, error) {
err := godotenv.Load()
if err != nil {
log.Println("No .env file found. Using environment variables.")
}
apiKey := os.Getenv("ONEINCH_API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("ONEINCH_API_KEY not set")
}
return &Config{
ApiKey: apiKey,
}, nil
}
Create a .env file in the root of your project and add your API key:
ONEINCH_API_KEY=your_1inch_api_key_here
- Implementing the 1inch Client
// pkg/oneinch/oneinch.go
package oneinch
import (
"fmt"
"log"
"net/url"
"orders-api/pkg/config"
"github.com/valyala/fasthttp"
)
// GetQuote fetches a token swap quote from the 1inch API
func GetQuote(fromTokenAddress, toTokenAddress, amount string) error {
// Load configuration
cfg, err := config.LoadEnv()
if err != nil {
log.Fatal(err)
}
apiKey := cfg.ApiKey
baseUrl := "https://api.1inch.dev/swap/v6.0/1/quote"
// Create query parameters
params := url.Values{}
params.Set("fromTokenAddress", fromTokenAddress)
params.Set("toTokenAddress", toTokenAddress)
params.Set("amount", amount)
// Construct the full API URL
apiUrl := fmt.Sprintf("%s?%s", baseUrl, params.Encode())
// Prepare the HTTP request
req := fasthttp.AcquireRequest()
req.SetRequestURI(apiUrl)
req.Header.SetMethod(fasthttp.MethodGet)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
req.Header.Set("Content-Type", "application/json")
// Prepare the HTTP response
resp := fasthttp.AcquireResponse()
// Initialize the fasthttp client
client := fasthttp.Client{}
// Send the request
err = client.Do(req, resp)
if err != nil {
fmt.Println("Error sending request:", err)
return err
}
// Read and print the response body
body := resp.Body()
fmt.Println(string(body))
// Release resources
fasthttp.ReleaseRequest(req)
fasthttp.ReleaseResponse(resp)
return nil
}
Creating the API Server with Gin
Now, let's set up the API server using Gin, which will expose an endpoint to fetch token quotes.
func GetMultipleQuotes(tokenPairs [][]string) error {
var wg sync.WaitGroup
errChan := make(chan error, len(tokenPairs)) // Channel to capture errors
defer close(errChan)
for _, pair := range tokenPairs {
wg.Add(1)
go func(fromToken, toToken string) {
defer wg.Done()
err := GetQuote(fromToken, toToken, "1000000000000000000") // Example amount: 1 ETH in wei
if err != nil {
errChan <- err
}
}(pair[0], pair[1])
}
// Wait for all goroutines to finish
wg.Wait()
// Check for errors
for err := range errChan {
if err != nil {
return err
}
}
return nil
}
Explanation
Gin Setup: We initialize a Gin router and define a route group /v1. Within this group, we add the /quote endpoint which is handled by the getQuote function.
Handling Requests: The getQuote function extracts query parameters (fromToken, toToken, amount) from the request. It validates these inputs to ensure they are present.
Fetching the Quote: It then calls the oneinch.GetQuote function, which interacts with the 1inch API to fetch the quote. If successful, it returns a success message. In a production scenario, you'd parse the response from 1inch and return meaningful data to the client.
Testing the API
With everything set up, let's test our API using curl.
Start the server:
go run main.go
In another terminal, execute the following curl command:
curl "http://localhost:8080/v1/quote?fromToken=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&toToken=0xdAC17F958D2ee523a2206206994597C13D831ec7&amount=1000000000000000000"
Parameters Explained:
fromToken: The address of the token you want to swap from. 0xEeee...EEeE typically represents Ether (ETH) in 1inch API.
toToken: The address of the token you want to swap to. In this case, 0xdAC17F958D2ee523a2206206994597C13D831ec7 is the address for Tether (USDT).
amount: The amount to swap, specified in the smallest unit of the token (wei for ETH). 1000000000000000000 wei equals 1 ETH.
Enhancements and Next Steps
While this basic setup provides a functional endpoint, there are several enhancements you might consider:
Error Handling: Instead of using log.Fatal, handle errors gracefully and return meaningful messages to the client.
Response Parsing: Parse the JSON response from 1inch and return structured data to the client instead of a generic success message.
Caching: Implement caching mechanisms to reduce redundant API calls and improve performance.
Security: Secure your API endpoints with authentication and rate limiting to prevent abuse.
Environment Variables: Use more robust configuration management, possibly supporting multiple environments (development, staging, production).
Testing: Write unit and integration tests to ensure the reliability of your API.
Posted on October 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024