Skip to content

Commit

Permalink
feat(config): allow specifying api url with port and path
Browse files Browse the repository at this point in the history
deprecate ApiScheme, ApiHost and replace them with ApiUrl

close #56
  • Loading branch information
rhamzeh committed Dec 6, 2023
1 parent aae9db4 commit cdd7206
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 132 deletions.
18 changes: 18 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
groups:
dependencies:
patterns:
- "*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
dependencies:
patterns:
- "*"
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,8 @@ import (

func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiScheme: os.Getenv("OPENFGA_API_SCHEME"), // optional, defaults to "https"
ApiHost: os.Getenv("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example)
StoreId: os.Getenv("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
})

if err != nil {
Expand All @@ -133,13 +132,12 @@ import (

func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiScheme: os.Getenv("OPENFGA_API_SCHEME"), // optional, defaults to "https"
ApiHost: os.Getenv("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example)
StoreId: os.Getenv("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
Credentials: &credentials.Credentials{
Method: credentials.CredentialsMethodApiToken,
Config: &credentials.Config{
ApiToken: os.Getenv("OPENFGA_API_TOKEN"), // will be passed as the "Authorization: Bearer ${ApiToken}" request header
ApiToken: os.Getenv("FGA_API_TOKEN"), // will be passed as the "Authorization: Bearer ${ApiToken}" request header
},
},
})
Expand All @@ -162,17 +160,16 @@ import (

func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiScheme: os.Getenv("OPENFGA_API_SCHEME"), // optional, defaults to "https"
ApiHost: os.Getenv("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example)
StoreId: os.Getenv("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
AuthorizationModelId: openfga.PtrString("OPENFGA_AUTHORIZATION_MODEL_ID"),
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
AuthorizationModelId: openfga.PtrString("OPENFGA_AUTHORIZATION_MODEL_ID"),
Credentials: &credentials.Credentials{
Method: credentials.CredentialsMethodClientCredentials,
Config: &credentials.Config{
ClientCredentialsClientId: os.Getenv("OPENFGA_CLIENT_ID"),
ClientCredentialsClientSecret: os.Getenv("OPENFGA_CLIENT_SECRET"),
ClientCredentialsApiAudience: os.Getenv("OPENFGA_API_AUDIENCE"),
ClientCredentialsApiTokenIssuer: os.Getenv("OPENFGA_API_TOKEN_ISSUER"),
ClientCredentialsClientId: os.Getenv("FGA_CLIENT_ID"),
ClientCredentialsClientSecret: os.Getenv("FGA_CLIENT_SECRET"),
ClientCredentialsApiAudience: os.Getenv("FGA_API_AUDIENCE"),
ClientCredentialsApiTokenIssuer: os.Getenv("FGA_API_TOKEN_ISSUER"),
},
},
})
Expand Down
20 changes: 5 additions & 15 deletions api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,37 +236,27 @@ func (c *APIClient) prepareRequest(
}

// Setup path and query parameters
url, err := url.Parse(path)
uri, err := url.Parse(c.cfg.ApiUrl + path)
if err != nil {
return nil, err
}

// Override request host, if applicable
if c.cfg.ApiHost != "" {
url.Host = c.cfg.ApiHost
}

// Override request scheme, if applicable
if c.cfg.ApiScheme != "" {
url.Scheme = c.cfg.ApiScheme
}

// Adding Query Param
query := url.Query()
query := uri.Query()
for k, v := range queryParams {
for _, iv := range v {
query.Add(k, iv)
}
}

// Encode the parameters.
url.RawQuery = query.Encode()
uri.RawQuery = query.Encode()

// Generate a new request
if body != nil {
localVarRequest, err = http.NewRequest(method, url.String(), body)
localVarRequest, err = http.NewRequest(method, uri.String(), body)
} else {
localVarRequest, err = http.NewRequest(method, url.String(), nil)
localVarRequest, err = http.NewRequest(method, uri.String(), nil)
}
if err != nil {
return nil, err
Expand Down
42 changes: 21 additions & 21 deletions api_open_fga_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func TestOpenFgaApiConfiguration(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", fmt.Sprintf("%s://%s/stores/%s/authorization-models", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId),
httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models", configuration.ApiUrl, configuration.StoreId),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, ReadAuthorizationModelsResponse{AuthorizationModels: []AuthorizationModel{
{
Expand Down Expand Up @@ -247,7 +247,7 @@ func TestOpenFgaApiConfiguration(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", fmt.Sprintf("%s://%s/stores/%s/authorization-models", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId),
httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models", configuration.ApiUrl, configuration.StoreId),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, ReadAuthorizationModelsResponse{AuthorizationModels: []AuthorizationModel{
{
Expand Down Expand Up @@ -287,7 +287,7 @@ func TestOpenFgaApiConfiguration(t *testing.T) {
if numCalls != 1 {
t.Fatalf("Expected call to get access token to be made exactly once, saw: %d", numCalls)
}
numCalls = info[fmt.Sprintf("GET %s://%s/stores/%s/authorization-models", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId)]
numCalls = info[fmt.Sprintf("GET %s/stores/%s/authorization-models", configuration.ApiUrl, configuration.StoreId)]
if numCalls != 1 {
t.Fatalf("Expected call to get authorization models to be made exactly once, saw: %d", numCalls)
}
Expand All @@ -311,7 +311,7 @@ func TestOpenFgaApiConfiguration(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", fmt.Sprintf("%s://%s/stores/%s/authorization-models", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId),
httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models", configuration.ApiUrl, configuration.StoreId),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(200, ReadAuthorizationModelsResponse{AuthorizationModels: []AuthorizationModel{
{
Expand All @@ -338,7 +338,7 @@ func TestOpenFgaApiConfiguration(t *testing.T) {
if numCalls != 0 {
t.Fatalf("Unexpected call to get access token made. Expected 0, saw: %d", numCalls)
}
numCalls = info[fmt.Sprintf("GET %s://%s/stores/%s/authorization-models", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId)]
numCalls = info[fmt.Sprintf("GET %s/stores/%s/authorization-models", configuration.ApiUrl, configuration.StoreId)]
if numCalls != 1 {
t.Fatalf("Expected call to get authorization models to be made exactly once, saw: %d", numCalls)
}
Expand Down Expand Up @@ -428,7 +428,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -491,7 +491,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -532,7 +532,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath, modelId),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath, modelId),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -584,7 +584,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -638,7 +638,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -684,7 +684,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -727,7 +727,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -775,7 +775,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -819,7 +819,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -885,7 +885,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse)
if err != nil {
Expand Down Expand Up @@ -938,7 +938,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
errObj := ErrorResponse{
Code: "validation_error",
Expand Down Expand Up @@ -1001,7 +1001,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
errObj := ErrorResponse{
Code: "auth_failure",
Expand Down Expand Up @@ -1057,7 +1057,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
errObj := ErrorResponse{
Code: "undefined_endpoint",
Expand Down Expand Up @@ -1120,7 +1120,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
errObj := ErrorResponse{
Code: "rate_limit_exceeded",
Expand Down Expand Up @@ -1193,7 +1193,7 @@ func TestOpenFgaApi(t *testing.T) {
defer httpmock.DeactivateAndReset()
firstMock := httpmock.NewStringResponder(429, "")
secondMock, _ := httpmock.NewJsonResponder(200, expectedResponse)
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
firstMock.Then(firstMock).Then(firstMock).Then(secondMock),
)
updatedConfiguration, err := NewConfiguration(Configuration{
Expand Down Expand Up @@ -1253,7 +1253,7 @@ func TestOpenFgaApi(t *testing.T) {

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s://%s/stores/%s/%s", configuration.ApiScheme, configuration.ApiHost, configuration.StoreId, test.RequestPath),
httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", configuration.ApiUrl, configuration.StoreId, test.RequestPath),
func(req *http.Request) (*http.Response, error) {
errObj := ErrorResponse{
Code: "internal_error",
Expand Down
9 changes: 8 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ var DEFAULT_MAX_METHOD_PARALLEL_REQS = int32(10)

type ClientConfiguration struct {
fgaSdk.Configuration
ApiScheme string `json:"api_scheme,omitempty"`
// ApiScheme - defines the scheme for the API: http or https
// Deprecated: use ApiUrl instead of ApiScheme and ApiHost
ApiScheme string `json:"api_scheme,omitempty"`
// ApiHost - defines the host for the API without the scheme e.g. (api.fga.example)
// Deprecated: use ApiUrl instead of ApiScheme and ApiHost
ApiHost string `json:"api_host,omitempty"`
ApiUrl string `json:"api_url,omitempty"`
StoreId string `json:"store_id,omitempty"`
AuthorizationModelId *string `json:"authorization_model_id,omitempty"`
Credentials *credentials.Credentials `json:"credentials,omitempty"`
Expand All @@ -51,6 +56,7 @@ func newClientConfiguration(cfg *fgaSdk.Configuration) ClientConfiguration {
return ClientConfiguration{
ApiScheme: cfg.ApiScheme,
ApiHost: cfg.ApiHost,
ApiUrl: cfg.ApiUrl,
StoreId: cfg.StoreId,
Credentials: cfg.Credentials,
DefaultHeaders: cfg.DefaultHeaders,
Expand All @@ -70,6 +76,7 @@ func NewSdkClient(cfg *ClientConfiguration) (*OpenFgaClient, error) {
apiConfiguration, err := fgaSdk.NewConfiguration(fgaSdk.Configuration{
ApiScheme: cfg.ApiScheme,
ApiHost: cfg.ApiHost,
ApiUrl: cfg.ApiUrl,
StoreId: cfg.StoreId,
Credentials: cfg.Credentials,
DefaultHeaders: cfg.DefaultHeaders,
Expand Down
Loading

0 comments on commit cdd7206

Please sign in to comment.