genapi is a declarative HTTP client generator for Go, inspired by OpenFeign(https://github.com/OpenFeign/feign). It allows you to write HTTP clients using just interface definitions with annotations, eliminating the need for manual HTTP request handling.
- Declarative HTTP API client using Go interfaces
- Automatic JSON marshaling/unmarshaling
- Support for path/query parameters
- Custom header support
- Flexible response handling
- Context support for cancellation/timeouts
- Use your favorate http client in runtime
go get github.com/lexcao/genapi
- Define your API interface:
package api
import "github.com/lexcao/genapi"
//go:generate go run github.com/lexcao/genapi/cmd/genapi -file $GOFILE
// @BaseURL("https://api.github.com")
// @Header("Accept", "application/vnd.github.v3+json")
type GitHub interface {
genapi.Interface
// @GET("/repos/{owner}/{repo}/contributors")
Contributors(ctx context.Context, owner, repo string) ([]Contributor, error)
}
type Contributor struct {
Login string `json:"login"`
Contributions int `json:"contributions"`
}
- Generate the client code:
$ go generate ./api
- Use the client:
import (
"fmt"
"github.com/lexcao/genapi"
"your/package/to/api"
)
func main() {
client := genapi.New[api.GitHub]()
contributors, err := client.Contributors(context.Background(), "lexcao", "genapi")
if err != nil {
log.Fatalf("failed to get contributors: %v", err)
}
for _, c := range contributors {
fmt.Printf("%s: %d contributions\n", c.Login, c.Contributions)
}
}
package main
import (
http_client "net/http"
"github.com/lexcao/genapi"
"github.com/lexcao/genapi/pkg/clients/http"
)
func main() {
httpClient := &http_client.Client{}
client := genapi.New[api.GitHub](
genapi.WithHttpClient(http.New(httpClient))
)
// or set client in the runtime
client.SetHttpClient(httpClient)
}
Resty is as seperate pkg, you need to install first
$ go get github.com/lexcao/genapi/pkg/clients/resty
Then use as following,
package main
import (
"github.com/lexcao/genapi"
"github.com/lexcao/genapi/pkg/clients/resty"
resty_client "github.com/go-resty/resty/v2"
)
func main() {
client := genapi.New[api.GitHub](
genapi.WithHttpClient(resty.DefaultClient), // default Resty client
genapi.WithHttpClient(resty.New(resty_client.New())), // customized Resty client
)
}
You should implmentate the interface genapi.HttpClient
(You can follow the resty for reference)
type HttpClient interface {
SetConfig(Config)
Do(req *Request) (*Response, error)
}
After implmentation, you should test your code to verify the base cases provided by the genapi (You can follow the resty_test for reference)
package client
import "github.com/lexcao/genapi"
func (c *HttpClient) GetClient() *http.Client {
return c.client.GetClient()
}
func TestHttpClient(t *testing.T) {
genapi.TestHttpClient(t, func() genapi.HttpClientTester { return DefaultClient })
}
The client can be configured with various options:
client := genapi.New[api.GitHub](
// Set runtime client
genapi.WithHttpClient(resty.DefaultClient),
// Set dynamic BaseURL
genapi.WithBaseURL(os.GetEnv("API_ENDPOINT")),
// Add global headers
genapi.WithHeader(map[string]string{
"Authorization": "Bearer " + token,
}),
)
Every interface must embed genapi.Interface
:
type MyAPI interface {
genapi.Interface
// your API methods here
}
Annotation | Description | Example |
---|---|---|
@BaseURL | Base URL for all API requests | @BaseURL("https://api.github.com") |
@Header | Global headers applied to all requests | @Header("Accept", "application/json") |
Annotation | Description | Example |
---|---|---|
@GET, @POST, etc | HTTP method and path | @GET("/users/{id}") |
@Query | URL query parameters | @Query("sort", "{sort}") |
@Header | Method-specific headers | @Header("Authorization", "Bearer {token}") |
genapi supports multiple response formats to fit your needs:
// No response body
func DeleteUser(ctx context.Context, id string) error
// Typed response with error handling
func GetUser(ctx context.Context, id string) (User, error)
// Raw response access
func GetRawResponse(ctx context.Context) (*genapi.Response, error)
// Must-style response (panics on error)
func MustGetUser(ctx context.Context, id string) User
You can access the Response from error
err := client.DeleteUser(ctx, id)
var apiErr *genapi.Error
if errors.As(err, &apiErr) {
// handle error with apiErr.Response
}
- Go 1.18 or higher
- Make (optional, for using Makefile commands)
- Clone the repository
$ git clone https://github.com/lexcao/genapi.git
$ cd genapi
- Install dependencies
$ go mod download
- Run tests
$ make test
make test
- Run tests for all go modulesmake lint
- Run linter for all go modulesmake generate
- Run go generatemake clean
- Clean up generated files
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests.
This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.