# Module structure

> Understand the structure of a Cloud Code module project and how it exposes endpoints.

A Cloud Code module is a simple .NET project that exposes the endpoints a game client can call. Modules adopt a similar paradigm as .NET class libraries. For example, a standard C# class might look like the following:

```csharp
namespace ModulesExample;

public class Example
{
    private static string[] GetCheatCodes()
    {
        return new string[]
        {
            "LEAVEMEALONE",
            "ASPIRINE",
            "BIGBANG"
        };
    }

    public void ChangeHaircut(string haircutName)
    {

    }
}
```

Once compiled, any reference to the class `Example` can only use the `ChangeHaircut()` method.

```csharp
using ModulesExample;

class UsageExample
{
    public void GameLoop()
    {
        Example.ChangeHaircut("buzzcut");

        // Compile error "Cannot access private method 'GetCheatCodes()' here"
        var cheatCodes = Example.GetCheatCodes();
    }
}
```

This allows developers to choose the interface of their library through access modifiers. Cloud Code modules work in the same way, however they use the `[CloudCodeFunction("ChangeHaircut")]` attribute instead.

With Cloud Code modules, you can create self-contained server-authoritative libraries. This allows you to run your game logic on the server, and call it from the client, which detaches the game logic from the client and increases security. Modules provide code reuse and provide an interface you can use to manage your game logic.

## C# project

A Cloud Code module project is a class library C# project. The project can also be part of a solution. The simplest project structure can look like this:

```text
├─ Main.csproj
    └─ Dependencies
    └─ HelloWorld.cs
```

Or, if in a solution, it can look like this:

```text
Sample.sln
├─ Main.csproj
    └─ Dependencies
    └─ HelloWorld.cs
```

The solution can also contain multiple projects that reference each other. This allows you to easily add test projects, and enables code reuse. The example below shows a valid project structure:

```text
Sample.sln
├─ Main.csproj
    └─ Dependencies
    └─ HelloWorld.cs
├─ Tests.csproj
    └─ Dependencies
    └─ Tests.cs
├─ Other.csproj
    └─ Dependencies
    └─ Class1.cs
```

However, only the main project can contain Cloud Code functions.

Refer to [Write unit tests](./unit-testing.md) to learn more about how to write unit tests for your Cloud Code module.

Refer to [Cloud Code limits](../reference/limits) to check what storage restrictions apply.

### Main project

Although the solution can contain multiple C# projects, you can have only one main project per module. The main project contains all your module entry points (functions with `CloudCodeFunction` attributes).

> **Warning:**
>
> If you attribute any functions with the `CloudCodeFunction` attribute outside of the main project, the Cloud Code service doesn't recognize them as entry points.

The main project is also the project that you deploy to the Cloud Code service.
You don't deploy the projects and dependencies that aren't referenced in the main project to the Cloud Code service.

You need to match the name of the main project to the name of the archive that you deploy to the Cloud Code service.

> **Note:**
>
> You can make a solution that contains more than one main Cloud Code module project. In this case, each main project corresponds to a different module.

### Sample project

The simplest module project can have the following structure:

```text
Sample.sln
├─ Main.csproj
    └─ Dependencies
    └─ HelloWorld.cs
```

The sample below defines a Cloud Code module with a single function `Hello` that returns the string `Hello World!`:

```csharp
using Unity.Services.CloudCode.Core;

namespace Sample;

public class HelloWorld
{
    [CloudCodeFunction("Hello")]
    public string PrintHello()
    {
        return "Hello World!";
    }
}
```

## Cloud Code NuGet packages

As .NET projects, Cloud Code module projects also use NuGet to share packaged code.

To learn more about NuGet, refer to [Microsoft documentation](https://learn.microsoft.com/en-us/nuget/what-is-nuget).

Cloud Code offers two packages that you can include in your modules:

* `com.Unity.Services.CloudCode.Core`: this package contains the core functionality of Cloud Code, including the `CloudCodeFunction` attribute. All Cloud Code modules require this package.
* `com.Unity.Services.CloudCode.Apis`: this is an optional package that contains the Unity Gaming Services APIs that you can use to interact with the Cloud Code service. You can use this package to call out to other Cloud Code SDKs, such as Cloud Save.

For more information, see the documentation on how to install and use NuGet packages in your project with [Jetbrains Rider](https://www.jetbrains.com/help/rider/Using_NuGet.html) or [Visual Studio](https://learn.microsoft.com/en-us/nuget/install-nuget-client-tools).

> **Note:**
>
> You can also install any external NuGet packages that you want to use in your module project. For more information, refer to [Integrate with external services](./external-services-integration.md).

## Code structure

To avoid issues with code structure, follow these guidelines.

### CloudCodeFunction attribute

To mark a method as a Cloud Code function and make it a viable Cloud Code module endpoint, use the `CloudCodeFunction` attribute.
You can only use Cloud Code function attributes in the main class of your modules.

To invoke the function, you need to call the name of the attribute.

### Method signature

Use the structure below for the method signature of your module function.

```csharp
[CloudCodeFunction("FunctionName")]
public async Task<ReturnType> FunctionName(IGameApiClient gameApiClient, IExecutionContext ctx, string parameter1, string parameter2)
{
    ...
}
```

> **Warning:**
>
> `async void` patterns cause errors. Always return a `Task` or `Task<T>`. Refer to the official [Microsoft documentation](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming) for best practices in asynchronous programming.

> **Warning:**
>
> Cloud Code doesn't support static methods for Cloud Code functions.

### Use singleton pattern for modules

You can use singleton pattern to integrate with Cloud Code C# packages and external service calls. Singleton patterns improve performance and scalability in Cloud Code and ensure that you don't create multiple instances of the same object.

You can use [Dependency Injection](./initialize-modules/dependency-injection.md) to inject the `IGameApiClient` and `IPushClient` interfaces into your modules.

> **Warning:**
>
> Don't rely on shared state across module function invocations because when there are multiple workers, the API call isn't guaranteed to land on the same worker.

> **Important:**
>
> Cloud Code workers have a 512 MB memory limit. If a worker exceeds this limit, the worker process crashes and restarts, and any function call in progress on that worker fails. Unbounded growth of cached data in static variables or singleton dependencies is a common cause. Refer to [In-memory cache](./in-memory-cache.md) for guidance on caching data safely.

## Passing in parameters

You can pass in parameters to your module functions.

### Primitive and complex types

This includes any primitive types, such as `int`, `string`, `bool`, and `float`, as well as complex types, such as `List<T>`, `Dictionary<T>`, and `Dictionary<string, T>`.

For example, you can pass in a `string` and a `List<string>` to your module function:

```json
{
  "params": {
    "parameter1": "a",
    "parameter2": ["b", "c"]
  }
}
```

Define your module function with the same parameters:

```csharp
[CloudCodeFunction("SimpleParams")]
public async Task SimpleParams(IExecutionContext ctx, string parameter1, List<string> parameter2)
{
  return parameter1 + parameter2[0] + parameter2[1];
}
```

### Custom types

You can also pass in any custom types that you define in your module project.

For example, you can pass in a JSON object to your module object:

```json
{
  "params": {
    "player": {
      "name": "player",
      "health": 50,
      "stamina": 20,
      "inventory": {
        "count": 5,
        "weight": 20
      }
    }
  }
}
```

Define a `Player` and `Inventory` classes and a function in your module project:

```csharp
public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }
    public int Stamina { get; set; }

    public Inventory Inventory { get; set; }
}

public class Inventory
{
    public int Count { get; set; }
    public int Weight { get; set; }
}

[CloudCodeFunction("CustomParams")]
public async Task<string> CustomParams(IExecutionContext ctx, Player player)
{
    return $"{player.Name} has {player.Health} health and {player.Stamina} stamina and {player.Inventory.Count} items in their inventory with a total weight of {player.Inventory.Weight}";
}
```

## Available interfaces

Cloud Code modules can use `IGameApiClient`, `IAdminApiClient`, `IPushClient`, and `IExecutionContext` interfaces to expand the functionality of your modules.

The `ICloudCodeSetup` interface allows you to manage the dependencies of your modules. Learn more about it in the [Dependency Injection](./initialize-modules/dependency-injection.md) documentation.

### IGameApiClient interface

The `IGameApiClient` interface provides a way to access the Cloud Code C# Client SDKs. You can use [Dependency Injection](./initialize-modules/dependency-injection.md) to inject the `IGameApiClient` into your modules.

1. Define a class that implements the `ICloudCodeSetup` interface and register the `IGameApiClient` interface:
   ```csharp
    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.AddGameApiClient();
        }
    }
   ```
2. Pass in the `IGameApiClient` interface as a function parameter to your module functions.

> **Note:**
>
> In the `Unity.Services.CloudCode.Apis.Extensions` namespace, `config.AddGameApiClient()` is available from `com.unity.services.cloudcode.core` version 0.0.4 and `com.unity.services.cloudcode.apis` version 0.0.24.
>
> In earlier versions, do the following to register the client manually:
>
> ```csharp
> config.Dependencies.AddSingleton<IGameApiClient>(GameApiClient.Create());
> ```

### IAdminApiClient interface

The `IAdminApiClient` interface provides a way to access the Cloud Code C# Admin SDKs. You can use [Dependency Injection](./initialize-modules/dependency-injection.md) to inject the `IAdminApiClient` into your modules.

1. Define a class that implements the `ICloudCodeSetup` interface and register the `IAdminApiClient` interface as a singleton:
   ```csharp
    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.AddAdminApiClient();
        }
    }
   ```
2. Pass in the `IAdminApiClient` interface as a function parameter to your module functions.

> **Note:**
>
> In the `Unity.Services.CloudCode.Apis.Extensions` namespace, `config.AddAdminApiClient()` is available from `com.unity.services.cloudcode.apis` version 0.0.27.
>
> In earlier versions, do the following to register the client manually:
>
> ```csharp
> config.Dependencies.AddSingleton<IAdminApiClient>(AdminApiClient.Create());
> ```

> **Note:**
>
> The Admin APIs have lower rate limits than the Game APIs. Use the Admin APIs for administrative tasks only. Don't use them for player-scale operations.
> Use the Game APIs to achieve all functionality intended for player-scale operations. Refer to [Limits](../reference/limits).

### IPushClient interface

The `IPushClient` interface provides a way to send push notifications to players.

From `com.unity.services.cloudcode.core` version 0.0.4 and `com.unity.services.cloudcode.apis` version 0.0.24, Cloud Code injects `IPushClient` by default. Pass the `IPushClient` interface as a function parameter to your module functions. You don't need to register the `IPushClient` interface.

> **Note:**
>
> In earlier versions, do the following to register `IPushClient` in an `ICloudCodeSetup` implementation before you pass it as a function parameter:
>
> ```csharp
> config.Dependencies.AddSingleton<IPushClient>(PushClient.Create());
> ```

To learn more about how to send push messages from Cloud Code, refer to [Push messages](./push-messages.md).

### IExecutionContext##iexecution-context

To make calls to other UGS services within your module, you can use the `IExecutionContext` interface to get extra information about the current call.
You can use the values below to access the [service SDKs](./unity-services-integration.md) and see which player makes a request.

* `ProjectId`: The project ID to which the caller was authenticated.
* `PlayerId`: The player ID that executed the script. **Note**: the player ID isn't available when a service calls the script.
* `EnvironmentId`: The environment ID of the module.
* `EnvironmentName`: The environment name of the module.
* `AccessToken`: The JSON Web Token (JWT) credential the player used to authenticate to Cloud Code.
* `UserId`: The user ID of the service account. (Note: the user ID is not available when a service calls the script.)
* `Issuer`: The issuer or the service account token. (Note: the issuer is not available when a player calls the script.)
* `ServiceToken`: The Cloud Code service account JWT credential.
* `AnalyticsUserId`: The Analytics User ID of the player. (Note: the analytic user ID is not available when a service calls the script.)
* `UnityInstallationId`: The Unity device installation ID of the player. (Note: the Unity installation ID is not available when a service calls the script.)

You can use the execution context to acquire the player ID and authenticate with different Unity Gaming Services. You can obtain the execution context through both the constructor of your class, and through any method with the `CloudCodeFunction` attribute.

For example, you can use the execution context to call out to Cloud Save to retrieve player keys:

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Apis.Extensions;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudCode.Shared;

namespace Sample;

public class HelloWorld
{
    private static ILogger<HelloWorld> _logger;
    public HelloWorld(ILogger<HelloWorld> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("GetData")]
    public async Task<object> GetData(IExecutionContext context, IGameApiClient gameApiClient, string key)
    {
        try
        {
            var result = await gameApiClient.CloudSaveData.GetItemsAsync(context, context.AccessToken,
                context.ProjectId, context.PlayerId, new List<string> { key });
            return result.Data.Results.First().Value;
        }
        catch (ApiException ex)
        {
            _logger.LogError("Failed to get data from Cloud Save. Error: {Error}", ex.Message);
            throw new Exception($"Failed to get data for playerId {context.PlayerId}. Error: {ex.Message}");
        }
    }

    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.AddGameApiClient();
        }
    }


}
```

#### Token authentication

The `AccessToken` and `ServiceToken` are [JWT](https://jwt.io/)s and properties of the `IExecutionContext` interface.

You can use these tokens to authenticate calls to other Unity Gaming Services from Cloud Code.

| Token type     | Origin                                                                          | Data access                    | Usage                                                                                                                                                                |
| -------------- | ------------------------------------------------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accessToken`  | Generated by the [Authentication service](/authentication/use-anon-sign-in.md). | Only the authenticated player. | The `AccessToken` is the JWT you use to authenticate a Cloud Code call. You can pass the token on to other UGS services to access data for the authenticated player. |
| `serviceToken` | Generated by Cloud Code.                                                        | Cross-player data access.      | The `ServiceToken` is a the token you use to call out to other UGS services and interact with cross-player data                                                      |

Any [Access Control](./access-control.md) rules that you configure affect the `AccessToken`.

The sample below shows how you can use the `AccessToken` to access an authenticated player's data with Cloud Save:

```csharp
using System;
using System.Threading.Tasks;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Apis.Extensions;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudCode.Shared;
using Unity.Services.CloudSave.Model;

namespace TokenSample;

public class TokenSample
{
    [CloudCodeFunction("GetKeysForAuthenticatedPlayer")]
    public  Task<ApiResponse<GetKeysResponse>> GetPlayerKeys(IExecutionContext ctx, IGameApiClient gameApiClient)
    {
        try
        {
            // Using ctx.AccessToken to access the data for the player calling the function
            return gameApiClient.CloudSaveData.GetKeysAsync(ctx, ctx.AccessToken, ctx.ProjectId, ctx.PlayerId);
        }
        catch (ApiException e)
        {
            throw new Exception($"Failed to get keys for playerId {ctx.PlayerId}. Error: {e.Message}");

        }
    }

    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.AddGameApiClient();
        }
    }
}
```

To access data for all players, you can use a `ServiceToken` and pass in a parameter for the `playerId`:

```csharp
using System;
using System.Threading.Tasks;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Apis.Extensions;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudCode.Shared;
using Unity.Services.CloudSave.Model;

namespace TokenSample;

public class TokenSample
{
    [CloudCodeFunction("GetKeysForAnyPlayer")]
    public  Task<ApiResponse<GetKeysResponse>> GetPlayerKeys(IExecutionContext ctx, IGameApiClient gameApiClient, string playerId)
    {
        try
        {
            // Using ctx.ServiceToken to access the data for any player
            return gameApiClient.CloudSaveData.GetKeysAsync(ctx, ctx.ServiceToken, ctx.ProjectId, playerId);
        } catch (ApiException e)
        {
            throw new Exception($"Failed to get keys for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }

    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.AddGameApiClient();
        }
    }
}
```

For an in-depth explanation of the differences between the two tokens, refer to the [Service and access tokens](./token-support.md) documentation.

## Cloud Code module metadata

To retrieve a Cloud Code module and its metadata, you can send a `GET` request to the Cloud Code service. The response is a JSON object with the following structure:

```json
{
  "name": "string",
  "language": "CS",
  "tags": {
    "property1": "string",
    "property2": "string"
  },
  "signedDownloadURL": "string",
  "dateCreated": "2022-04-05T09:12:13Z",
  "dateModified": "2022-04-05T09:12:13Z"
}
```

### Tags

Tags are key-value pairs that you can attach to your Cloud Code modules. You can record any information you want in the tags, such as the version of the module, the author, or the commit hash if you use version control.

Modules can store up to 10 tags, and the maximum characters you can use per tag key and tag value is 128.

> **Note:**
>
> The custom tags are only supported when you use the [Cloud Code API](./run-modules/rest-api.md) to author. Cloud Code ignores the tags when you use the [Unity Gaming Services CLI](./write-modules/cli.md) and the [Unity Editor](./write-modules/unity-editor.md) to author.

### Signed Download URL

Signed Download URL is a temporary URL that you can use to download the module archive.
