requestgen
requestgen generates the cascade call for your request object
Installation
go install github.com/txt1899/cmd/requestgen
Usage
requestgen
scans all the fields of the target struct, and generate setter
methods and getParameters method.
package api
import "github.com/txt1899/requestgen"
//go:generate requestgen -type PlaceOrderRequest
type PlaceOrderRequest struct {
// client is an optional field to implement.
// If the API needs authentication, the client type should be `AuthenticatedAPIClient`. Otherwise, `APIClient`.
// The `Do()` method will be generated if the client field is provided.
// note, you will have to add flag "-url" and "-method" to specify your endpoint and the request method.
client requestgen.AuthenticatedAPIClient
// A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 32 characters.
clientOrderID *string `param:"clientOid,required" defaultValuer:"uuid()"`
symbol string `param:"symbol,required"`
// A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 8 characters.
tag *string `param:"tag"`
// "buy" or "sell"
side SideType `param:"side,required" validValues:"buy,sell"`
orderType OrderType `param:"ordType" validValues:"limit,market"`
size string `param:"size"`
// limit order parameters
price *string `param:"price,omitempty"`
timeInForce *TimeInForceType `param:"timeInForce,omitempty" validValues:"GTC,GTT,FOK"`
complexArg ComplexArg `param:"complexArg"`
startTime *time.Time `param:"startTime,milliseconds" defaultValuer:"now()"`
}
Or you can run generate command manually like this:
go run ./cmd/requestgen -type PlaceOrderRequest -method GET -url "/api/v1/bullet" -debug ./example/api
Then you can do:
req := &PlaceOrderRequest{}
err := req.Tag(..).
OrderType(OrderTypeLimit).
Side(SideTypeBuy).
Do(ctx)
Embedding parameter in the URL
You can use the slug
attribute to embed the parameter into the url:
//go:generate GetRequest -url "/api/v1/accounts/{accountID}" -type NewGetAccountRequest -responseDataType []Account
type NewGetAccountRequest struct {
client requestgen.AuthenticatedAPIClient
accountID string `param:"accountID,slug"`
}
Command Options
-submitFormat [submitDataForamt]
query: Usually used for query as get requests
from: Usually used for post requests, received in from format
json: Usually used for post requests, received in json format
// When the field tag contains "query"
// the field will be appended to the URL for sending the request
// even if the submit format is not "query".
type MyRequest struct {
// ... other filed
tag string `param:"tag, query"` // https://example.com/api/v1/order?tag=xxx
}
-responseType [responseTypeSelector]
When responseTypeSelector
is not given, interface{}
will be used for decoding the response content from the API server.
You can define your own responseType struct that can decode the API response, like this, e.g.,
type Response struct {
Code string `json:"code"`
Message string `json:"msg"`
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
TotalNum int `json:"totalNum"`
TotalPage int `json:"totalPage"`
Orders []Orders `json:"orders"`
}
And then use the type selector like this:
# if the type is in a relative package
requestgen ... -responseType '"./example/api".Response'
# if the type is in the same package
requestgen ... -responseType '".".Response'
When using requestgen with go:generate, you should handle the quote escaping
for the type selector, for example:
//go:generate requestgen -type PlaceOrderRequest -responseType "\".\".Response" -responseDataField Data -responseDataType "\".\"Order"
But don't worry about the escaping, the above selector can be simplified as:
//go:generate requestgen -type PlaceOrderRequest -responseType .Response -responseDataField Data -responseDataType .Order
If you want to reference a type defined in an external package, you can pass
something like "net/url".Response
as the type selector, but it needs to be
escaped like this:
//go:generate requestgen -type PlaceOrderRequest -responseType "\"net/url\".Response"
-responseDataField [dataField]
When dataField
is given, it means your data is inside the responseType
, the field name is where you want to extract the data from.
Be sure to define dataField
as a json.RawMessage
so that the generated code can handle the decoding separately.
For example:
type Response struct {
Code string `json:"code"`
Message string `json:"msg"`
CurrentPage int `json:"currentPage"`
PageSize int `json:"pageSize"`
TotalNum int `json:"totalNum"`
TotalPage int `json:"totalPage"`
Data json.RawMessage `json:"data"`
}
-responseDataType [dataType]
When dataType
is given, it means your data is inside the responseType
. the raw json message will be decoded with this given type.
Placing parameter in the request query
//go:generate GetRequest -url "/api/orders" -type GetOpenOrdersRequest -responseDataType []Order
type GetOpenOrdersRequest struct {
client requestgen.AuthenticatedAPIClient
market string `param:"market,query"`
}
func (c *RestClient) NewGetOpenOrdersRequest(market string) *GetOpenOrdersRequest {
return &GetOpenOrdersRequest{
client: c,
market: market,
}
}
Placing parameter in the request path
//go:generate requestgen -method DELETE -url "/api/orders/:orderID" -type CancelOrderRequest -responseType .APIResponse
type CancelOrderRequest struct {
client requestgen.AuthenticatedAPIClient
orderID string `param:"orderID,required,slug"`
}
func (c *RestClient) NewCancelOrderRequest(orderID string) *CancelOrderRequest {
return &CancelOrderRequest{
client: c,
orderID: orderID,
}
}
APIClient
The project does not provide an http client but defines two interfaces, PrivateClient
and PublicClient
.
You need to implement the methods in these interfaces in your own project.
// PrivateClient fot the signature private requests
type PrivateClient interface {
NewSignRequest(ctx context.Context, method, endPoint string, params url.Values, payload interface{}) ([]byte, int, error)
DecodeJSON(buffer []byte, statusCode int, resp interface{}) error
}
// PublicClient for the public requests
type PublicClient interface {
NewRequest(ctx context.Context, method, endPoint string, params url.Values, payload interface{}) ([]byte, int, error)
DecodeJSON(buffer []byte, statusCode int, resp interface{}) error
}
example:
type RestClient struct {
client *http.Client
}
func NewClient() *RestClient {
return &RestClient{
client: http.DefaultClient,
}
func (c *RestClient) NewRequest(ctx context.Context, method, endPoint string, params url.Values, payload interface{}) ([]byte, int, error) {
//TODO implement me
panic("implement me")
}
func (c *RestClient) NewSignRequest(ctx context.Context, method, endPoint string, params url.Values, payload interface{}) ([]byte, int, error) {
//TODO implement me
panic("implement me")
}
func (c *RestClient) DecodeJSON(buffer []byte, statusCode int, resp interface{}) error {
//TODO implement me
panic("implement me")
}