From ced496049d584a9eead968a9486ab42c1c060a29 Mon Sep 17 00:00:00 2001 From: Raghd Hamzeh Date: Fri, 17 Jun 2022 14:47:52 -0400 Subject: [PATCH] feat(config): update auth opts & allow no storeId for certain requests --- .github/workflows/main.yaml | 18 +- .openapi-generator/FILES | 2 + CHANGELOG.md | 8 +- README.md | 149 ++++++++++++++--- docs/OpenFgaApi.md | 154 +++++++----------- src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs | 133 ++++++++++++--- src/OpenFga.Sdk.Test/Models/ModelTests.cs | 113 +++++++++++++ src/OpenFga.Sdk/Api/OpenFgaApi.cs | 150 ++++++++++------- src/OpenFga.Sdk/Client/ApiClient.cs | 17 +- src/OpenFga.Sdk/Client/OAuth2Client.cs | 17 +- .../Configuration/Configuration.cs | 57 +------ src/OpenFga.Sdk/Configuration/Credentials.cs | 152 +++++++++++++++++ src/OpenFga.Sdk/Model/Any.cs | 7 + src/OpenFga.Sdk/Model/Assertion.cs | 4 +- src/OpenFga.Sdk/Model/AuthorizationModel.cs | 9 + src/OpenFga.Sdk/Model/CheckRequest.cs | 9 + src/OpenFga.Sdk/Model/CheckResponse.cs | 9 + src/OpenFga.Sdk/Model/Computed.cs | 9 + src/OpenFga.Sdk/Model/ContextualTupleKeys.cs | 4 +- src/OpenFga.Sdk/Model/CreateStoreRequest.cs | 9 + src/OpenFga.Sdk/Model/CreateStoreResponse.cs | 9 + src/OpenFga.Sdk/Model/Difference.cs | 9 + src/OpenFga.Sdk/Model/ExpandRequest.cs | 9 + src/OpenFga.Sdk/Model/ExpandResponse.cs | 9 + src/OpenFga.Sdk/Model/GetStoreResponse.cs | 9 + .../Model/InternalErrorMessageResponse.cs | 9 + src/OpenFga.Sdk/Model/Leaf.cs | 9 + src/OpenFga.Sdk/Model/ListStoresResponse.cs | 9 + src/OpenFga.Sdk/Model/Node.cs | 9 + src/OpenFga.Sdk/Model/Nodes.cs | 11 +- src/OpenFga.Sdk/Model/ObjectRelation.cs | 9 + .../Model/PathUnknownErrorMessageResponse.cs | 9 + .../Model/ReadAssertionsResponse.cs | 9 + .../Model/ReadAuthorizationModelResponse.cs | 9 + .../Model/ReadAuthorizationModelsResponse.cs | 9 + src/OpenFga.Sdk/Model/ReadChangesResponse.cs | 9 + src/OpenFga.Sdk/Model/ReadRequest.cs | 9 + src/OpenFga.Sdk/Model/ReadResponse.cs | 9 + src/OpenFga.Sdk/Model/Status.cs | 9 + src/OpenFga.Sdk/Model/Store.cs | 9 + src/OpenFga.Sdk/Model/Tuple.cs | 9 + src/OpenFga.Sdk/Model/TupleChange.cs | 9 + src/OpenFga.Sdk/Model/TupleKey.cs | 17 +- src/OpenFga.Sdk/Model/TupleKeys.cs | 4 +- src/OpenFga.Sdk/Model/TupleToUserset.cs | 9 + src/OpenFga.Sdk/Model/TypeDefinition.cs | 4 +- src/OpenFga.Sdk/Model/TypeDefinitions.cs | 9 + src/OpenFga.Sdk/Model/Users.cs | 11 +- src/OpenFga.Sdk/Model/Userset.cs | 9 + src/OpenFga.Sdk/Model/UsersetTree.cs | 9 + .../Model/UsersetTreeDifference.cs | 15 +- .../Model/UsersetTreeTupleToUserset.cs | 9 + src/OpenFga.Sdk/Model/Usersets.cs | 9 + .../Model/ValidationErrorMessageResponse.cs | 9 + .../Model/WriteAssertionsRequest.cs | 4 +- .../Model/WriteAuthorizationModelResponse.cs | 9 + src/OpenFga.Sdk/Model/WriteRequest.cs | 9 + 57 files changed, 1063 insertions(+), 303 deletions(-) create mode 100644 src/OpenFga.Sdk.Test/Models/ModelTests.cs create mode 100644 src/OpenFga.Sdk/Configuration/Credentials.cs diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index eab129e..a8ba908 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -9,9 +9,9 @@ jobs: fossa: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: dotnet-version: 6.0.x - name: Restore dependencies @@ -30,9 +30,9 @@ jobs: snyk: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: dotnet-version: 6.0.x - name: Restore dependencies @@ -48,10 +48,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: dotnet-version: 6.0.x @@ -75,10 +75,10 @@ jobs: needs: [test, fossa, snyk] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: dotnet-version: 6.0.x source-url: https://api.nuget.org/v3/index.json @@ -107,7 +107,7 @@ jobs: needs: publish steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: Roang-zero1/github-create-release-action@5cf058ddffa6fa04e5cda07c98570c757dc4a0e1 with: diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index cfbe549..b9b88e8 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -67,6 +67,7 @@ docs/WriteAssertionsRequest.md docs/WriteAuthorizationModelResponse.md docs/WriteRequest.md src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs +src/OpenFga.Sdk.Test/Models/ModelTests.cs src/OpenFga.Sdk.Test/OpenFga.Sdk.Test.csproj src/OpenFga.Sdk/Api/OpenFgaApi.cs src/OpenFga.Sdk/Client/ApiClient.cs @@ -76,6 +77,7 @@ src/OpenFga.Sdk/Client/OAuth2Client.cs src/OpenFga.Sdk/Client/RequestBuilder.cs src/OpenFga.Sdk/Client/Utils.cs src/OpenFga.Sdk/Configuration/Configuration.cs +src/OpenFga.Sdk/Configuration/Credentials.cs src/OpenFga.Sdk/Exceptions/ApiAuthenticationError.cs src/OpenFga.Sdk/Exceptions/ApiError.cs src/OpenFga.Sdk/Exceptions/ApiException.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index a7dc82c..74479fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,4 +4,10 @@ ### [0.0.1](https://github.com/openfga/dotnet-sdk/releases/tag/v0.0.1) (2022-06-09) -Initial Release +Initial OpenFGA .NET SDK release +- Support for [OpenFGA](https://github.com/openfga/openfga) API + - CRUD stores + - Create, read & list authorization models + - Writing and Reading Tuples + - Checking authorization + - Using Expand to understand why access was granted diff --git a/README.md b/README.md index 50f273e..fd828f5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ # .NET SDK for OpenFGA +[![Nuget](https://img.shields.io/nuget/v/OpenFga.Sdk?label=OpenFga.Sdk&style=flat-square)](https://www.nuget.org/packages/OpenFga.Sdk) +[![Release](https://img.shields.io/github/v/release/openfga/dotnet-sdk?sort=semver&color=green)](https://github.com/openfga/dotnet-sdk/releases) +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE) +[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B4989%2Fgithub.com%2Fopenfga%2Fdotnet-sdk.svg?type=shield)](https://app.fossa.com/reports/4b3a7481-7918-4779-b4ff-b42e5c273517) +[![Discord Server](https://img.shields.io/discord/759188666072825867?color=7289da&logo=discord "Discord Server")](https://discord.com/channels/759188666072825867/930524706854031421) +[![Twitter](https://img.shields.io/twitter/follow/openfga?color=%23179CF0&logo=twitter&style=flat-square "@openfga on Twitter")](https://twitter.com/openfga) This is an autogenerated SDK for OpenFGA. It provides a wrapper around the [OpenFGA API definition](https://openfga.dev/api). -Warning: This SDK comes with no SLAs and is not production-ready! - ## Table of Contents - [About OpenFGA](#about) @@ -38,14 +42,14 @@ OpenFGA is designed to make it easy for application builders to model their perm It allows in-memory data storage for quick development, as well as pluggable database modules - with initial support for PostgreSQL. -It offers an [HTTP API](https://openfga.dev/docs/api) and has SDKs for programming languages including [Node.js/JavaScript](https://github.com/openfga/js-sdk), [GoLang](https://github.com/openfga/go-sdk) and [.NET](https://github.com/openfga/dotnet-sdk). +It offers an [HTTP API](https://openfga.dev/api) and has SDKs for programming languages including [Node.js/JavaScript](https://github.com/openfga/js-sdk), [GoLang](https://github.com/openfga/go-sdk) and [.NET](https://github.com/openfga/dotnet-sdk). More SDKs and integrations such as Rego are planned for the future. ## Resources - [OpenFGA Documentation](https://openfga.dev/docs) -- [OpenFGA API Documentation](https://openfga.dev/docs/api) +- [OpenFGA API Documentation](https://openfga.dev/api) - [Twitter](https://twitter.com/openfga) - [OpenFGA Discord Community](https://discord.gg/8naAwJfWN6) - [Zanzibar Academy](https://zanzibar.academy) @@ -77,6 +81,10 @@ Search for and install `OpenFga.Sdk` in each of their respective package manager ### Initializing the API Client +[Learn how to initialize your SDK](https://openfga.dev/docs/getting-started/setup-sdk-client) + +Without an API Token + ```csharp using OpenFga.Sdk.Api; using OpenFga.Sdk.Client; @@ -87,18 +95,46 @@ namespace Example { public class Example { public static void Main() { try { - var configuration = new Configuration(storeId, environment) { +var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` +}; +var openFgaApi = new OpenFgaApi(configuration); + var response = openFgaApi.ReadAuthorizationModels(); + } catch (ApiException e) { + Debug.Print("Status Code: "+ e.ErrorCode); + } + } + } +} +``` + +With an API Token + +```csharp +using OpenFga.Sdk.Api; +using OpenFga.Sdk.Client; +using OpenFga.Sdk.Configuration; +using OpenFga.Sdk.Model; + +namespace Example { + public class Example { + public static async void Main() { + try { + var configuration = new Configuration() { ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" - ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example) - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional (pass in if your provider requires authentication via client credential flow) - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` +Credentials = new Credentials() { + Method = CredentialsMethod.ApiToken, + Config = new CredentialsConfig() { + ApiToken = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN"), // will be passed as the "Authorization: Bearer ${ApiToken}" request header + } +} }; var openFgaApi = new OpenFgaApi(configuration); - var response = openFgaApi.ReadAuthorizationModels(); - Debug.WriteLine(response.AuthorizationModelIds); + var response = await openFgaApi.ReadAuthorizationModels(); } catch (ApiException e) { Debug.Print("Status Code: "+ e.ErrorCode); } @@ -110,17 +146,82 @@ namespace Example { ### Get your Store ID and optional credentials -You need your store id to call the OpenFGA API. You may also configure your credentials if your token provider requires it. +You need your store id to call the OpenFGA API (unless it is to create a store or list all stores). You may also configure your credentials if your service requires it. ### Calling the API +#### List Stores + +[API Documentation](https://openfga.dev/api/docs/api#/Stores/ListStores) + +```csharp +var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), +}; +var openFgaApi = new OpenFgaApi(configuration); +var response = await openFgaApi.ListStores(); + +// stores = [{ "id": "01FQH7V8BEG3GPQW93KTRFR8JB", "name": "FGA Demo Store", "created_at": "2022-01-01T00:00:00.000Z", "updated_at": "2022-01-01T00:00:00.000Z" }] +``` + +#### Create Store + +[API Documentation](https://openfga.dev/api/docs/api#/Stores/CreateStore) + +```csharp +var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), +}; +var openFgaApi = new OpenFgaApi(configuration); +var store = await openFgaApi.CreateStore(new CreateStoreRequest(){Name = "FGA Demo"}) + +// store.Id = "01FQH7V8BEG3GPQW93KTRFR8JB" + +// store store.Id in database + +// update the storeId of the current instance +openFgaApi.StoreId = storeId; + +// continue calling the API normally +``` + +#### Get Store + +[API Documentation](https://openfga.dev/api/docs/api#/Stores/GetStore) + +> Requires a client initialized with a storeId + +```csharp +var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), +}; +var openFgaApi = new OpenFgaApi(configuration); +var store = await openFgaApi.GetStore(); + +// store = { "id": "01FQH7V8BEG3GPQW93KTRFR8JB", "name": "FGA Demo Store", "created_at": "2022-01-01T00:00:00.000Z", "updated_at": "2022-01-01T00:00:00.000Z" } +``` + +#### Delete Store + +[API Documentation](https://openfga.dev/api/docs/api#/Stores/DeleteStore) + +> Requires a client initialized with a storeId + +```csharp +var store = await openFgaApi.DeleteStore(); +``` + #### Write Authorization Model -[API Documentation](https://openfga.dev/docs/api#/Authorization%20Models/WriteAuthorizationModel) +[API Documentation](https://openfga.dev/api#/Authorization%20Models/WriteAuthorizationModel) > Note: To learn how to build your authorization model, check the Docs at https://openfga.dev/docs. -> Learn more about [the OpenFGA configuration language](https://openfga.dev/docs/modeling/configuration-language). +> Learn more about [the OpenFGA configuration language](https://openfga.dev/docs/configuration-language). ```csharp var relations = new Dictionary() @@ -140,7 +241,7 @@ var response = await openFgaApi.WriteAuthorizationModel(body); #### Read a Single Authorization Model -[API Documentation](https://openfga.dev/docs/api#/Authorization%20Models/ReadAuthorizationModel) +[API Documentation](https://openfga.dev/api#/Authorization%20Models/ReadAuthorizationModel) ```csharp string authorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"; // Assuming `1uHxCSuTP0VKPYSnkq1pbb1jeZw` is an id of an existing model @@ -152,7 +253,7 @@ var response = await openFgaApi.ReadAuthorizationModel(authorizationModelId); #### Read Authorization Model IDs -[API Documentation](https://openfga.dev/docs/api#/Authorization%20Models/ReadAuthorizationModels) +[API Documentation](https://openfga.dev/api#/Authorization%20Models/ReadAuthorizationModels) ```csharp var response = await openFgaApi.ReadAuthorizationModels(); @@ -162,7 +263,7 @@ var response = await openFgaApi.ReadAuthorizationModels(); #### Check -[API Documentation](https://openfga.dev/docs/api#/Tuples/Check) +[API Documentation](https://openfga.dev/api#/Relationship%20Queries/Check) ```csharp var body = @@ -173,7 +274,7 @@ var response = await openFgaApi.Check(body); #### Write Tuples -[API Documentation](https://openfga.dev/docs/api#/Tuples/Write) +[API Documentation](https://openfga.dev/api#/Relationship%20Tuples/Write) ```csharp var body = new WriteRequest(new TupleKeys(new List @@ -183,7 +284,7 @@ var response = await openFgaApi.Write(body); #### Delete Tuples -[API Documentation](https://openfga.dev/docs/api#/Tuples/Write) +[API Documentation](https://openfga.dev/api#/Relationship%20Tuples/Write) ```csharp var body = new WriteRequest(new TupleKeys(new List { }), @@ -193,7 +294,7 @@ var response = await openFgaApi.Write(body); #### Expand -[API Documentation](https://openfga.dev/docs/api#/Debugging/Expand) +[API Documentation](https://openfga.dev/api#/Relationship%20Queries/Expand) ```csharp var body = new ExpandRequest(new TupleKey("document:project-roadmap", "editor")); @@ -204,7 +305,7 @@ var response = await openFgaApi.Expand(body); #### Read -[API Documentation](https://openfga.dev/docs/api#/Tuples/Read) +[API Documentation](https://openfga.dev/api#/Relationship%20Tuples/Read) ```csharp // Find if a relationship tuple stating that a certain user is an admin on a certain workspace @@ -237,7 +338,7 @@ var response = await openFgaApi.Read(body); #### Read Changes (Watch) -[API Documentation](https://openfga.dev/docs/api#/Tuples/ReadChanges) +[API Documentation](https://openfga.dev/api#/Relationship%20Tuples/ReadChanges) ```csharp var type = 'workspace'; diff --git a/docs/OpenFgaApi.md b/docs/OpenFgaApi.md index ee0f7cd..8d5854c 100644 --- a/docs/OpenFgaApi.md +++ b/docs/OpenFgaApi.md @@ -44,13 +44,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -124,13 +121,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -202,13 +196,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -279,13 +270,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -359,13 +347,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -437,13 +422,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -517,13 +499,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -597,13 +576,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -677,13 +653,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -757,13 +730,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -839,13 +809,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -923,13 +890,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -1003,13 +967,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); @@ -1084,13 +1045,10 @@ namespace Example { public static void Main() { - var configuration = new Configuration(storeId, environment) { - StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), - Host = Environment.GetEnvironmentVariable("OPENFGA_HOST"), - ApiTokenIssuer = Environment.GetEnvironmentVariable("OPENFGA_API_TOKEN_ISSUER"), // optional, required if client id is passed - ApiAudience = Environment.GetEnvironmentVariable("OPENFGA_API_AUDIENCE"), // optional, required if client id is passed - ClientId = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_ID"), // optional - ClientSecret = Environment.GetEnvironmentVariable("OPENFGA_CLIENT_SECRET"), // optional, required if client id is passed + var configuration = new Configuration() { + ApiScheme = Environment.GetEnvironmentVariable("OPENFGA_API_SCHEME"), // optional, defaults to "https" + ApiHost = Environment.GetEnvironmentVariable("OPENFGA_API_HOST"), // required, define without the scheme (e.g. api.fga.example instead of https://api.fga.example) + StoreId = Environment.GetEnvironmentVariable("OPENFGA_STORE_ID"), // not needed when calling `CreateStore` or `ListStores` }; HttpClient httpClient = new HttpClient(); var openFgaApi = new OpenFgaApi(config, httpClient); diff --git a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs index 7eef11c..7de3db7 100644 --- a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs +++ b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs @@ -14,6 +14,7 @@ using Moq.Protected; using OpenFga.Sdk.Api; using OpenFga.Sdk.Client; +using OpenFga.Sdk.Configuration; using OpenFga.Sdk.Exceptions; using OpenFga.Sdk.Exceptions.Parsers; using OpenFga.Sdk.Model; @@ -62,13 +63,24 @@ public void Dispose() { } /// - /// Test that a storeId is required in the configuration + /// Test that a storeId is not required in the configuration /// [Fact] - public void StoreIdRequired() { + public void StoreIdNotRequired() { var storeIdRequiredConfig = new Configuration.Configuration() { ApiHost = _host }; - void ActionMissingStoreId() => storeIdRequiredConfig.IsValid(); - var exception = Assert.Throws(ActionMissingStoreId); + storeIdRequiredConfig.IsValid(); + } + + /// + /// Test that a storeId is required when calling methods that need it + /// + [Fact] + public async void StoreIdRequiredWhenNeeded() { + var config = new Configuration.Configuration() { ApiHost = _host }; + var openFgaApi = new OpenFgaApi(config); + + async Task ActionMissingStoreId() => await openFgaApi.ReadAuthorizationModels(null, null); + var exception = await Assert.ThrowsAsync(ActionMissingStoreId); Assert.Equal("Required parameter StoreId was not defined when calling Configuration.", exception.Message); } @@ -94,12 +106,44 @@ public void ValidHostWellFormed() { Assert.Equal("Configuration.ApiScheme (https) and Configuration.ApiHost (https://api.fga.example) do not form a valid URI (https://https://api.fga.example)", exception.Message); } + /// + /// Test that providing no api token when it is required should error + /// + [Fact] + public void ApiTokenRequired() { + var missingApiTokenConfig = new Configuration.Configuration() { + StoreId = _storeId, + ApiHost = _host, + Credentials = new Credentials() { + Method = CredentialsMethod.ApiToken, + } + }; + void ActionMissingApiToken() => + missingApiTokenConfig.IsValid(); + var exceptionMissingApiToken = + Assert.Throws(ActionMissingApiToken); + Assert.Equal("Required parameter ApiToken was not defined when calling Configuration.", + exceptionMissingApiToken.Message); + } + // /// // /// Test that the provided api token issuer is well-formed // /// [Fact] public void ValidApiTokenIssuerWellFormed() { - var config = new Configuration.Configuration() { StoreId = _storeId, ApiHost = "api.fga.example", ApiTokenIssuer = "https://tokenissuer.fga.example" }; + var config = new Configuration.Configuration() { + StoreId = _storeId, + ApiHost = _host, + Credentials = new Credentials() { + Method = CredentialsMethod.ClientCredentials, + Config = new CredentialsConfig() { + ClientId = "some-id", + ClientSecret = "some-secret", + ApiTokenIssuer = "https://tokenissuer.fga.example", + ApiAudience = "some-audience", + } + } + }; void ActionMalformedApiTokenIssuer() => config.IsValid(); var exception = Assert.Throws(ActionMalformedApiTokenIssuer); Assert.Equal("Configuration.ApiTokenIssuer does not form a valid URI (https://https://tokenissuer.fga.example)", exception.Message); @@ -113,9 +157,14 @@ public void ClientIdClientSecretRequired() { var missingClientIdConfig = new Configuration.Configuration() { StoreId = _storeId, ApiHost = _host, - ClientSecret = "some-secret", - ApiTokenIssuer = "tokenisssuer.fga.example", - ApiAudience = _host, + Credentials = new Credentials() { + Method = CredentialsMethod.ClientCredentials, + Config = new CredentialsConfig() { + ClientSecret = "some-secret", + ApiTokenIssuer = "tokenissuer.fga.example", + ApiAudience = "some-audience", + } + } }; void ActionMissingClientId() => missingClientIdConfig.IsValid(); @@ -127,9 +176,14 @@ void ActionMissingClientId() => var missingClientSecretConfig = new Configuration.Configuration() { StoreId = _storeId, ApiHost = _host, - ApiTokenIssuer = "tokenisssuer.fga.example", - ApiAudience = _host, - ClientId = "some-id" + Credentials = new Credentials() { + Method = CredentialsMethod.ClientCredentials, + Config = new CredentialsConfig() { + ClientId = "some-id", + ApiTokenIssuer = "tokenissuer.fga.example", + ApiAudience = "some-audience", + } + } }; void ActionMissingClientSecret() => missingClientSecretConfig.IsValid(); @@ -141,9 +195,14 @@ void ActionMissingClientSecret() => var missingApiTokenIssuerConfig = new Configuration.Configuration() { StoreId = _storeId, ApiHost = _host, - ApiAudience = _host, - ClientId = "some-id", - ClientSecret = "some-secret" + Credentials = new Credentials() { + Method = CredentialsMethod.ClientCredentials, + Config = new CredentialsConfig() { + ClientId = "some-id", + ClientSecret = "some-secret", + ApiAudience = "some-audience", + } + } }; void ActionMissingApiTokenIssuer() => missingApiTokenIssuerConfig.IsValid(); @@ -155,10 +214,16 @@ void ActionMissingApiTokenIssuer() => var missingApiAudienceConfig = new Configuration.Configuration() { StoreId = _storeId, ApiHost = _host, - ApiTokenIssuer = "tokenisssuer.fga.example", - ClientId = "some-id", - ClientSecret = "some-secret" + Credentials = new Credentials() { + Method = CredentialsMethod.ClientCredentials, + Config = new CredentialsConfig() { + ClientId = "some-id", + ClientSecret = "some-secret", + ApiTokenIssuer = "tokenissuer.fga.example", + } + } }; + void ActionMissingApiAudience() => missingApiAudienceConfig.IsValid(); var exceptionMissingApiAudience = @@ -175,10 +240,15 @@ public async Task ExchangeCredentialsTest() { var config = new Configuration.Configuration() { StoreId = _storeId, ApiHost = _host, - ApiTokenIssuer = "tokenisssuer.fga.example", - ApiAudience = _host, - ClientId = "some-id", - ClientSecret = "some-secret" + Credentials = new Credentials() { + Method = CredentialsMethod.ClientCredentials, + Config = new CredentialsConfig() { + ClientId = "some-id", + ClientSecret = "some-secret", + ApiTokenIssuer = "tokenissuer.fga.example", + ApiAudience = "some-audience", + } + } }; var mockHandler = new Mock(MockBehavior.Strict); @@ -186,7 +256,7 @@ public async Task ExchangeCredentialsTest() { .Setup>( "SendAsync", ItExpr.Is(req => - req.RequestUri == new Uri($"https://{config.ApiTokenIssuer}/oauth/token") && + req.RequestUri == new Uri($"https://{config.Credentials.Config.ApiTokenIssuer}/oauth/token") && req.Method == HttpMethod.Post), ItExpr.IsAny() ) @@ -223,7 +293,7 @@ public async Task ExchangeCredentialsTest() { "SendAsync", Times.Exactly(1), ItExpr.Is(req => - req.RequestUri == new Uri($"https://{config.ApiTokenIssuer}/oauth/token") && + req.RequestUri == new Uri($"https://{config.Credentials.Config.ApiTokenIssuer}/oauth/token") && req.Method == HttpMethod.Post), ItExpr.IsAny() ); @@ -245,6 +315,19 @@ public async Task ExchangeCredentialsTest() { ); } + /// + /// Test that updating StoreId after initialization works + /// + [Fact] + public void UpdateStoreIdTest() { + var config = new Configuration.Configuration() { ApiHost = _host }; + var openFgaApi = new OpenFgaApi(config); + Assert.Equal(null, openFgaApi.StoreId); + var storeId = "some-id"; + openFgaApi.StoreId = storeId; + Assert.Equal(storeId, openFgaApi.StoreId); + } + /** * Errors */ @@ -810,8 +893,6 @@ public async Task ExpandComplexResponseTest() { }))), })) )); - var jsonResponse = JsonSerializer.Serialize(mockResponse); - //Console.Write(jsonResponse); mockHandler.Protected() .Setup>( @@ -823,7 +904,7 @@ public async Task ExpandComplexResponseTest() { ) .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, - Content = new StringContent(jsonResponse, Encoding.UTF8, "application/json"), + Content = Utils.CreateJsonStringContent(mockResponse), }); var httpClient = new HttpClient(mockHandler.Object); diff --git a/src/OpenFga.Sdk.Test/Models/ModelTests.cs b/src/OpenFga.Sdk.Test/Models/ModelTests.cs new file mode 100644 index 0000000..b037091 --- /dev/null +++ b/src/OpenFga.Sdk.Test/Models/ModelTests.cs @@ -0,0 +1,113 @@ +// +// OpenFGA/.NET SDK for OpenFGA +// +// API version: 0.1 +// Website: https://openfga.dev +// Documentation: https://openfga.dev/docs +// Support: https://discord.gg/8naAwJfWN6 +// License: [Apache-2.0](https://github.com/openfga/dotnet-sdk/blob/main/LICENSE) +// +// NOTE: This file was auto generated. DO NOT EDIT. +// + +using OpenFga.Sdk.Model; +using System; +using System.Text.Json; +using Xunit; + +namespace OpenFga.Sdk.Test.Models { + public class OpenFgaModelTests : IDisposable { + + public void Dispose() { + // Cleanup when everything is done. + } + + /// + /// Deserialize ReadAuthorizationModelsResponse + /// + [Fact] + public void DeserializeReadAuthorizationModelsResponse() { + var jsonResponse = + "{\"authorization_models\":[{\"id\":\"01FQHMTEX3ASF7TAGZZ828KSQ2\",\"type_definitions\":[{\"type\":\"group\",\"relations\":{\"member\":{\"this\":{}}}},{\"type\":\"folder\",\"relations\":{\"create_file\":{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},\"owner\":{\"this\":{}},\"parent\":{\"this\":{}},\"viewer\":{\"union\":{\"child\":[{\"this\":{}},{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},{\"tupleToUserset\":{\"tupleset\":{\"object\":\"\",\"relation\":\"parent\"},\"computedUserset\":{\"object\":\"\",\"relation\":\"viewer\"}}}]}}}},{\"type\":\"doc\",\"relations\":{\"change_owner\":{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},\"owner\":{\"this\":{}},\"parent\":{\"this\":{}},\"read\":{\"union\":{\"child\":[{\"computedUserset\":{\"object\":\"\",\"relation\":\"viewer\"}},{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},{\"tupleToUserset\":{\"tupleset\":{\"object\":\"\",\"relation\":\"parent\"},\"computedUserset\":{\"object\":\"\",\"relation\":\"viewer\"}}}]}},\"share\":{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},\"viewer\":{\"this\":{}},\"write\":{\"union\":{\"child\":[{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},{\"tupleToUserset\":{\"tupleset\":{\"object\":\"\",\"relation\":\"parent\"},\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}}}]}}}}]}],\"continuation_token\":\"\"}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize ReadAuthorizationModelResponse + /// + [Fact] + public void DeserializeReadAuthorizationModelResponse() { + var jsonResponse = + "{\"authorization_model\":{\"id\":\"01FQHMTEX3ASF7TAGZZ828KSQ2\",\"type_definitions\":[{\"type\":\"group\",\"relations\":{\"member\":{\"this\":{}}}},{\"type\":\"folder\",\"relations\":{\"create_file\":{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},\"owner\":{\"this\":{}},\"parent\":{\"this\":{}},\"viewer\":{\"union\":{\"child\":[{\"this\":{}},{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},{\"tupleToUserset\":{\"tupleset\":{\"object\":\"\",\"relation\":\"parent\"},\"computedUserset\":{\"object\":\"\",\"relation\":\"viewer\"}}}]}}}},{\"type\":\"doc\",\"relations\":{\"change_owner\":{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},\"owner\":{\"this\":{}},\"parent\":{\"this\":{}},\"read\":{\"union\":{\"child\":[{\"computedUserset\":{\"object\":\"\",\"relation\":\"viewer\"}},{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},{\"tupleToUserset\":{\"tupleset\":{\"object\":\"\",\"relation\":\"parent\"},\"computedUserset\":{\"object\":\"\",\"relation\":\"viewer\"}}}]}},\"share\":{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},\"viewer\":{\"this\":{}},\"write\":{\"union\":{\"child\":[{\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}},{\"tupleToUserset\":{\"tupleset\":{\"object\":\"\",\"relation\":\"parent\"},\"computedUserset\":{\"object\":\"\",\"relation\":\"owner\"}}}]}}}}]}}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize WriteAuthorizationModelResponse + /// + [Fact] + public void DeserializeWriteAuthorizationModelResponse() { + var jsonResponse = + "{\"authorization_model_id\":\"01G56QKZCF23KQ1WPQPAK3WXKB\"}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize ReadResponse + /// + [Fact] + public void DeserializeReadResponse() { + var jsonResponse = + "{\"tuples\":[{\"tuple_key\":{\"object\":\"document:planning\",\"relation\":\"viewer\",\"user\":\"user:jane\"},\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"}]}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize ReadChangesResponse + /// + [Fact(Skip = "Known issue deserializing TUPLE_OPERATION_WRITE")] + public void DeserializeReadChangesResponse() { + var jsonResponse = + "{\"changes\":[{\"tuple_key\":{\"object\":\"document:planning\",\"relation\":\"viewer\",\"user\":\"user:jane\"},\"operation\":\"TUPLE_OPERATION_WRITE\",\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"},{\"tuple_key\":{\"object\":\"document:roadmap\",\"relation\":\"owner\",\"user\":\"user:anna\"},\"operation\":\"TUPLE_OPERATION_DELETE\",\"timestamp\":\"2022-01-01T00:00:00.000000000Z\"}],\"continuation_token\":\"abcxyz==\"}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize CheckResponse + /// + [Fact] + public void DeserializeCheckResponse() { + var jsonResponse = + "{\"allowed\":true,\"resolution\":\"\"}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize ReadAssertionsResponse + /// + [Fact] + public void DeserializeReadAssertionsResponse() { + var jsonResponse = + "{\"authorization_model_id\":\"01FQHMTEX3ASF7TAGZZ828KSQ2\",\"assertions\":[{\"tuple_key\":{\"object\":\"document:roadmap\",\"relation\":\"viewer\",\"user\":\"carlos\"},\"expectation\":true}]}"; + + JsonSerializer.Deserialize(jsonResponse); + } + + /// + /// Deserialize ExpandResponse + /// + [Fact] + public void DeserializeExpandResponse() { + var jsonResponse = + "{\"tree\":{\"root\":{\"name\":\"document:roadmap#owner\", \"union\":{\"nodes\":[{\"name\":\"document:roadmap#owner\", \"leaf\":{\"users\":{\"users\":[\"team:product#member\"]}}}, {\"name\":\"document:roadmap#owner\", \"leaf\":{\"tupleToUserset\":{\"tupleset\":\"document:roadmap#owner\", \"computed\":[{\"userset\":\"org:contoso#admin\"}]}}}]}}}}"; + + JsonSerializer.Deserialize(jsonResponse); + } + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Api/OpenFgaApi.cs b/src/OpenFga.Sdk/Api/OpenFgaApi.cs index f68b107..7c0b64f 100644 --- a/src/OpenFga.Sdk/Api/OpenFgaApi.cs +++ b/src/OpenFga.Sdk/Api/OpenFgaApi.cs @@ -12,6 +12,7 @@ using OpenFga.Sdk.Client; +using OpenFga.Sdk.Exceptions; using OpenFga.Sdk.Model; namespace OpenFga.Sdk.Api; @@ -21,34 +22,11 @@ public class OpenFgaApi : IDisposable { private ApiClient _apiClient; /// - /// Initializes a new instance of the class. + /// Store ID /// - /// - /// define without the scheme (e.g. api.fga.example instead of https://api.fga.example) - /// - /// - /// - /// - /// - /// - public OpenFgaApi( - string storeId, - string apiHost, - string? apiTokenIssuer, - string? apiAudience, - string? clientId, - string? clientSecret, - IDictionary? defaultHeaders, - HttpClient? httpClient = null - ) : this(new Configuration.Configuration() { - StoreId = storeId, - ApiHost = apiHost, - ApiTokenIssuer = apiTokenIssuer, - ApiAudience = apiAudience, - ClientId = clientId, - ClientSecret = clientSecret, - DefaultHeaders = defaultHeaders ?? new Dictionary() - }, httpClient) { + public string? StoreId { + get => _configuration.StoreId; + set => _configuration.StoreId = value; } /// @@ -67,12 +45,17 @@ public OpenFgaApi( /// /// Check whether a user is authorized to access an object The Check API queries to check if the user has a certain relationship with an object in a certain store. Path parameter `store_id` as well as the body parameter `tuple_key` with specified `object`, `relation` and `user` subfields are all required. Optionally, a `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. The response will return whether the relationship exists in the field `allowed`. ## Example In order to check if user `anne` has a `can_read` relationship with object `document:2021-budget` given the following contextual tuple ```json { \"user\": \"anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ``` a check API call should be fired with the following body: ```json { \"tuple_key\": { \"user\": \"anne\", \"relation\": \"can_read\", \"object\": \"document:2021-budget\" }, \"contextual_tuples\": { \"tuple_keys\": [ { \"user\": \"anne\", \"relation\": \"member\", \"object\": \"time_slot:office_hours\" } ] } } ``` OpenFGA's response will include `{ \"allowed\": true }` if there is a relationship and `{ \"allowed\": false }` if there isn't. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of CheckResponse public async Task Check(CheckRequest body, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); @@ -92,12 +75,13 @@ public async Task Check(CheckRequest body, CancellationToken canc /// /// Create a store Create a unique OpenFGA store which will be used to store authorization models and relationship tuples. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of CreateStoreResponse public async Task CreateStore(CreateStoreRequest body, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + var queryParams = new Dictionary(); var requestBuilder = new RequestBuilder { @@ -116,11 +100,16 @@ public async Task CreateStore(CreateStoreRequest body, Canc /// /// Delete a store Delete an OpenFGA store. This does not delete the data associated to it, like tuples or authorization models. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// Cancellation Token to cancel the request. /// Task of void public async Task DeleteStore(CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); @@ -139,12 +128,17 @@ await this._apiClient.SendRequestAsync(requestBuilder, /// /// Expand all relationships in userset tree format, and following userset rewrite rules. Useful to reason about and debug a certain relationship The Expand API will return all users (including user and userset) that have certain relationship with an object in a certain store. This is different from the `/stores/{store_id}/read` API in that both users and computed references are returned. Path parameter `store_id` as well as body parameter `object`, `relation` are all required. The response will return a userset tree whose leaves are the user id and usersets. Union, intersection and difference operator are located in the intermediate nodes. ## Example Assume the following type definition for document: ```yaml type document relations define reader as self or writer define writer as self ``` In order to expand all users that have `reader` relationship with object `document:2021-budget`, an expand API call should be fired with the following body ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` OpenFGA's response will be a userset tree of the users and computed usersets that have read access to the document. ```json { \"tree\":{ \"root\":{ \"type\":\"document:2021-budget#reader\", \"union\":{ \"nodes\":[ { \"type\":\"document:2021-budget#reader\", \"leaf\":{ \"users\":{ \"users\":[ \"bob\" ] } } }, { \"type\":\"document:2021-budget#reader\", \"leaf\":{ \"computed\":{ \"userset\":\"document:2021-budget#writer\" } } } ] } } } } ``` The caller can then call expand API for the `writer` relationship for the `document:2021-budget`. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of ExpandResponse public async Task Expand(ExpandRequest body, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); @@ -164,11 +158,16 @@ public async Task Expand(ExpandRequest body, CancellationToken c /// /// Get a store Returns an OpenFGA store. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// Cancellation Token to cancel the request. /// Task of GetStoreResponse public async Task GetStore(CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); @@ -187,13 +186,14 @@ public async Task GetStore(CancellationToken cancellationToken /// /// Get all stores Returns a paginated list of OpenFGA stores. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// (optional) /// (optional) /// Cancellation Token to cancel the request. /// Task of ListStoresResponse public async Task ListStores(int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + var queryParams = new Dictionary(); if (pageSize != null) { queryParams.Add("page_size", pageSize.ToString()); @@ -217,12 +217,17 @@ public async Task GetStore(CancellationToken cancellationToken /// /// Get tuples from the store that matches a query, without following userset rewrite rules The POST read API will return the tuples for a certain store that matches a query filter specified in the body. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. It is different from the `/stores/{store_id}/expand` API in that only read returns relationship tuples that are stored in the system and satisfy the query. It does not expand or traverse the graph by taking the authorization model into account.Path parameter `store_id` is required. In the body: 1. Object is mandatory. An object can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 2. User is mandatory in the case the object is type only. ## Examples ### Query for all objects in a type definition To query for all objects that `bob` has `reader` relationship in the document type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and an optional continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ] } ``` This means that `bob` has a `reader` relationship with 1 document `document:2021-budget`. ### Query for all users with particular relationships for a particular document To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ] } ``` This means that `document:2021-budget` has 1 `reader` (`bob`). Note that the API will not return writers such as `anne` even when all writers are readers. This is because only direct relationship are returned for the READ API. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ] } ``` This means that `document:2021-budget` has 1 `reader` (`bob`) and 1 `writer` (`anne`). /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of ReadResponse public async Task Read(ReadRequest body, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); @@ -242,12 +247,17 @@ public async Task Read(ReadRequest body, CancellationToken cancell /// /// Read assertions for an authorization model ID The GET assertions API will return, for a given authorization model id, all the assertions stored for it. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of ReadAssertionsResponse public async Task ReadAssertions(string authorizationModelId, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + if (authorizationModelId != null) { pathParams.Add("authorization_model_id", authorizationModelId.ToString()); @@ -269,12 +279,17 @@ public async Task ReadAssertions(string authorizationMod /// /// Return a particular version of an authorization model The GET authorization-models by ID API will return a particular version of authorization model that had been configured for a certain store. Path parameter `store_id` and `id` are required. The response will return the authorization model for the particular version. ## Example To retrieve the authorization model with ID `01G5JAVJ41T49E9TT3SKVS7X1J` for the store, call the GET authorization-models by ID API with `01G5JAVJ41T49E9TT3SKVS7X1J` as the `id` path parameter. The API will return: ```json { \"authorization_model\":{ \"id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\", \"type_definitions\":[ { \"type\":\"document\", \"relations\":{ \"reader\":{ \"union\":{ \"child\":[ { \"this\":{} }, { \"computedUserset\":{ \"object\":\"\", \"relation\":\"writer\" } } ] } }, \"writer\":{ \"this\":{} } } } ] } } ``` In the above example, there is only 1 type (`document`) with 2 relations (`writer` and `reader`). /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of ReadAuthorizationModelResponse public async Task ReadAuthorizationModel(string id, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + if (id != null) { pathParams.Add("id", id.ToString()); @@ -296,13 +311,18 @@ public async Task ReadAuthorizationModel(string /// /// Return all the authorization models for a particular store The GET authorization-models API will return all the authorization models for a certain store. Path parameter `store_id` is required. OpenFGA's response will contain an array of all authorization models, sorted in descending order of creation. ## Example Assume that a store's authorization model has been configured twice. To get all the authorization models that have been created in this store, call GET authorization-models. The API will return a response that looks like: ```json { \"authorization_models\": [ { \"id\": \"01G50QVV17PECNVAHX1GG4Y5NC\", \"type_definitions\": [...] }, { \"id\": \"01G4ZW8F4A07AKQ8RHSVG9RW04\", \"type_definitions\": [...] }, ] } ``` If there are more authorization models available, the response will contain an extra field `continuation_token`: ```json { \"authorization_models\": [ { \"id\": \"01G50QVV17PECNVAHX1GG4Y5NC\", \"type_definitions\": [...] }, { \"id\": \"01G4ZW8F4A07AKQ8RHSVG9RW04\", \"type_definitions\": [...] }, ] \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// (optional) /// (optional) /// Cancellation Token to cancel the request. /// Task of ReadAuthorizationModelsResponse public async Task ReadAuthorizationModels(int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); if (pageSize != null) { @@ -327,14 +347,19 @@ public async Task ReadAuthorizationModel(string /// /// Return a list of all the tuple changes The GET changes API will return a paginated list of tuple changes (additions and deletions) that occurred in a given store, sorted by ascending time. The response will include a continuation token that is used to get the next set of changes. If there are no changes after the provided continuation token, the same token will be returned in order for it to be used when new changes are recorded. If the store never had any tuples added or removed, this token will be empty. You can use the `type` parameter to only get the list of tuple changes that affect objects of that type. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// (optional) /// (optional) /// (optional) /// Cancellation Token to cancel the request. /// Task of ReadChangesResponse public async Task ReadChanges(string? type = default(string?), int? pageSize = default(int?), string? continuationToken = default(string?), CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); if (type != null) { @@ -362,12 +387,17 @@ public async Task ReadAuthorizationModel(string /// /// Add or delete tuples from the store The POST write API will update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user. Path parameter `store_id` is required. In the body, `writes` adds new tuples while `deletes` removes existing tuples. ## Example ### Adding relationships To add `anne` as a `writer` for `document:2021-budget`, call write API with the following ```json { \"writes\": { \"tuple_keys\": [ { \"user\": \"anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" } ] } } ``` ### Removing relationships To remove `bob` as a `reader` for `document:2021-budget`, call write API with the following ```json { \"deletes\": { \"tuple_keys\": [ { \"user\": \"bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" } ] } } ``` /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of Object public async Task Write(WriteRequest body, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); @@ -387,13 +417,18 @@ public async Task Write(WriteRequest body, CancellationToken cancellatio /// /// Upsert assertions for an authorization model ID The Write Assertions API will add new assertions for an authorization model id, or overwrite the existing ones. An assertion is an object that contains a tuple key, and the expectation of whether a call to the Check API of that tuple key will return true or false. /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// /// Cancellation Token to cancel the request. /// Task of void public async Task WriteAssertions(string authorizationModelId, WriteAssertionsRequest body, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + if (authorizationModelId != null) { pathParams.Add("authorization_model_id", authorizationModelId.ToString()); @@ -416,12 +451,17 @@ await this._apiClient.SendRequestAsync(requestBuilder, /// /// Create a new authorization model The POST authorization-model API will update the authorization model for a certain store. Path parameter `store_id` and `type_definitions` array in the body are required. Each item in the `type_definitions` array is a type definition as specified in the field `type_definition`. The response will return the authorization model's ID in the `id` field. ## Example To update the authorization model with a single `document` authorization model, call POST authorization-models API with the body: ```json { \"type_definitions\":[ { \"type\":\"document\", \"relations\":{ \"reader\":{ \"union\":{ \"child\":[ { \"this\":{} }, { \"computedUserset\":{ \"object\":\"\", \"relation\":\"writer\" } } ] } }, \"writer\":{ \"this\":{} } } } ] } ``` OpenFGA's response will include the version id for this authorization model, which will look like ``` {\"authorization_model_id\": \"01G50QVV17PECNVAHX1GG4Y5NC\"} ``` /// - /// Thrown when fails to make API call + /// Thrown when fails to make API call /// /// Cancellation Token to cancel the request. /// Task of WriteAuthorizationModelResponse public async Task WriteAuthorizationModel(TypeDefinitions typeDefinitions, CancellationToken cancellationToken = default) { - var pathParams = new Dictionary { { "store_id", _configuration.StoreId } }; + var pathParams = new Dictionary { }; + if (string.IsNullOrWhiteSpace(_configuration.StoreId)) { + throw new FgaRequiredParamError("Configuration", nameof(_configuration.StoreId)); + } + pathParams.Add("store_id", _configuration.StoreId); + var queryParams = new Dictionary(); diff --git a/src/OpenFga.Sdk/Client/ApiClient.cs b/src/OpenFga.Sdk/Client/ApiClient.cs index 92f5cc1..39186ce 100644 --- a/src/OpenFga.Sdk/Client/ApiClient.cs +++ b/src/OpenFga.Sdk/Client/ApiClient.cs @@ -11,6 +11,7 @@ // +using OpenFga.Sdk.Configuration; using OpenFga.Sdk.Exceptions; namespace OpenFga.Sdk.Client; @@ -33,8 +34,20 @@ public ApiClient(Configuration.Configuration configuration, HttpClient? userHttp _configuration = configuration; _baseClient = new BaseClient(configuration, userHttpClient); - if (!string.IsNullOrEmpty(_configuration.ClientId)) { - _oauth2Client = new OAuth2Client(configuration, _baseClient); + if (configuration.Credentials == null) { + return; + } + + switch (configuration.Credentials.Method) { + case CredentialsMethod.ApiToken: + configuration.DefaultHeaders.Add("Authorization", $"Bearer {configuration.Credentials.Config!.ApiToken}"); + break; + case CredentialsMethod.ClientCredentials: + _oauth2Client = new OAuth2Client(configuration.Credentials, _baseClient); + break; + case CredentialsMethod.None: + default: + break; } } diff --git a/src/OpenFga.Sdk/Client/OAuth2Client.cs b/src/OpenFga.Sdk/Client/OAuth2Client.cs index 8f02616..ab2f806 100644 --- a/src/OpenFga.Sdk/Client/OAuth2Client.cs +++ b/src/OpenFga.Sdk/Client/OAuth2Client.cs @@ -11,6 +11,7 @@ // +using OpenFga.Sdk.Configuration; using OpenFga.Sdk.Exceptions; using System.Text.Json.Serialization; @@ -87,24 +88,24 @@ public bool IsValid() { /// /// Initializes a new instance of the class /// - /// + /// /// /// - public OAuth2Client(Configuration.Configuration config, BaseClient httpClient) { - if (string.IsNullOrWhiteSpace(config.ClientId)) { + public OAuth2Client(Credentials credentialsConfig, BaseClient httpClient) { + if (string.IsNullOrWhiteSpace(credentialsConfig.Config!.ClientId)) { throw new FgaRequiredParamError("OAuth2Client", "config.ClientId"); } - if (string.IsNullOrWhiteSpace(config.ClientSecret)) { + if (string.IsNullOrWhiteSpace(credentialsConfig.Config.ClientSecret)) { throw new FgaRequiredParamError("OAuth2Client", "config.ClientSecret"); } this._httpClient = httpClient; - this._apiTokenIssuer = config.ApiTokenIssuer; + this._apiTokenIssuer = credentialsConfig.Config.ApiTokenIssuer; this._authRequest = new AuthRequestBody() { - ClientId = config.ClientId, - ClientSecret = config.ClientSecret, - Audience = config.ApiAudience, + ClientId = credentialsConfig.Config.ClientId, + ClientSecret = credentialsConfig.Config.ClientSecret, + Audience = credentialsConfig.Config.ApiAudience, GrantType = "client_credentials" }; } diff --git a/src/OpenFga.Sdk/Configuration/Configuration.cs b/src/OpenFga.Sdk/Configuration/Configuration.cs index de4982e..95030fc 100644 --- a/src/OpenFga.Sdk/Configuration/Configuration.cs +++ b/src/OpenFga.Sdk/Configuration/Configuration.cs @@ -32,10 +32,6 @@ private static bool IsWellFormedUriString(string uri) { /// /// public void IsValid() { - if (string.IsNullOrWhiteSpace(StoreId)) { - throw new FgaRequiredParamError("Configuration", nameof(StoreId)); - } - if (string.IsNullOrWhiteSpace(ApiScheme)) { throw new FgaRequiredParamError("Configuration", nameof(ApiScheme)); } @@ -49,32 +45,11 @@ public void IsValid() { $"Configuration.ApiScheme ({ApiScheme}) and Configuration.ApiHost ({ApiHost}) do not form a valid URI ({BasePath})"); } - if (!string.IsNullOrWhiteSpace(ClientId) || !string.IsNullOrWhiteSpace(ClientSecret)) { - if (string.IsNullOrWhiteSpace(ClientId)) { - throw new FgaRequiredParamError("Configuration", nameof(ClientId)); - } - - if (string.IsNullOrWhiteSpace(ClientSecret)) { - throw new FgaRequiredParamError("Configuration", nameof(ClientSecret)); - } - - if (string.IsNullOrWhiteSpace(ApiTokenIssuer)) { - throw new FgaRequiredParamError("Configuration", nameof(ApiTokenIssuer)); - } - - if (string.IsNullOrWhiteSpace(ApiAudience)) { - throw new FgaRequiredParamError("Configuration", nameof(ApiAudience)); - } - } - - if (!string.IsNullOrWhiteSpace(ApiTokenIssuer) && !IsWellFormedUriString($"https://{ApiTokenIssuer}")) { - throw new FgaValidationError( - $"Configuration.ApiTokenIssuer does not form a valid URI (https://{ApiTokenIssuer})"); - } - if (MaxRetry > 5) { throw new FgaValidationError("Configuration.MaxRetry exceeds maximum allowed limit of 5"); } + + Credentials?.IsValid(); } #endregion @@ -104,7 +79,7 @@ public Configuration(string storeId) : this() { /// /// public Configuration() { - UserAgent = "openfga-sdk {sdkId}/{packageVersion}".Replace("{sdkId}", "dotnet").Replace("{packageVersion}", "0.0.1"); + UserAgent = "openfga-sdk {sdkId}/{packageVersion}".Replace("{sdkId}", "dotnet").Replace("{packageVersion}", Version); DefaultHeaders ??= new Dictionary(); if (!DefaultHeaders.ContainsKey("User-Agent")) { @@ -150,31 +125,13 @@ public Configuration() { /// Gets or sets the Store ID. /// /// Store ID. - public string StoreId { get; set; } - - /// - /// Gets or sets the Client ID. - /// - /// Client ID. - public string? ClientId { get; set; } - - /// - /// Gets or sets the Client Secret. - /// - /// Client Secret. - public string? ClientSecret { get; set; } - - /// - /// Gets or sets the API Token Issuer. - /// - /// API Token Issuer. - public string ApiTokenIssuer { get; set; } = null!; + public string? StoreId { get; set; } /// - /// Gets or sets the API Audience. + /// Gets or sets the Credentials /// - /// API Audience. - public string ApiAudience { get; set; } = null!; + /// Credentials. + public Credentials? Credentials { get; set; } /// /// Max number of times to retry after a request is rate limited diff --git a/src/OpenFga.Sdk/Configuration/Credentials.cs b/src/OpenFga.Sdk/Configuration/Credentials.cs new file mode 100644 index 0000000..51d2903 --- /dev/null +++ b/src/OpenFga.Sdk/Configuration/Credentials.cs @@ -0,0 +1,152 @@ +using OpenFga.Sdk.Exceptions; +using System.Runtime.Serialization; + +namespace OpenFga.Sdk.Configuration; + +/// +/// Available credential methods +/// +public enum CredentialsMethod { + /// + /// None - no auth required + /// + [EnumMember(Value = "none")] None, + + /// + /// API Bearer Token header required + /// + [EnumMember(Value = "api_token")] ApiToken, + + /// + /// Client ID, Secret, API Token Issuer & Audience for client credential flow required + /// + [EnumMember(Value = "client_credentials")] ClientCredentials, +} + +/// +/// +/// +public interface IApiTokenConfig { + public string? ApiToken { get; set; } +} + +/// +/// +/// +public interface IClientCredentialsConfig { + + /// + /// Gets or sets the Client ID. + /// + /// Client ID. + public string? ClientId { get; set; } + + /// + /// Gets or sets the Client Secret. + /// + /// Client Secret. + public string? ClientSecret { get; set; } + + /// + /// Gets or sets the API Token Issuer. + /// + /// API Token Issuer. + public string? ApiTokenIssuer { get; set; } + + /// + /// Gets or sets the API Audience. + /// + /// API Audience. + public string? ApiAudience { get; set; } +} + +public interface ICredentialsConfig : IClientCredentialsConfig, IApiTokenConfig { } + +public struct CredentialsConfig : ICredentialsConfig { + public string? ClientId { get; set; } + public string? ClientSecret { get; set; } + public string? ApiTokenIssuer { get; set; } + public string? ApiAudience { get; set; } + public string? ApiToken { get; set; } +} + +public interface IAuthCredentialsConfig { + public CredentialsMethod Method { get; } + public ICredentialsConfig? Config { get; } +} + +/// +/// +/// +public class Credentials : IAuthCredentialsConfig { + /// + /// credential methods + /// + public CredentialsMethod Method { get; set; } = CredentialsMethod.None; + + /// + /// Credential config options + /// + public ICredentialsConfig? Config { get; set; } + + private static bool IsWellFormedUriString(string uri) { + return Uri.TryCreate(uri, UriKind.Absolute, out var uriResult) && + ((uriResult.ToString().Equals(uri) || uriResult.ToString().Equals($"{uri}/")) && + (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps)); + } + + /// + /// Checks if the credentials configuration is valid + /// + /// + public void IsValid() { + switch (Method) { + case CredentialsMethod.ApiToken: + if (string.IsNullOrWhiteSpace(Config?.ApiToken)) { + throw new FgaRequiredParamError("Configuration", nameof(Config.ApiToken)); + } + break; + case CredentialsMethod.ClientCredentials: + if (string.IsNullOrWhiteSpace(Config?.ClientId)) { + throw new FgaRequiredParamError("Configuration", nameof(Config.ClientId)); + } + + if (string.IsNullOrWhiteSpace(Config?.ClientSecret)) { + throw new FgaRequiredParamError("Configuration", nameof(Config.ClientSecret)); + } + + if (string.IsNullOrWhiteSpace(Config?.ApiTokenIssuer)) { + throw new FgaRequiredParamError("Configuration", nameof(Config.ApiTokenIssuer)); + } + + if (string.IsNullOrWhiteSpace(Config?.ApiAudience)) { + throw new FgaRequiredParamError("Configuration", nameof(Config.ApiAudience)); + } + + if (!string.IsNullOrWhiteSpace(Config?.ApiTokenIssuer) && !IsWellFormedUriString($"https://{Config.ApiTokenIssuer}")) { + throw new FgaValidationError( + $"Configuration.ApiTokenIssuer does not form a valid URI (https://{Config.ApiTokenIssuer})"); + } + + break; + case CredentialsMethod.None: + default: + break; + } + } + + /// + /// Initializes a new instance of the class + /// + /// + public Credentials() { + this.IsValid(); + } + + static Credentials Init(IAuthCredentialsConfig config) { + return new Credentials() { + Method = config.Method, + Config = config.Config, + }; + } +} \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Any.cs b/src/OpenFga.Sdk/Model/Any.cs index 7f9bcfa..ba1ce7f 100644 --- a/src/OpenFga.Sdk/Model/Any.cs +++ b/src/OpenFga.Sdk/Model/Any.cs @@ -22,6 +22,12 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Any")] public partial class Any : Dictionary, IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Any() { } + /// /// Initializes a new instance of the class. /// @@ -103,6 +109,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Assertion.cs b/src/OpenFga.Sdk/Model/Assertion.cs index 298cb3d..96c3bf1 100644 --- a/src/OpenFga.Sdk/Model/Assertion.cs +++ b/src/OpenFga.Sdk/Model/Assertion.cs @@ -26,9 +26,10 @@ public partial class Assertion : IEquatable, IValidatableObject { /// Initializes a new instance of the class. /// [JsonConstructor] - protected Assertion() { + public Assertion() { this.AdditionalProperties = new Dictionary(); } + /// /// Initializes a new instance of the class. /// @@ -135,6 +136,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/AuthorizationModel.cs b/src/OpenFga.Sdk/Model/AuthorizationModel.cs index 4213af6..0d0a97a 100644 --- a/src/OpenFga.Sdk/Model/AuthorizationModel.cs +++ b/src/OpenFga.Sdk/Model/AuthorizationModel.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "AuthorizationModel")] public partial class AuthorizationModel : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public AuthorizationModel() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/CheckRequest.cs b/src/OpenFga.Sdk/Model/CheckRequest.cs index e2fae26..4c3d0ac 100644 --- a/src/OpenFga.Sdk/Model/CheckRequest.cs +++ b/src/OpenFga.Sdk/Model/CheckRequest.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Check_request")] public partial class CheckRequest : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public CheckRequest() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -168,6 +176,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/CheckResponse.cs b/src/OpenFga.Sdk/Model/CheckResponse.cs index 8ef444b..6f1d30e 100644 --- a/src/OpenFga.Sdk/Model/CheckResponse.cs +++ b/src/OpenFga.Sdk/Model/CheckResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "CheckResponse")] public partial class CheckResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public CheckResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -129,6 +137,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Computed.cs b/src/OpenFga.Sdk/Model/Computed.cs index a460e1e..f308896 100644 --- a/src/OpenFga.Sdk/Model/Computed.cs +++ b/src/OpenFga.Sdk/Model/Computed.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Computed")] public partial class Computed : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Computed() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -114,6 +122,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs b/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs index da08b90..596971a 100644 --- a/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs +++ b/src/OpenFga.Sdk/Model/ContextualTupleKeys.cs @@ -26,9 +26,10 @@ public partial class ContextualTupleKeys : IEquatable, IVal /// Initializes a new instance of the class. /// [JsonConstructor] - protected ContextualTupleKeys() { + public ContextualTupleKeys() { this.AdditionalProperties = new Dictionary(); } + /// /// Initializes a new instance of the class. /// @@ -126,6 +127,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/CreateStoreRequest.cs b/src/OpenFga.Sdk/Model/CreateStoreRequest.cs index 91e172a..7b2a5a8 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreRequest.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreRequest.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "CreateStoreRequest")] public partial class CreateStoreRequest : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public CreateStoreRequest() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -114,6 +122,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs index 2fb3702..4b0091c 100644 --- a/src/OpenFga.Sdk/Model/CreateStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/CreateStoreResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "CreateStoreResponse")] public partial class CreateStoreResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public CreateStoreResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -165,6 +173,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Difference.cs b/src/OpenFga.Sdk/Model/Difference.cs index f2cbff2..761b512 100644 --- a/src/OpenFga.Sdk/Model/Difference.cs +++ b/src/OpenFga.Sdk/Model/Difference.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Difference")] public partial class Difference : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Difference() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -131,6 +139,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ExpandRequest.cs b/src/OpenFga.Sdk/Model/ExpandRequest.cs index 8a69500..31403dd 100644 --- a/src/OpenFga.Sdk/Model/ExpandRequest.cs +++ b/src/OpenFga.Sdk/Model/ExpandRequest.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Expand_request")] public partial class ExpandRequest : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ExpandRequest() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -131,6 +139,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ExpandResponse.cs b/src/OpenFga.Sdk/Model/ExpandResponse.cs index a0a264e..73017c7 100644 --- a/src/OpenFga.Sdk/Model/ExpandResponse.cs +++ b/src/OpenFga.Sdk/Model/ExpandResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ExpandResponse")] public partial class ExpandResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ExpandResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -114,6 +122,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/GetStoreResponse.cs b/src/OpenFga.Sdk/Model/GetStoreResponse.cs index 7bc03e7..e17614f 100644 --- a/src/OpenFga.Sdk/Model/GetStoreResponse.cs +++ b/src/OpenFga.Sdk/Model/GetStoreResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "GetStoreResponse")] public partial class GetStoreResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public GetStoreResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -165,6 +173,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs index 801f594..3954057 100644 --- a/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/InternalErrorMessageResponse.cs @@ -29,6 +29,14 @@ public partial class InternalErrorMessageResponse : IEquatable + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public InternalErrorMessageResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -128,6 +136,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Leaf.cs b/src/OpenFga.Sdk/Model/Leaf.cs index 2753bbd..425219c 100644 --- a/src/OpenFga.Sdk/Model/Leaf.cs +++ b/src/OpenFga.Sdk/Model/Leaf.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Leaf")] public partial class Leaf : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Leaf() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -148,6 +156,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ListStoresResponse.cs b/src/OpenFga.Sdk/Model/ListStoresResponse.cs index d1bab60..3ce88bf 100644 --- a/src/OpenFga.Sdk/Model/ListStoresResponse.cs +++ b/src/OpenFga.Sdk/Model/ListStoresResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ListStoresResponse")] public partial class ListStoresResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ListStoresResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Node.cs b/src/OpenFga.Sdk/Model/Node.cs index 41e8135..b77d509 100644 --- a/src/OpenFga.Sdk/Model/Node.cs +++ b/src/OpenFga.Sdk/Model/Node.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Node")] public partial class Node : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Node() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -182,6 +190,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Nodes.cs b/src/OpenFga.Sdk/Model/Nodes.cs index dab2d5e..c169aa1 100644 --- a/src/OpenFga.Sdk/Model/Nodes.cs +++ b/src/OpenFga.Sdk/Model/Nodes.cs @@ -25,17 +25,17 @@ public partial class Nodes : IEquatable, IValidatableObject { /// /// Initializes a new instance of the class. /// - /// nodes. - public Nodes(List? nodes = default(List)) { - this._Nodes = nodes; + [JsonConstructor] + public Nodes() { this.AdditionalProperties = new Dictionary(); } /// /// Initializes a new instance of the class. /// - [JsonConstructor] - public Nodes() { + /// nodes. + public Nodes(List? nodes = default(List)) { + this._Nodes = nodes; this.AdditionalProperties = new Dictionary(); } @@ -123,6 +123,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ObjectRelation.cs b/src/OpenFga.Sdk/Model/ObjectRelation.cs index c7f1f3d..8be8a4a 100644 --- a/src/OpenFga.Sdk/Model/ObjectRelation.cs +++ b/src/OpenFga.Sdk/Model/ObjectRelation.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ObjectRelation")] public partial class ObjectRelation : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ObjectRelation() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -131,6 +139,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs index 5cb210d..4131086 100644 --- a/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/PathUnknownErrorMessageResponse.cs @@ -29,6 +29,14 @@ public partial class PathUnknownErrorMessageResponse : IEquatable + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public PathUnknownErrorMessageResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -128,6 +136,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs index 34d5352..024e0c6 100644 --- a/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAssertionsResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ReadAssertionsResponse")] public partial class ReadAssertionsResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadAssertionsResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs index 8c8823a..c571f88 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ReadAuthorizationModelResponse")] public partial class ReadAuthorizationModelResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadAuthorizationModelResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -114,6 +122,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs index 060227f..58e772d 100644 --- a/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadAuthorizationModelsResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ReadAuthorizationModelsResponse")] public partial class ReadAuthorizationModelsResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadAuthorizationModelsResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs index 978140f..da30dc5 100644 --- a/src/OpenFga.Sdk/Model/ReadChangesResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadChangesResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ReadChangesResponse")] public partial class ReadChangesResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadChangesResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadRequest.cs b/src/OpenFga.Sdk/Model/ReadRequest.cs index 4de2516..e8e2031 100644 --- a/src/OpenFga.Sdk/Model/ReadRequest.cs +++ b/src/OpenFga.Sdk/Model/ReadRequest.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Read_request")] public partial class ReadRequest : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadRequest() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -162,6 +170,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ReadResponse.cs b/src/OpenFga.Sdk/Model/ReadResponse.cs index 02713d1..cde0707 100644 --- a/src/OpenFga.Sdk/Model/ReadResponse.cs +++ b/src/OpenFga.Sdk/Model/ReadResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "ReadResponse")] public partial class ReadResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ReadResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Status.cs b/src/OpenFga.Sdk/Model/Status.cs index a01f984..6fcf657 100644 --- a/src/OpenFga.Sdk/Model/Status.cs +++ b/src/OpenFga.Sdk/Model/Status.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Status")] public partial class Status : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Status() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -146,6 +154,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Store.cs b/src/OpenFga.Sdk/Model/Store.cs index 1c5d1e9..a103799 100644 --- a/src/OpenFga.Sdk/Model/Store.cs +++ b/src/OpenFga.Sdk/Model/Store.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Store")] public partial class Store : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Store() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -182,6 +190,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Tuple.cs b/src/OpenFga.Sdk/Model/Tuple.cs index 66724dc..83c8851 100644 --- a/src/OpenFga.Sdk/Model/Tuple.cs +++ b/src/OpenFga.Sdk/Model/Tuple.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Tuple")] public partial class Tuple : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Tuple() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -131,6 +139,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TupleChange.cs b/src/OpenFga.Sdk/Model/TupleChange.cs index 17b077c..0551991 100644 --- a/src/OpenFga.Sdk/Model/TupleChange.cs +++ b/src/OpenFga.Sdk/Model/TupleChange.cs @@ -29,6 +29,14 @@ public partial class TupleChange : IEquatable, IValidatableObject { [DataMember(Name = "operation", EmitDefaultValue = false)] [JsonPropertyName("operation")] public TupleOperation? Operation { get; set; } + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public TupleChange() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -145,6 +153,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TupleKey.cs b/src/OpenFga.Sdk/Model/TupleKey.cs index bc46173..750971a 100644 --- a/src/OpenFga.Sdk/Model/TupleKey.cs +++ b/src/OpenFga.Sdk/Model/TupleKey.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "TupleKey")] public partial class TupleKey : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public TupleKey() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -35,14 +43,6 @@ public partial class TupleKey : IEquatable, IValidatableObject { this.AdditionalProperties = new Dictionary(); } - /// - /// Initializes a new instance of the class. - /// - [JsonConstructor] - public TupleKey() { - this.AdditionalProperties = new Dictionary(); - } - /// /// Gets or Sets Object /// @@ -171,6 +171,7 @@ public IEnumerable Validate(ValidationContext validationContex yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TupleKeys.cs b/src/OpenFga.Sdk/Model/TupleKeys.cs index 11a0159..626a93e 100644 --- a/src/OpenFga.Sdk/Model/TupleKeys.cs +++ b/src/OpenFga.Sdk/Model/TupleKeys.cs @@ -26,9 +26,10 @@ public partial class TupleKeys : IEquatable, IValidatableObject { /// Initializes a new instance of the class. /// [JsonConstructor] - protected TupleKeys() { + public TupleKeys() { this.AdditionalProperties = new Dictionary(); } + /// /// Initializes a new instance of the class. /// @@ -126,6 +127,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TupleToUserset.cs b/src/OpenFga.Sdk/Model/TupleToUserset.cs index d214f4f..4ac7129 100644 --- a/src/OpenFga.Sdk/Model/TupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/TupleToUserset.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "TupleToUserset")] public partial class TupleToUserset : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public TupleToUserset() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -131,6 +139,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TypeDefinition.cs b/src/OpenFga.Sdk/Model/TypeDefinition.cs index bebbc62..c883358 100644 --- a/src/OpenFga.Sdk/Model/TypeDefinition.cs +++ b/src/OpenFga.Sdk/Model/TypeDefinition.cs @@ -26,9 +26,10 @@ public partial class TypeDefinition : IEquatable, IValidatableOb /// Initializes a new instance of the class. /// [JsonConstructor] - protected TypeDefinition() { + public TypeDefinition() { this.AdditionalProperties = new Dictionary(); } + /// /// Initializes a new instance of the class. /// @@ -147,6 +148,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/TypeDefinitions.cs b/src/OpenFga.Sdk/Model/TypeDefinitions.cs index 7852692..bf95ba9 100644 --- a/src/OpenFga.Sdk/Model/TypeDefinitions.cs +++ b/src/OpenFga.Sdk/Model/TypeDefinitions.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "TypeDefinitions")] public partial class TypeDefinitions : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public TypeDefinitions() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -115,6 +123,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Users.cs b/src/OpenFga.Sdk/Model/Users.cs index 528c4c6..91831f5 100644 --- a/src/OpenFga.Sdk/Model/Users.cs +++ b/src/OpenFga.Sdk/Model/Users.cs @@ -25,17 +25,17 @@ public partial class Users : IEquatable, IValidatableObject { /// /// Initializes a new instance of the class. /// - /// users. - public Users(List? users = default(List)) { - this._Users = users; + [JsonConstructor] + public Users() { this.AdditionalProperties = new Dictionary(); } /// /// Initializes a new instance of the class. /// - [JsonConstructor] - public Users() { + /// users. + public Users(List? users = default(List)) { + this._Users = users; this.AdditionalProperties = new Dictionary(); } @@ -123,6 +123,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Userset.cs b/src/OpenFga.Sdk/Model/Userset.cs index 270992a..298292c 100644 --- a/src/OpenFga.Sdk/Model/Userset.cs +++ b/src/OpenFga.Sdk/Model/Userset.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Userset")] public partial class Userset : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Userset() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -200,6 +208,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/UsersetTree.cs b/src/OpenFga.Sdk/Model/UsersetTree.cs index 9205e80..5c33c04 100644 --- a/src/OpenFga.Sdk/Model/UsersetTree.cs +++ b/src/OpenFga.Sdk/Model/UsersetTree.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "UsersetTree")] public partial class UsersetTree : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public UsersetTree() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -114,6 +122,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs index 1c9d911..525009c 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeDifference.cs @@ -25,19 +25,19 @@ public partial class UsersetTreeDifference : IEquatable, /// /// Initializes a new instance of the class. /// - /// _base. - /// subtract. - public UsersetTreeDifference(Node? _base = default(Node), Node? subtract = default(Node)) { - this.Base = _base; - this.Subtract = subtract; + [JsonConstructor] + public UsersetTreeDifference() { this.AdditionalProperties = new Dictionary(); } /// /// Initializes a new instance of the class. /// - [JsonConstructor] - public UsersetTreeDifference() { + /// _base. + /// subtract. + public UsersetTreeDifference(Node? _base = default(Node), Node? subtract = default(Node)) { + this.Base = _base; + this.Subtract = subtract; this.AdditionalProperties = new Dictionary(); } @@ -139,6 +139,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs index b3bda22..d16acc9 100644 --- a/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs +++ b/src/OpenFga.Sdk/Model/UsersetTreeTupleToUserset.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "UsersetTree.TupleToUserset")] public partial class UsersetTreeTupleToUserset : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public UsersetTreeTupleToUserset() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -132,6 +140,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/Usersets.cs b/src/OpenFga.Sdk/Model/Usersets.cs index b14ce70..143b30b 100644 --- a/src/OpenFga.Sdk/Model/Usersets.cs +++ b/src/OpenFga.Sdk/Model/Usersets.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Usersets")] public partial class Usersets : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public Usersets() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -115,6 +123,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs b/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs index 8dea169..01262f3 100644 --- a/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs +++ b/src/OpenFga.Sdk/Model/ValidationErrorMessageResponse.cs @@ -29,6 +29,14 @@ public partial class ValidationErrorMessageResponse : IEquatable + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public ValidationErrorMessageResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -128,6 +136,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs b/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs index ad23da2..d933878 100644 --- a/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteAssertionsRequest.cs @@ -26,9 +26,10 @@ public partial class WriteAssertionsRequest : IEquatable /// Initializes a new instance of the class. /// [JsonConstructor] - protected WriteAssertionsRequest() { + public WriteAssertionsRequest() { this.AdditionalProperties = new Dictionary(); } + /// /// Initializes a new instance of the class. /// @@ -126,6 +127,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs index e2d202b..1a25ba1 100644 --- a/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs +++ b/src/OpenFga.Sdk/Model/WriteAuthorizationModelResponse.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "WriteAuthorizationModelResponse")] public partial class WriteAuthorizationModelResponse : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public WriteAuthorizationModelResponse() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -114,6 +122,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file diff --git a/src/OpenFga.Sdk/Model/WriteRequest.cs b/src/OpenFga.Sdk/Model/WriteRequest.cs index 6b2cd6a..0edebec 100644 --- a/src/OpenFga.Sdk/Model/WriteRequest.cs +++ b/src/OpenFga.Sdk/Model/WriteRequest.cs @@ -22,6 +22,14 @@ namespace OpenFga.Sdk.Model { /// [DataContract(Name = "Write_request")] public partial class WriteRequest : IEquatable, IValidatableObject { + /// + /// Initializes a new instance of the class. + /// + [JsonConstructor] + public WriteRequest() { + this.AdditionalProperties = new Dictionary(); + } + /// /// Initializes a new instance of the class. /// @@ -148,6 +156,7 @@ public override int GetHashCode() { public IEnumerable Validate(ValidationContext validationContext) { yield break; } + } } \ No newline at end of file