Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release(go-sdk): v0.3.3 with WriteAuthorizationModel fix #262

Merged
merged 3 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions config/clients/go/CHANGELOG.md.mustache
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v0.3.3

### [0.3.3](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v0.3.2...v0.3.3) (2023-12-21)

- fix: WriteAuthorizationModel was not passing conditions to API
- chore: add example project

## v0.3.2

### [0.3.2](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v0.3.1...v0.3.2) (2023-12-20)
Expand Down
9 changes: 7 additions & 2 deletions config/clients/go/config.overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"sdkId": "go",
"gitRepoId": "go-sdk",
"packageName": "openfga",
"packageVersion": "0.3.2",
"packageVersion": "0.3.3",
"packageDescription": "Go SDK for OpenFGA",
"packageDetailedDescription": "This is an autogenerated Go SDK for OpenFGA. It provides a wrapper around the [OpenFGA API definition](https://openfga.dev/api).",
"fossaComplianceNoticeId": "41c01c64-f74a-414a-9e39-7aeca87bc47b",
Expand Down Expand Up @@ -75,6 +75,11 @@
"internal/utils/ulid_test.mustache": {
"destinationFilename": "internal/utils/ulid_test.go",
"templateType": "SupportingFiles"
}
},
"example/Makefile": {},
"example/README.md": {},
"example/example1/example1.go": {},
"example/example1/go.mod": {},
"example/example1/go.sum": {}
}
}
6 changes: 1 addition & 5 deletions config/clients/go/template/client/client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -779,11 +779,7 @@ type SdkClientWriteAuthorizationModelRequestInterface interface {
GetContext() _context.Context
}


type ClientWriteAuthorizationModelRequest struct {
TypeDefinitions []fgaSdk.TypeDefinition `json:"type_definitions"`
SchemaVersion string `json:"schema_version,omitempty"`
}
type ClientWriteAuthorizationModelRequest = fgaSdk.WriteAuthorizationModelRequest;

type ClientWriteAuthorizationModelOptions struct {
}
Expand Down
14 changes: 14 additions & 0 deletions config/clients/go/template/example/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
all: run

project_name=example1
openfga_version=latest

restore:
go mod tidy

run: restore
go run ${project_name}/${project_name}.go

run-openfga:
docker pull docker.io/openfga/openfga:${openfga_version} && \
docker run -p 8080:8080 docker.io/openfga/openfga:${openfga_version}
34 changes: 34 additions & 0 deletions config/clients/go/template/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Examples of using the OpenFGA Go SDK

A set of examples on how to call the OpenFGA Go SDK

### Examples
Example 1:
A bare bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access.


### Running the Examples

Prerequisites:
- `docker`
- `make`
- `go` 1.20+

#### Run using a published SDK

Steps
1. Clone/Copy the example folder
2. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done)
3. Run `make run` to run the example

#### Run using a local unpublished SDK build

Steps
1. Build the SDK
2. In the Example `go.mod`, uncomment out the part that replaces the remote SDK with the local one, e.g.
```
// To refrence local build, uncomment below and run `go mod tidy`
replace github.com/openfga/go-sdk v0.3.2 => ../../
```
3. If you have an OpenFGA server running, you can use it, otherwise run `make run-openfga` to spin up an instance (you'll need to switch to a different terminal after - don't forget to close it when done)
4. Run `make run` to run the example
290 changes: 290 additions & 0 deletions config/clients/go/template/example/example1/example1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
package main

import (
"context"
"fmt"
openfga "github.com/openfga/go-sdk"
"github.com/openfga/go-sdk/client"
"github.com/openfga/go-sdk/credentials"
"os"
)

func mainInner() error {

ctx := context.Background()
creds := credentials.Credentials{}
if os.Getenv("FGA_CLIENT_ID") != "" {
creds = credentials.Credentials{
Method: credentials.CredentialsMethodClientCredentials,
Config: &credentials.Config{
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"),
},
}
}

apiUrl := os.Getenv("FGA_API_URL")
if apiUrl == "" {
apiUrl = "http://localhost:8080"
}
fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{
ApiUrl: apiUrl,
StoreId: os.Getenv("FGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores`
AuthorizationModelId: os.Getenv("FGA_AUTHORIZATION_MODEL_ID"), // optional, recommended to be set for production
Credentials: &creds,
})

if err != nil {
return err
}

// ListStores
fmt.Println("Listing Stores")
stores1, err := fgaClient.ListStores(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Stores Count: %d\n", len(stores1.GetStores()))

// CreateStore
fmt.Println("Creating Test Store")
store, err := fgaClient.CreateStore(ctx).Body(client.ClientCreateStoreRequest{Name: "Test Store"}).Execute()
if err != nil {
return err
}
fmt.Printf("Test Store ID: %v\n", store.Id)

// Set the store id
fgaClient.SetStoreId(store.Id)

// ListStores after Create
fmt.Println("Listing Stores")
stores, err := fgaClient.ListStores(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Stores Count: %d\n", len(stores.Stores))

// GetStore
fmt.Println("Getting Current Store")
currentStore, err := fgaClient.GetStore(ctx).Execute()
if err != nil {
return err
}
fmt.Println("Current Store Name: %v\n" + currentStore.Name)

// ReadAuthorizationModels
fmt.Println("Reading Authorization Models")
models, err := fgaClient.ReadAuthorizationModels(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Models Count: %d\n", len(models.AuthorizationModels))

// ReadLatestAuthorizationModel
latestAuthorizationModel, err := fgaClient.ReadLatestAuthorizationModel(ctx).Execute()
if err != nil {
return err
}
if latestAuthorizationModel.AuthorizationModel != nil {
fmt.Printf("Latest Authorization Model ID: %v\n", (*latestAuthorizationModel.AuthorizationModel).Id)
} else {
fmt.Println("Latest Authorization Model not found")
}

// WriteAuthorizationModel
fmt.Println("Writing an Authorization Model")
body := client.ClientWriteAuthorizationModelRequest{
SchemaVersion: "1.1",
TypeDefinitions: []openfga.TypeDefinition{
{
Type: "user",
Relations: &map[string]openfga.Userset{},
},
{
Type: "document",
Relations: &map[string]openfga.Userset{
"writer": {This: &map[string]interface{}{}},
"viewer": {Union: &openfga.Usersets{
Child: []openfga.Userset{
{This: &map[string]interface{}{}},
{ComputedUserset: &openfga.ObjectRelation{
Object: openfga.PtrString(""),
Relation: openfga.PtrString("writer"),
}},
},
}},
},
Metadata: &openfga.Metadata{
Relations: &map[string]openfga.RelationMetadata{
"writer": {
DirectlyRelatedUserTypes: &[]openfga.RelationReference{
{Type: "user"},
{Type: "user", Condition: openfga.PtrString("ViewCountLessThan200")},
},
},
"viewer": {
DirectlyRelatedUserTypes: &[]openfga.RelationReference{
{Type: "user"},
},
},
},
},
},
},
Conditions: &map[string]openfga.Condition{
"ViewCountLessThan200": {
Name: "ViewCountLessThan200",
Expression: "ViewCount < 200",
Parameters: &map[string]openfga.ConditionParamTypeRef{
"ViewCount": {
TypeName: openfga.INT,
},
"Type": {
TypeName: openfga.STRING,
},
"Name": {
TypeName: openfga.STRING,
},
},
},
},
}
authorizationModel, err := fgaClient.WriteAuthorizationModel(ctx).Body(body).Execute()
if err != nil {
return err
}
fmt.Printf("Authorization Model ID: %v\n", authorizationModel.AuthorizationModelId)

// ReadAuthorizationModels - after Write
fmt.Println("Reading Authorization Models")
models, err = fgaClient.ReadAuthorizationModels(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Models Count: %d\n", len(models.AuthorizationModels))

// ReadLatestAuthorizationModel - after Write
latestAuthorizationModel, err = fgaClient.ReadLatestAuthorizationModel(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Latest Authorization Model ID: %v\n", (*latestAuthorizationModel.AuthorizationModel).Id)

// Write
fmt.Println("Writing Tuples")
_, err = fgaClient.Write(ctx).Body(client.ClientWriteRequest{
Writes: []client.ClientTupleKey{
{
User: "user:anne",
Relation: "writer",
Object: "document:roadmap",
Condition: &openfga.RelationshipCondition{
Name: "ViewCountLessThan200",
Context: &map[string]interface{}{"Name": "Roadmap", "Type": "document"},
},
},
},
}).Options(client.ClientWriteOptions{
AuthorizationModelId: &authorizationModel.AuthorizationModelId,
}).Execute()
if err != nil {
return err
}
fmt.Println("Done Writing Tuples")

// Set the model ID
err = fgaClient.SetAuthorizationModelId(latestAuthorizationModel.AuthorizationModel.Id)
if err != nil {
return err
}

// Read
fmt.Println("Reading Tuples")
readTuples, err := fgaClient.Read(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Read Tuples: %v\n", readTuples)

// ReadChanges
fmt.Println("Reading Tuple Changes")
readChangesTuples, err := fgaClient.ReadChanges(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Read Changes Tuples: %v\n", readChangesTuples)

// Check
fmt.Println("Checking for access")
failingCheckResponse, err := fgaClient.Check(ctx).Body(client.ClientCheckRequest{
User: "user:anne",
Relation: "viewer",
Object: "document:roadmap",
}).Execute()
if err != nil {
fmt.Printf("Failed due to: %w\n", err.Error())
} else {
fmt.Printf("Allowed: %v\n", failingCheckResponse.Allowed)
}

// Checking for access with context
fmt.Println("Checking for access with context")
checkResponse, err := fgaClient.Check(ctx).Body(client.ClientCheckRequest{
User: "user:anne",
Relation: "viewer",
Object: "document:roadmap",
Context: &map[string]interface{}{"ViewCount": 100},
}).Execute()
if err != nil {
return err
}
fmt.Printf("Allowed: %v\n", checkResponse.Allowed)

// WriteAssertions
_, err = fgaClient.WriteAssertions(ctx).Body([]client.ClientAssertion{
{
User: "user:carl",
Relation: "writer",
Object: "document:budget",
Expectation: true,
},
{
User: "user:anne",
Relation: "viewer",
Object: "document:roadmap",
Expectation: false,
},
}).Execute()
if err != nil {
return err
}
fmt.Println("Assertions updated")

// ReadAssertions
fmt.Println("Reading Assertions")
assertions, err := fgaClient.ReadAssertions(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Assertions: %v\n", assertions)

// DeleteStore
fmt.Println("Deleting Current Store")
_, err = fgaClient.DeleteStore(ctx).Execute()
if err != nil {
return err
}
fmt.Printf("Deleted Store: %v\n", currentStore.Name)

return nil
}

func main() {
if err := mainInner(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}
Loading
Loading