# 스크립트 API (/ko/docs/reference/scripting-api)

스크립트는 요청을 보내기 전(요청 전)이나 응답이 도착한 후(테스트)에 실행되는 JavaScript입니다. Postman의 `pm` API를 사용하므로 Postman
컬렉션의 스크립트가 그대로 실행됩니다. 이 페이지는 그 전체를 나열합니다. 앱에서 스크립트를 작성하고 결과를 읽는 방법은
[스크립트와 테스트](/docs/requests/scripts-and-tests)를 참고하세요.

## 스크립트가 실행되는 곳 [#where-scripts-run]

- 요청의 스크립트는 **스크립트** 탭에 있으며, 요청 옆에 `<slug>.pre.js`와 `<slug>.test.js`로 저장됩니다. 폴더와 작업 공간에도 스크립트가 있습니다
  (`_folder.pre.js`, `_folder.test.js`). [작업 공간 파일](/docs/reference/workspace-files#_foldertoml)을 참고하세요.
- 각 요청에 대해 작업 공간의 스크립트가 먼저 실행되고, 그다음 각 폴더의 스크립트가 바깥쪽에서 안쪽으로, 마지막으로 요청 자신의 스크립트가
  실행됩니다. 한 이벤트의 모든 스크립트는 하나의 샌드박스를 공유합니다.
- MCP 호출에는 스크립트가 없습니다.
- Echolot 외부(가져오기, Git, 다른 편집기)에서 온 스크립트는 신뢰할 때만 실행됩니다. <strong>스크립트 검토…</strong>로 읽은 다음 <strong>스크립트 신뢰</strong>를 선택하세요.
- 명령줄 도구도 [`echolot run`](/docs/cli/run)과 [`echolot send`](/docs/cli/send)에서 스크립트를 실행합니다.

## 샌드박스 [#the-sandbox]

스크립트는 Echolot 안의 샌드박스 JavaScript 엔진(QuickJS)에서 실행되며, 파일 시스템도, 자체 네트워크도, Node.js 모듈도 없습니다. 밖으로 나가는 유일한
방법은 Echolot을 통해 보내는 `pm.sendRequest`입니다.

| 제한 | 값 |
| --- | --- |
| 한 이벤트의 모든 스크립트가 사용할 수 있는 JavaScript 시간 | 5초 |
| 메모리 | 128 MB |
| 모든 `pm.sendRequest` 응답을 기다리는 시간 | 30초 |
| 스크립트가 볼 수 있는 응답 본문 | 처음 32 MB |

예외를 던지거나 제한을 넘은 스크립트는 스크립트 오류로 보고되며, 실패한 테스트로 집계됩니다.

## pm.test [#pmtest]

```js
pm.test("Status is 200", () => {
  pm.response.to.have.status(200);
});

pm.test("Has products", () => {
  const body = pm.response.json();
  pm.expect(body.items).to.be.an("array").that.is.not.empty;
});
```

| 형태 | 의미 |
| --- | --- |
| `pm.test(name, fn)` | 이름이 있는 테스트. `fn`이 예외 없이 반환하면 통과합니다. |
| `pm.test(name, async () => { … })` | 프라미스를 반환하는 테스트는 프라미스가 이행되면 통과합니다. |
| `pm.test(name, done => { … })` | 인수를 받는 테스트는 `done()`을 호출하면 통과하고, `done(error)`를 호출하거나 호출하지 않으면 실패합니다. |
| `pm.test.skip(name, fn)` | 건너뛴 테스트. 나열되지만 집계되지 않습니다. |
| `tests[name] = condition` | 예전 형태. 조건이 true이면 통과합니다. |

요청 전 스크립트의 테스트도 집계됩니다.

## pm.expect [#pmexpect]

`pm.expect(value)`(또는 `expect(value)`)는 Chai 스타일 단언입니다. 실패 메시지는 Chai와 같습니다. `expected 401 to equal 200`.

**체인 단어**는 읽기 좋게 해 줄 뿐 아무 일도 하지 않습니다. `to`, `be`, `been`, `is`, `that`, `which`, `and`, `has`, `have`, `with`, `at`, `of`,
`same`, `but`, `does`, `still`, `also`.

**플래그:** `not`(부정), `deep`(값으로 비교), `nested`(`property`에서 점으로 구분한 경로), `own`, `any`, `all`, `ordered`.

| 단언 | 통과하는 경우 |
| --- | --- |
| `.equal(x)`, `.equals`, `.eq` | 값이 `x`(`===`. `deep`이면 값으로 비교). |
| `.eql(x)`, `.eqls` | 값이 `x`와 깊이 같음. |
| `.above(n)`, `.gt`, `.greaterThan` | 값이 `n`보다 큼. |
| `.least(n)`, `.gte`, `.greaterThanOrEqual` | 값이 `n` 이상. |
| `.below(n)`, `.lt`, `.lessThan` | 값이 `n`보다 작음. |
| `.most(n)`, `.lte`, `.lessThanOrEqual` | 값이 `n` 이하. |
| `.within(a, b)` | 값이 `a`와 `b` 사이(양 끝 포함). |
| `.closeTo(x, delta)`, `.approximately` | 값이 `x`에서 `delta` 이내. |
| `.a(type)`, `.an(type)` | 값의 타입이 `type`: `string`, `number`, `boolean`, `object`, `array`, `null`, `undefined`, `regexp`, `date`, `error`, `function`. |
| `.instanceof(C)`, `.instanceOf` | 값이 `C`의 인스턴스. |
| `.include(x)`, `.includes`, `.contain`, `.contains` | 문자열이 `x`를 포함하거나, 배열에 `x`가 있거나, 객체가 `x`의 키와 값을 가짐. |
| `.ok` | 값이 참으로 평가됨. |
| `.true`, `.false`, `.null`, `.undefined`, `.NaN` | 값이 정확히 그것. |
| `.exist`, `.exists` | 값이 `null`도 `undefined`도 아님. |
| `.empty` | 문자열이나 배열에 항목이 없거나, 객체에 키가 없거나, Map이나 Set에 항목이 없음. |
| `.finite` | 값이 유한한 숫자. |
| `.property(name)`, `.property(name, value)` | 객체에 그 속성이 있음(값을 지정하면 그 값으로). 속성의 값으로 이어집니다. `.ownProperty`, `.haveOwnProperty`도 같습니다. |
| `.lengthOf(n)`, `.length(n)` | 값의 `length`(또는 Map이나 Set의 크기)가 `n`. |
| `.match(regex)`, `.matches` | 문자열이 정규 표현식과 일치. |
| `.string(s)` | 문자열이 `s`를 포함. |
| `.keys(…)`, `.key` | 객체가 정확히 이 키들을 가짐(`any`와 함께면 그중 하나, `include` 뒤에서는 최소한 이 키들). |
| `.members(array)` | 배열이 같은 구성원을 가짐(`include`와 함께면 최소한 이 구성원들, `ordered`와 함께면 이 순서로). |
| `.oneOf(array)` | 값이 배열의 항목 중 하나. |
| `.satisfy(fn)`, `.satisfies` | `fn(value)`가 true를 반환. |
| `.throw()`, `.throws`, `.Throw` | 함수가 예외를 던짐(지정하면 문자열을 포함하거나 정규 표현식과 일치하는 메시지로, 또는 해당 클래스로). |
| `.jsonSchema(schema)` | 값이 JSON 스키마와 일치. [JSON 스키마](#json-schema)를 참고하세요. |

응답에서는 `expect`가 Postman의 응답 단언도 받습니다. `pm.expect(pm.response).to.have.status(200)`, `.header(name)`, `.jsonBody(…)`, `.body(…)`,
`.responseTime(…)`, 그리고 `pm.expect(pm.response).to.be.ok`, `.success`, `.json`과 아래의 나머지입니다.

## pm.response [#pmresponse]

테스트 스크립트에서의 응답입니다.

| 멤버 | 의미 |
| --- | --- |
| `code` | 상태 코드: `200`. |
| `status` | 사유 문구: `"OK"`. `reason()`도 같습니다. |
| `headers` | [목록](#lists)으로서의 헤더. `pm.response.headers.get("Content-Type")`. |
| `responseTime` | 밀리초 단위 시간. |
| `responseSize` | 본문의 크기(바이트). `{ body, header, total }`을 반환하는 `size()`도 있습니다. |
| `text()` | 텍스트로서의 본문. |
| `json(reviver)` | JSON으로 파싱한 본문. JSON이 아니면 예외를 던집니다. |

**응답 단언:** `pm.response.to.have.…`와 `pm.response.to.not.have.…`

| 단언 | 통과하는 경우 |
| --- | --- |
| `status(200)`, `status("OK")` | 코드가 200이거나 사유가 OK. `statusCode(n)`, `statusReason(text)`도 있습니다. |
| `header(name)`, `header(name, value)` | 헤더가 있음(값을 지정하면 그 값으로). |
| `body()`, `body(text)`, `body(regex)`, `body(object)` | 본문이 비어 있지 않거나, 그 텍스트이거나, 일치하거나, 그 JSON임. |
| `jsonBody()`, `jsonBody(path)`, `jsonBody(path, value)`, `jsonBody(object)` | 본문이 JSON이거나, 점으로 구분한 경로가 있거나, 그 값이거나, 객체와 같음. |
| `responseTime(ms)` | 응답이 `ms` 이하로 걸림. |

`pm.response.to.be.…`

| 속성 | 코드가 다음일 때 통과 |
| --- | --- |
| `info` | 100~199 |
| `success` | 200~299 |
| `ok` | 200 |
| `accepted` | 202 |
| `redirection` | 300~399 |
| `clientError` | 400~499 |
| `serverError` | 500 이상 |
| `error` | 400 이상 |
| `badRequest`, `unauthorized`(또는 `unauthorised`), `forbidden`, `notFound`, `rateLimited` | 400, 401, 403, 404, 429 |
| `json`, `html`, `xml`, `text` | (`Content-Type`에 그 단어가 포함됨) |
| `withBody` | (본문이 비어 있지 않음) |

## pm.request [#pmrequest]

요청입니다. 요청 전 스크립트에서는 요청을 바꾼 내용이 전송됩니다.

| 멤버 | 의미 |
| --- | --- |
| `url` | 객체로서의 URL. 아래를 참고하세요. `String(pm.request.url)`이 텍스트입니다. |
| `method` | 메서드. 바꿀 수 있습니다. |
| `headers` | [목록](#lists)으로서의 헤더. |
| `body` | 본문: `{ mode: "raw", raw: "…" }` 또는 `undefined`. |
| `name`, `id` | 요청의 이름과 작업 공간에서의 경로. |
| `addHeader(item)`, `removeHeader(name)`, `upsertHeader(item)` | 헤더를 바꿉니다. 항목은 `{ key, value }` 또는 `"Name: value"`입니다. |
| `addQueryParams(params)`, `removeQueryParams(names)` | 쿼리를 바꿉니다. `"a=1&b=2"`, `{ key, value }`, 또는 그 배열. |
| `to.have.header(name, value)` | 요청의 헤더에 대한 단언. |

```js
pm.request.headers.upsert({ key: "X-Request-Id", value: pm.variables.replaceIn("{{$guid}}") });
pm.request.url.addQueryParams("per_page=50");
```

`url` 객체에는 `protocol`, `host`(레이블 배열), `port`, `path`(구간 배열), `query`(목록), `hash`, 그리고 `getHost()`, `getPath()`, `getQueryString()`,
`getPathWithQuery()`, `getRemote()`, `update(text)`, `addQueryParams(…)`, `removeQueryParams(…)`, `toString()`이 있습니다. 바꾸지 않은 URL은
`{{variables}}`를 포함해 정확한 텍스트가 유지되며, Echolot은 스크립트가 끝난 뒤에 이를 해석합니다.

## 변수 [#variables]

| 범위 | 설명 |
| --- | --- |
| `pm.environment` | 활성 환경의 변수. `pm.environment.name`이 환경의 이름입니다. |
| `pm.collectionVariables` | 작업 공간의 변수. |
| `pm.globals` | 전역 변수. |
| `pm.iterationData` | 데이터 기반 실행의 현재 행. 읽기 전용입니다. |
| `pm.variables` | 모든 범위를 한 번에, 가까운 것부터. `set`과 `unset`은 로컬 값만 바꿉니다. |

각 범위에는 `get(name)`, `has(name)`, `set(name, value)`, `unset(name)`, `clear()`, `toObject()`, `replaceIn(text)`가 있습니다. `set`은 객체를 JSON
텍스트로 바꿉니다.

`pm.variables.get`은 로컬 값, 데이터 행, 폴더와 요청 변수, 환경, 작업 공간, 전역 변수의 순서로 찾습니다.

```js
// 요청 전: 본문에 서명
const signature = CryptoJS.HmacSHA256(pm.request.body.raw, pm.environment.get("apiSecret")).toString();
pm.request.headers.upsert({ key: "X-Signature", value: signature });

// 테스트: 새 주문의 ID를 다음 요청을 위해 보관
pm.collectionVariables.set("orderId", pm.response.json().id);
```

**`set`이 유지하는 것.** 스크립트가 설정한 값은 Postman의 “현재 값”입니다. 앱에서는 윈도우가 열려 있는 동안, 명령줄에서는 명령이 실행되는 동안
유지되며, 요청이 해석될 때 해당 범위에 저장된 값보다 우선합니다. 작업 공간 파일에는 절대 기록되지 않습니다. 응답의 값을 저장하려면
[응답 캡처](/docs/requests/captures)를 사용하세요. `pm.variables.set`의 로컬 값은 실행이 시작될 때 잊힙니다.

`replaceIn(text)`은 위의 범위에서 `{{variables}}`를 채웁니다. 동적 값 중에서는 `{{$guid}}`, `{{$randomUUID}}`, `{{$timestamp}}`,
`{{$isoTimestamp}}`, `{{$randomInt}}`를 알며, 그 외의 `{{$…}}`는 그대로 두어 Echolot이 요청을 보낼 때 해석합니다.

## pm.info [#pminfo]

| 멤버 | 의미 |
| --- | --- |
| `eventName` | `"prerequest"` 또는 `"test"`. |
| `iteration` | 실행의 반복 번호(0부터). |
| `iterationCount` | 실행의 반복 횟수. |
| `requestName` | 요청의 이름. |
| `requestId` | 작업 공간에서의 요청 경로. |

## pm.sendRequest [#pmsendrequest]

스크립트에서 Echolot을 통해 다른 요청을 보냅니다. 프록시, 인증서, 쿠키는 다른 요청과 똑같이 적용됩니다.

```js
pm.sendRequest("https://demo.echolot.dev/v1/categories", (error, response) => {
  if (error) { console.error(error); return; }
  pm.collectionVariables.set("firstCategory", response.json().items[0].id);
});

// 프라미스를 사용할 수도 있습니다
pm.sendRequest({
  url: pm.variables.replaceIn("{{baseURL}}/auth/token"),
  method: "POST",
  header: { "Content-Type": "application/json" },
  body: { mode: "raw", raw: JSON.stringify({ email: "heidi@alpenglow.ch", password: pm.environment.get("password") }) }
}).then(response => {
  pm.environment.set("token", response.json().access_token);
});
```

- 첫 번째 인수는 URL이거나, `url`, `method`(기본값 `GET`), `header`(`{ key, value }` 배열, 객체, 또는 목록), `body`가 있는 객체입니다.
- `body`는 문자열, `{ mode: "raw", raw }`, `{ mode: "urlencoded", urlencoded: [{ key, value }] }`, 또는
  `{ mode: "graphql", graphql: { query, variables } }`입니다. 뒤의 두 가지는 `Content-Type`을 지정하지 않으면 알아서 설정합니다.
- URL의 `{{variables}}`는 요청의 환경으로 채워집니다.
- 콜백은 `(error, response)`를 받으며, `response`는 `pm.response`와 같습니다. 콜백이 없으면 프라미스를 반환합니다.
- 이 요청에는 자체 인증이 없으며(작업 공간의 인증은 적용되지 않습니다) 스크립트도 실행하지 않습니다.
- 에이전트의 `pm.sendRequest`는 다른 전송과 마찬가지로 에이전트의 승인을 거칩니다.

## 실행 제어 [#controlling-a-run]

| 호출 | 하는 일 |
| --- | --- |
| `pm.execution.setNextRequest(name)` | 실행에서 그 요청을 다음에 계속합니다. `null`은 실행을 끝냅니다. `pm.setNextRequest`, `postman.setNextRequest`도 같습니다. |
| `pm.execution.skipRequest()` | 요청 전 스크립트에서: 이 요청을 보내지 않습니다. |

## pm.cookies [#pmcookies]

이 교환의 쿠키입니다. 요청이 보낸 쿠키와 응답이 설정한 쿠키입니다. [목록](#lists)이며 `pm.cookies.get(name)`, `has(name)`, `toObject()`,
`{ name, key, value }`를 반환하는 `one(name)`이 있습니다.

## 목록 [#lists]

헤더, 쿼리 매개변수, 쿠키는 Postman 속성 목록입니다.

| 메서드 | 하는 일 |
| --- | --- |
| `get(key)` | 값. 키는 대소문자를 구분하지 않습니다. |
| `one(key)` | 항목 전체, `{ key, value, disabled }`. |
| `has(key)`, `has(key, value)` | 있는지 여부(그 값으로). |
| `add(item)`, `append(item)`, `upsert(item)` | 항목을 추가하거나, 추가 또는 교체합니다. |
| `remove(key)`, `remove(fn)`, `clear()` | 항목을 제거합니다. |
| `toObject()`, `all()`, `count()`, `idx(i)` | 항목을 객체로, 배열로, 개수로, 인덱스 위치의 항목으로. |
| `each(fn)`, `map(fn)`, `filter(fn)`, `find(fn)` | 항목을 순회합니다. |
| `toString()` | `Name: value` 줄. |

## console [#console]

`console.log`, `info`, `warn`, `error`, `debug`, `trace`는 요청의 **콘솔**에 쓰이며, 명령줄에서는 `── console ──` 아래에 쓰입니다. 객체는 JSON으로
기록됩니다.

## 타이머 [#timers]

`setTimeout`, `setInterval`, `setImmediate`는 스크립트가 끝난 후 지연 시간 순서대로 함수를 실행하며, 실제로 기다리지는 않습니다. `setInterval`은
한 번 실행됩니다. `clearTimeout` 등은 취소합니다.

## JSON 스키마 [#json-schema]

세 가지 방법이 있으며 모두 Echolot 자체의 JSON 스키마 검증기를 사용합니다.

```js
const schema = {
  type: "object",
  required: ["sku", "price"],
  properties: { sku: { type: "string" }, price: { type: "object" } }
};

// Chai
pm.expect(pm.response.json()).to.have.jsonSchema(schema);

// ajv
const Ajv = require("ajv");
const validate = new Ajv().compile(schema);
pm.test("Matches the schema", () => pm.expect(validate(pm.response.json()), JSON.stringify(validate.errors)).to.be.true);

// tv4
pm.test("Matches the schema", () => pm.expect(tv4.validate(pm.response.json(), schema)).to.be.true);
```

| 도우미 | 제공하는 것 |
| --- | --- |
| `require("ajv")` | 클래스: `new Ajv(options)`, `validate(schema, data)`, `compile(schema)`(`.errors`가 있는 함수), `addSchema(schema, key)`, `getSchema(key)`, `errorsText(errors)`, `errors`. `addFormat`과 `addKeyword`는 받아들이지만 아무 일도 하지 않습니다. |
| `tv4`(`require("tv4")`도 가능) | `tv4.error`가 있는 `validate(data, schema)`, `validateResult(data, schema)`, `validateMultiple(data, schema)`. |
| `.jsonSchema(schema)` | 위의 Chai 단언. |

JSON 스키마 검사는 스크립트 없이도 동작합니다. **테스트** 탭의 **JSON Schema** 검사입니다.

## 라이브러리 [#libraries]

| 이름 | 제공하는 것 |
| --- | --- |
| `CryptoJS`(`require("crypto-js")`도 가능) | `MD5`, `SHA1`, `SHA256`, `SHA384`, `SHA512`, `HmacMD5`, `HmacSHA1`, `HmacSHA256`, `HmacSHA384`, `HmacSHA512`. `enc.Hex`, `enc.Utf8`, `enc.Base64`, `enc.Latin1`. `lib.WordArray.create(bytes)`와 `lib.WordArray.random(n)`. 결과에는 `toString(encoder)`가 있습니다. |
| `_`(`require("lodash")`도 가능) | 컬렉션이 사용하는 lodash 함수: `each`/`forEach`, `map`, `filter`, `reject`, `find`, `findIndex`, `some`, `every`, `reduce`, `includes`/`contains`, `get`, `has`, `set`, `keys`, `values`, `size`, `is…` 검사(`isArray`, `isString`, `isEmpty`, `isEqual` 등), `startsWith`, `endsWith`, `trim`, `toLower`, `toUpper`, `capitalize`, `parseInt`, `toNumber`, `toString`, `first`/`head`, `last`, `tail`, `initial`, `uniq`, `flatten`, `compact`, `concat`, `range`, `times`, `sortBy`, `groupBy`, `keyBy`, `countBy`, `pick`, `omit`, `assign`/`extend`, `clone`, `cloneDeep`, `merge`, `random`, `sample`, `sum`, `max`, `min`, `noop`, `identity`, `now`, `uniqueId`. |
| `require("uuid")` | 무작위 UUID를 반환하는 `v4()`. |
| `btoa`, `atob`(`require("btoa")`, `require("atob")`도 가능) | Latin-1 텍스트의 Base64 인코딩과 디코딩. |

## 예전 Postman 전역 객체 [#the-old-postman-globals]

예전 컬렉션의 스크립트가 사용하는 것들이며, 동작합니다.

| 전역 객체 | 설명 |
| --- | --- |
| `tests["name"] = condition` | 테스트. |
| `responseBody`, `responseCode`(`code`, `name`, `detail`), `responseHeaders`, `responseTime` | 응답. |
| `request`(`url`, `method`, `headers`, `data`, `name`, `description`) | 요청. |
| `environment`, `globals`, `data`, `iteration` | 객체로서의 변수, 데이터 행, 반복. |
| `postman.setEnvironmentVariable`, `getEnvironmentVariable`, `clearEnvironmentVariable`, `clearEnvironmentVariables` | 환경. |
| `postman.setGlobalVariable`, `getGlobalVariable`, `clearGlobalVariable`, `clearGlobalVariables` | 전역 변수. |
| `postman.getResponseHeader(name)`, `postman.getResponseCookie(name)`, `postman.setNextRequest(name)` | 응답과 실행. |
| `"text".has("x")` | 문자열이 다른 문자열을 포함하는지 여부. |

## 없는 것 [#what-is-not-there]

- 다른 모듈: 위에 나열되지 않은 것(`cheerio`, `xml2js`, `moment`, Node 자체 모듈)을 `require`하면 “The module … is not available in Echolot
  scripts.”라는 예외가 발생합니다.
- 실제 대기: 타이머는 지연 없이 실행되며, `fetch`나 `XMLHttpRequest`는 없습니다. `pm.sendRequest`를 사용하세요.
- 파일과 프로세스: 스크립트는 파일을 읽거나 쓰거나 프로그램을 시작할 수 없습니다.
- `pm.visualizer.set`은 받아들여지므로 이를 사용하는 스크립트는 실행되지만, Echolot은 시각화를 표시하지 않습니다.
- `xml2Json`, `pm.require`와 Postman의 패키지 라이브러리, `pm.vault`.
- 파일 속의 비밀 값: 스크립트는 비밀 변수를 다른 변수처럼 읽지만, `set`으로 설정한 값은 작업 공간 파일에 전달되지 않습니다.
