# 스크립트 구조

> Understand the structure of a Cloud Code script and how the main function acts as the entry point.

런타임의 진입점 역할을 하는 Cloud Code 스크립트의 기본 함수는 CommonJS 래퍼의 형태를 띱니다.

다음 코드 스니핏은 가능한 가장 간단한 스크립트의 예시입니다.

*JavaScript*

```js
module.exports = async ({ params, context, logger }) => {
  // this script does nothing
};
```

이 스크립트는 실제로는 아무 작업도 수행하지 않지만, 컨텍스트 오브젝트와 더불어 스크립트 함수의 비동기적인 특성을 보여 줍니다.

> **Note:**
>
> **참고**: 스크립트는 CommonJS 함수를 익스포트하지 않으면 유효하지 않습니다.

> **Note:**
>
> **참고**: 스크립트 이름은 프로젝트와 환경 전체에서 고유해야 하며, 문자, 숫자, 밑줄, 대시만 사용하고 50자를 초과해서는 안 됩니다.

## 컨텍스트 오브젝트##context-object

컨텍스트 오브젝트에는 다음과 같은 유용한 오브젝트가 포함되어 있습니다.

* `Params`: 스크립트와 함께 호출되는 입력 파라미터의 이름-값 페어 배열입니다.

* `Context`: 이 오브젝트는 스크립트 내에서 다음과 같은 유용한 추가 컨텍스트를 제공합니다.

  * `projectId`: 호출자가 인증을 받은 프로젝트 ID입니다.
  * `playerId`: 인증된 플레이어 ID입니다.
  * `accessToken`: 인증된 플레이어로 다른 Unity 게임 서비스 SDK를 호출하는 데 사용할 수 있는 JWT입니다.
  * `environmentName`: 현재 사용 중인 Unity [환경](/services/service-environments.md)의 이름입니다.
  * `environmentId`: 현재 사용 중인 Unity 환경의 ID입니다.
  * `serviceToken`: 인증된 Cloud Code 사용자로 다른 Unity 게임 서비스 SDK를 호출하는 데 사용되는 JWT입니다.
  * `unityInstallationId`: 클라이언트 디바이스에서 설치를 식별하는 고유 ID입니다. 동일한 플레이어가 여러 디바이스에 게임을 설치한 경우, `installationId`가 서로 다를 수 있습니다. Services SDK Core 패키지와 연동되는 모든 Unity 패키지에서 사용할 수 있습니다.
  * `analyticsUserId`: 플레이어를 식별하는 고유 문자열로, 분석 목적으로 후속 플레이 세션 전반에서 일관되게 사용됩니다. 이 문자열은 기본 사용자 ID로 Core 패키지에서 제공됩니다.
  * `correlationId`: 요청의 상관 관계를 파악하는 데 사용되는 고유 ID입니다.

* `Logger`: 스크립트에서 정보, 경고, 오류를 기록하도록 허용하는 오브젝트입니다.

### JavaScript##javascript

```js
module.exports = async ({logger}) => {
  logger.info('This message confirms that the logging client is functional!');
  logger.warning('This is a serious warning that the cheese is about to run out.');
  logger.error('Out of cheese :(');
}
```

자세한 내용은 [로깅](../../logging/overview) 기술 자료를 참고하십시오.

### 토큰 인증##token-authentication

`accessToken`과 `serviceToken`은 `context` 오브젝트의 프로퍼티로 제공되는 [JWT](https://jwt.io/)입니다.

이 토큰은 Cloud Code에서 다른 Unity Gaming Services로의 호출을 인증합니다.

| 토큰 유형          | 출처                                            | 데이터 액세스             | 사용                                                                                          |
| -------------- | --------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------- |
| `accessToken`  | [Authentication 서비스](/authentication.md)에서 생성 | 인증된 플레이어로 제한        | `accessToken`은 Cloud Code 호출과 함께 인증되는 JWT로, 인증된 플레이어의 데이터에 액세스하기 위해 다른 UGS 서비스에 전달할 수 있습니다. |
| `serviceToken` | Cloud Code에서 생성                               | 크로스 플레이어 데이터 액세스 허용 | `serviceToken`은 Cloud Code에서 생성된 토큰으로, 다른 UGS 서비스를 호출하고 클로스 플레이어 데이터와 상호 작용하는 데 사용할 수 있습니다. |

구성된 모든 [액세스 제어](./access-control.md) 규칙은 `accessToken`에 영향을 줍니다.

아래는 `accessToken`을 사용하여 Economy SDK를 호출하고 플레이어의 인벤토리를 가져오는 방법의 예시입니다.

#### JavaScript##javascript

```js
// Player inventory
const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({params, context, logger}) => {
 const { projectId, playerId, accessToken } = context;
 const inventory = new InventoryApi({accessToken});
 const result = await inventory.getPlayerInventory({projectId, playerId});
 return result.data;
}
```

`serviceToken`을 사용하려는 경우, 위 스크립트를 아래와 같이 바꿔 줍니다.

#### JavaScript##javascript

```js
// Player inventory
const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({params, context, logger}) => {
const { projectId, playerId } = context;
const inventory = new InventoryApi(context);
const result = await inventory.getPlayerInventory({projectId, playerId});
return result.data;
}
```

두 토큰의 차이점에 대한 자세한 설명은 [서비스 및 액세스 토큰](./token-support.md)을 참고하십시오.

## 스크립트 파라미터##script-parameters

스크립트 파라미터는 스크립트 본문 외부 또는 내부에서 정의할 수 있습니다.

> **Note:**
>
> **참고**: 스크립트 내 파라미터는 파라미터를 선언하는 것보다 간단하지만, Deployment 패키지를 사용하지 않고 스크립트 내 파라미터를 업데이트하려고 하면 Unity Dashboard가 파라미터를 파싱하지 않습니다.

### 스크립트 내 파라미터##in-script-parameters

스크립트 내 파라미터는 각 파라미터의 이름을 키로, 파라미터의 유형을 값으로 포함하는 `params` 오브젝트를 익스포트해서 추가할 수 있습니다.

> **Important:**
>
> **중요**: 파라미터를 설정하기 전에 `module.exports` 프로퍼티를 할당해야 합니다.

예제는 아래와 같습니다.

#### JavaScript##javascript

```js
module.exports.params = { "echo" : "Boolean" }
```

또는 파라미터를 필수 파라미터로 지정하려는 경우, `type`과 `required` 프로퍼티가 모두 포함된 오브젝트를 지정하면 됩니다.

#### JavaScript##javascript

```js
module.exports = async ({ params, context, logger }) => {
    return {
        "value": params["aParam"]
    };
};

module.exports.params = { "aParam" : { "type": "String", "required": true } }
```

기본적으로 파라미터는 필수가 아닙니다.

두 포맷 모두 다음과 같이 원하는 대로 결합할 수 있습니다.

#### JavaScript##javascript

```js
module.exports = async ({ params, context, logger }) => {
    var value = params["echo"] ? params["aParam"] : "default";
    return {
        "value": value
    };
};

module.exports.params = {
  "echo" : "Boolean",
  "aParam" : { "type": "String", "required": true }
 }
```

## async/await##asyncawait

기본 스크립트 함수가 비동기 함수일 수 있습니다. 다시 말해서 함수가 프로미스(Promise)를 기다릴 수 있으며, 이를 통해 스크립트 내에서 다른 Unity 게임 서비스 SDK를 사용할 수 있습니다. [프로미스](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises)에 대한 설명은 Mozilla 기술 자료(영문)를 참고하십시오.

간단한 예시는 다음과 같습니다.

### JavaScript##javascript

```js
// Player inventory
const { InventoryApi } = require("@unity-services/economy-2.4");

module.exports = async ({params, context, logger}) => {
 const { projectId, playerId } = context;
 const inventory = new InventoryApi(context);
 const result = await inventory.getPlayerInventory({projectId, playerId});
 return result.data;
}
```

> **Note:**
>
> **참고**: Cloud Code 클라이언트 측 호출은 항상 비동기이며, 일반(동기) 스크립트와 비동기 스크립트가 모두 포함됩니다.

## 추가 패키지##additional-packages

스크립트는 `import` 또는 `require` 키워드로 로컬 스크립트나 외부 패키지를 임포트할 수 있습니다.

임포트할 수 있는 전체 패키지 목록은 [사용 가능한 패키지](../reference/available-libraries)를 참고하십시오.

### JavaScript##javascript

```js
const _ = require("lodash-4.17");

module.exports = async () => {
  return _.random(1, 6);
};
```

> **Note:**
>
> **참고**: 필수 패키지는 익스포트한 함수 외부에서 선언해야 합니다.

## 번들링##bundling

> **Note:**
>
> **참고**: 현재 Unity Dashboard와 CLI는 번들 스크립트를 완전히 지원하지 않습니다.

스크립트 번들링은 Unity 에디터 내에서 Deployment 패키지를 사용해서 활성화할 수 있는 기능으로, 이 기능을 사용하면 스크립트를 로컬에서 관리하고, 추가 워크플로를 활용하며, 여러 스크립트에서 공통의 기능을 공유할 수 있습니다. 번들 스크립트를 생성하는 방법을 자세히 알아보려면 [JS 번들](./write-scripts/unity-editor.md#js-bundles) 기술 자료를 참고하십시오.

### JavaScript##javascript

```js

const lib = require("./lib");

module.exports = async () => {
  return lib.helloWorld();
};

module.exports.bundled = true;
```

## 출력##output

스크립트 출력은 다음과 같은 유형으로 구성될 수 있습니다.

### JavaScript##javascript

* `string`
  ```js
  module.exports = async () => {
    return "hello world";
  };
  ```
* `boolean`
  ```js
  module.exports = async () => {
    return true;
  };
  ```
* `number`
  ```js
  module.exports = async () => {
    return 3.14;
  };
  ```
* `object`
  ```js
  module.exports = async () => {
    return {
      message: "hello world",
      success: true
    };
  };
  ```

성공적인 응답은 API에서 다음과 같은 구조의 JSON으로 반환됩니다.

```text
{
  "output": <SCRIPT OUTPUT>
}
```

### 오류 출력##error-output

서비스 요청이 실패하는 등 호출이 실패하는 원인이 발생하면 스크립트에서 오류가 발생할 수 있습니다.

스크립트 내에서 오류를 포착하면 실패를 처리하는 방식을 정할 수 있습니다.

#### JavaScript##javascript

```js
module.exports = async ({logger}) => {
  try {
    let result = service.call("example");
    return result;
  } catch (err) {
    logger.error("Something went wrong!", {"error.message": err.message});
    throw err;
  }
};
```

오류 응답은 API에서 JSON으로 반환되며, 이때 오류의 원인을 파악할 수 있도록 오류 유형, 오류 메시지, 스택 추적을 비롯한 오류 세부 정보를 함께 반환합니다.

```text
{
  "type": "problems/invocation",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Invocation Error",
  "instance": null,
  "code": 9009,
  "details": [
      {
          "name": "ReferenceError",
          "message": "service is not defined",
          "stackTrace": [
              "at module.exports (example-test.js:1:26)"
          ]
      }
  ]
}
```
