{
	"info": {
		"name": "Tetiva Playground",
		"description": "Один хост, четыре протокола, 20 запросов. Tetiva Playground на `playground.tetiva.app` отвечает тем, что вы прислали, любым кодом, который попросите, и так медленно, как нужно. Без ключа, ничего не хранит, не прокси. Два стриминговых вызова gRPC лежат в описании папки gRPC командами grpcurl.",
		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
	},
	"item": [
		{
			"name": "REST · Эхо",
			"description": "Эхо возвращает метод, URL, query (в `args`), заголовки и тело, которые получило, и `request_id`. JSON-тело приходит сырым в `data` и разобранным в `json`, формы и файлы multipart — в `form` и `files`.",
			"item": [
				{
					"name": "Эхо GET",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/get?source=docs&page=2"
						},
						"description": "Возвращает ваш запрос в JSON: параметры query в `args`, заголовки в `headers`, ваш IP в `origin`."
					},
					"response": [
						{
							"name": "Эхо",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/get?source=docs&page=2"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "314"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"GET\",\n  \"url\": \"https://playground.tetiva.app/get?source=docs&page=2\",\n  \"args\": {\n    \"page\": \"2\",\n    \"source\": \"docs\"\n  },\n  \"headers\": {\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\"\n  },\n  \"origin\": \"203.0.113.42\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Вернуть моё POST-тело",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\"hello\":\"world\"}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/post"
						},
						"description": "Отправьте JSON-тело и получите его обратно: сырым в `data` и разобранным в `json`. Тело до 1 МБ; формы и файлы multipart возвращаются в `form` и `files`."
					},
					"response": [
						{
							"name": "Эхо",
							"originalRequest": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\"hello\":\"world\"}",
									"options": {
										"raw": {
											"language": "json"
										}
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/post"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "397"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"POST\",\n  \"url\": \"https://playground.tetiva.app/post\",\n  \"args\": {},\n  \"headers\": {\n    \"Content-Length\": \"17\",\n    \"Content-Type\": \"application/json\",\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\"\n  },\n  \"data\": \"{\\\"hello\\\":\\\"world\\\"}\",\n  \"json\": {\n    \"hello\": \"world\"\n  },\n  \"origin\": \"203.0.113.42\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Эхо PUT",
					"request": {
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"id\": 42,\n  \"name\": \"Ada Lovelace\",\n  \"role\": \"admin\"\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/put"
						},
						"description": "То же эхо для PUT: тело возвращается в `data` и `json`."
					},
					"response": [
						{
							"name": "Эхо",
							"originalRequest": {
								"method": "PUT",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n  \"id\": 42,\n  \"name\": \"Ada Lovelace\",\n  \"role\": \"admin\"\n}",
									"options": {
										"raw": {
											"language": "json"
										}
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/put"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "488"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"PUT\",\n  \"url\": \"https://playground.tetiva.app/put\",\n  \"args\": {},\n  \"headers\": {\n    \"Content-Length\": \"59\",\n    \"Content-Type\": \"application/json\",\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\"\n  },\n  \"data\": \"{\\n  \\\"id\\\": 42,\\n  \\\"name\\\": \\\"Ada Lovelace\\\",\\n  \\\"role\\\": \\\"admin\\\"\\n}\",\n  \"json\": {\n    \"id\": 42,\n    \"name\": \"Ada Lovelace\",\n    \"role\": \"admin\"\n  },\n  \"origin\": \"203.0.113.42\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Эхо PATCH",
					"request": {
						"method": "PATCH",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"role\": \"viewer\"\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/patch"
						},
						"description": "То же эхо для PATCH, удобно для частичных обновлений."
					},
					"response": [
						{
							"name": "Эхо",
							"originalRequest": {
								"method": "PATCH",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n  \"role\": \"viewer\"\n}",
									"options": {
										"raw": {
											"language": "json"
										}
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/patch"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "406"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"PATCH\",\n  \"url\": \"https://playground.tetiva.app/patch\",\n  \"args\": {},\n  \"headers\": {\n    \"Content-Length\": \"22\",\n    \"Content-Type\": \"application/json\",\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\"\n  },\n  \"data\": \"{\\n  \\\"role\\\": \\\"viewer\\\"\\n}\",\n  \"json\": {\n    \"role\": \"viewer\"\n  },\n  \"origin\": \"203.0.113.42\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Эхо DELETE",
					"request": {
						"method": "DELETE",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/delete?id=42"
						},
						"description": "То же эхо для DELETE. Тело разрешено и тоже возвращается."
					},
					"response": [
						{
							"name": "Эхо",
							"originalRequest": {
								"method": "DELETE",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/delete?id=42"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "314"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"DELETE\",\n  \"url\": \"https://playground.tetiva.app/delete?id=42\",\n  \"args\": {\n    \"id\": \"42\"\n  },\n  \"headers\": {\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\"\n  },\n  \"data\": \"\",\n  \"json\": null,\n  \"origin\": \"203.0.113.42\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Любой метод, любой путь",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"status\": \"shipped\"\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/anything/orders/42?dry_run=true"
						},
						"description": "`/anything` и любой путь под ним отвечают эхом на любой метод, включая нестандартные: так можно подставить маршрут, которого ещё нет."
					},
					"response": [
						{
							"name": "Эхо",
							"originalRequest": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n  \"status\": \"shipped\"\n}",
									"options": {
										"raw": {
											"language": "json"
										}
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/anything/orders/42?dry_run=true"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "462"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"POST\",\n  \"url\": \"https://playground.tetiva.app/anything/orders/42?dry_run=true\",\n  \"args\": {\n    \"dry_run\": \"true\"\n  },\n  \"headers\": {\n    \"Content-Length\": \"25\",\n    \"Content-Type\": \"application/json\",\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\"\n  },\n  \"data\": \"{\\n  \\\"status\\\": \\\"shipped\\\"\\n}\",\n  \"json\": {\n    \"status\": \"shipped\"\n  },\n  \"origin\": \"203.0.113.42\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Мои заголовки",
					"request": {
						"method": "GET",
						"header": [
							{
								"key": "X-Debug",
								"value": "1"
							}
						],
						"url": {
							"raw": "https://playground.tetiva.app/headers"
						},
						"description": "Возвращает только заголовки, которые получил сервер. Удобно проверить, что добавляет ваш клиент, прокси или SDK."
					},
					"response": [
						{
							"name": "Ваши заголовки",
							"originalRequest": {
								"method": "GET",
								"header": [
									{
										"key": "X-Debug",
										"value": "1"
									}
								],
								"url": {
									"raw": "https://playground.tetiva.app/headers"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "167"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"headers\": {\n    \"Host\": \"playground.tetiva.app\",\n    \"User-Agent\": \"curl/8.7.1\",\n    \"X-Debug\": \"1\"\n  },\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				}
			]
		},
		{
			"name": "REST · Коды ответа и задержки",
			"description": "Заставьте сервер ошибиться или притормозить: любой код от 200 до 599 или ожидание до 10 секунд.",
			"item": [
				{
					"name": "Любой код ответа",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/status/418"
						},
						"description": "Отвечает кодом из пути, от 200 до 599. Редиректы ведут на `/get`, к 401 добавляется `WWW-Authenticate`, к 429 и 503 — `Retry-After`."
					},
					"response": [
						{
							"name": "Я чайник",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/status/418"
								}
							},
							"status": "I'm a teapot",
							"code": 418,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "104"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"status\": 418,\n  \"reason\": \"I'm a teapot\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						},
						{
							"name": "Сервис недоступен",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/status/418"
								}
							},
							"status": "Service Unavailable",
							"code": 503,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "111"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								},
								{
									"key": "retry-after",
									"value": "5"
								}
							],
							"body": "{\n  \"status\": 503,\n  \"reason\": \"Service Unavailable\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Медленный ответ",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/delay/2"
						},
						"description": "Ждёт столько секунд, сколько указано в пути, но не больше 10, и только потом отвечает; можно дробные, например `/delay/0.5`. Подходит для проверки таймаутов и состояний загрузки."
					},
					"response": [
						{
							"name": "Через 2 секунды",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/delay/2"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "237"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"method\": \"GET\",\n  \"url\": \"https://playground.tetiva.app/delay/2\",\n  \"args\": {},\n  \"delay\": 2,\n  \"started_at\": \"2026-10-17T09:30:00Z\",\n  \"finished_at\": \"2026-10-17T09:30:02Z\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				}
			]
		},
		{
			"name": "REST · Авторизация",
			"description": "Проверьте, что клиент отправляет учётные данные и не теряется, когда в ответ приходит 401.",
			"item": [
				{
					"name": "Bearer-авторизация",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/bearer"
						},
						"auth": {
							"type": "bearer",
							"bearer": [
								{
									"key": "token",
									"value": "test-token"
								}
							]
						},
						"description": "Проходит любой непустой токен, он возвращается в `token`. Без `Authorization: Bearer …` придёт 401 с `WWW-Authenticate: Bearer`."
					},
					"response": [
						{
							"name": "С токеном",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/bearer"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "109"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"authenticated\": true,\n  \"token\": \"test-token\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						},
						{
							"name": "Без заголовка Authorization",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/bearer"
								}
							},
							"status": "Unauthorized",
							"code": 401,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "128"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								},
								{
									"key": "www-authenticate",
									"value": "Bearer realm=\"playground\""
								}
							],
							"body": "{\n  \"authenticated\": false,\n  \"error\": \"missing Authorization header\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Basic-авторизация",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/basic-auth/tetiva/playground"
						},
						"auth": {
							"type": "basic",
							"basic": [
								{
									"key": "username",
									"value": "tetiva"
								},
								{
									"key": "password",
									"value": "playground"
								}
							]
						},
						"description": "Проходит, если логин и пароль Basic совпадают с теми, что в пути, здесь `tetiva` / `playground`. Иначе 401."
					},
					"response": [
						{
							"name": "Логин и пароль совпали",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/basic-auth/tetiva/playground"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "104"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"authenticated\": true,\n  \"user\": \"tetiva\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						},
						{
							"name": "Неверный пароль",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/basic-auth/tetiva/playground"
								}
							},
							"status": "Unauthorized",
							"code": 401,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "122"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								},
								{
									"key": "www-authenticate",
									"value": "Basic realm=\"playground\""
								}
							],
							"body": "{\n  \"authenticated\": false,\n  \"error\": \"wrong user or password\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				}
			]
		},
		{
			"name": "REST · Фейковые данные",
			"description": "Пять фейковых пользователей для списков, таблиц и пагинации. Данные каждый раз одни и те же, а `POST /users` отвечает так, будто всё получилось, но ничего не сохраняет.",
			"item": [
				{
					"name": "Фейковые пользователи",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/users?limit=3"
						},
						"description": "Страница фейковых пользователей. `limit` от 1 до 5, `next` ведёт на следующую страницу, пока не станет `null`."
					},
					"response": [
						{
							"name": "Первая страница",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/users?limit=3"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "576"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"Mila Novak\",\n      \"email\": \"mila.novak@example.com\",\n      \"role\": \"admin\",\n      \"created_at\": \"2026-03-02T09:14:00Z\"\n    },\n    {\n      \"id\": 2,\n      \"name\": \"Jonas Berg\",\n      \"email\": \"jonas.berg@example.com\",\n      \"role\": \"editor\",\n      \"created_at\": \"2026-04-18T16:40:00Z\"\n    },\n    {\n      \"id\": 3,\n      \"name\": \"Priya Raman\",\n      \"email\": \"priya.raman@example.com\",\n      \"role\": \"viewer\",\n      \"created_at\": \"2026-05-27T11:05:00Z\"\n    }\n  ],\n  \"total\": 5,\n  \"limit\": 3,\n  \"next\": \"/users?limit=3&after=3\"\n}\n"
						}
					]
				},
				{
					"name": "Один фейковый пользователь",
					"request": {
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://playground.tetiva.app/users/2"
						},
						"description": "Пользователь по id от 1 до 5. На любой другой id придёт 404 с подсказкой."
					},
					"response": [
						{
							"name": "Найден",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/users/2"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "135"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"id\": 2,\n  \"name\": \"Jonas Berg\",\n  \"email\": \"jonas.berg@example.com\",\n  \"role\": \"editor\",\n  \"created_at\": \"2026-04-18T16:40:00Z\"\n}\n"
						},
						{
							"name": "Нет такого id",
							"originalRequest": {
								"method": "GET",
								"header": [],
								"url": {
									"raw": "https://playground.tetiva.app/users/2"
								}
							},
							"status": "Not Found",
							"code": 404,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "138"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"error\": \"not_found\",\n  \"message\": \"No user with id 9. Ids go from 1 to 5.\",\n  \"request_id\": \"00000000-0000-4000-8000-000000000001\"\n}\n"
						}
					]
				},
				{
					"name": "Создать пользователя",
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"name\": \"Grace Hopper\",\n  \"email\": \"grace@example.com\",\n  \"role\": \"editor\"\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/users"
						},
						"description": "Проверяет `name` и `email` и отвечает 201 с новым пользователем и заголовком `Location`. Ничего не сохраняется: `stored` равен `false`."
					},
					"response": [
						{
							"name": "Создан, но не сохранён",
							"originalRequest": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n  \"name\": \"Grace Hopper\",\n  \"email\": \"grace@example.com\",\n  \"role\": \"editor\"\n}",
									"options": {
										"raw": {
											"language": "json"
										}
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/users"
								}
							},
							"status": "Created",
							"code": 201,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "151"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								},
								{
									"key": "location",
									"value": "https://playground.tetiva.app/users/6"
								}
							],
							"body": "{\n  \"id\": 6,\n  \"name\": \"Grace Hopper\",\n  \"email\": \"grace@example.com\",\n  \"role\": \"editor\",\n  \"created_at\": \"2026-10-17T09:30:00Z\",\n  \"stored\": false\n}\n"
						}
					]
				}
			]
		},
		{
			"name": "GraphQL",
			"description": "Маленькая библиотека на `https://playground.tetiva.app/graphql`: книги, авторы и одна мутация. Introspection включена, так что любой GraphQL-клиент сам загрузит схему.",
			"item": [
				{
					"name": "Запрос GraphQL",
					"request": {
						"method": "POST",
						"header": [],
						"body": {
							"mode": "graphql",
							"graphql": {
								"query": "query Books($first: Int) {\n  books(first: $first) {\n    id\n    title\n    author {\n      name\n    }\n  }\n}",
								"variables": "{\n  \"first\": 2\n}"
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/graphql"
						},
						"description": "Список книг с авторами. `first` от 1 до 50; на несуществующее поле придёт ошибка со списком настоящих."
					},
					"response": [
						{
							"name": "Две книги",
							"originalRequest": {
								"method": "POST",
								"header": [],
								"body": {
									"mode": "graphql",
									"graphql": {
										"query": "query Books($first: Int) {\n  books(first: $first) {\n    id\n    title\n    author {\n      name\n    }\n  }\n}",
										"variables": "{\n  \"first\": 2\n}"
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/graphql"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "304"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"data\": {\n    \"books\": [\n      {\n        \"id\": \"1\",\n        \"title\": \"Frankenstein\",\n        \"author\": {\n          \"name\": \"Mary Shelley\"\n        }\n      },\n      {\n        \"id\": \"2\",\n        \"title\": \"Moby-Dick\",\n        \"author\": {\n          \"name\": \"Herman Melville\"\n        }\n      }\n    ]\n  }\n}\n"
						},
						{
							"name": "Неизвестное поле",
							"originalRequest": {
								"method": "POST",
								"header": [],
								"body": {
									"mode": "graphql",
									"graphql": {
										"query": "query Books($first: Int) {\n  books(first: $first) {\n    id\n    title\n    author {\n      name\n    }\n  }\n}",
										"variables": "{\n  \"first\": 2\n}"
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/graphql"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "233"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"errors\": [\n    {\n      \"message\": \"Cannot query field \\\"isbn\\\" on type \\\"Book\\\". Fields on Book: id, title, year, author.\",\n      \"locations\": [\n        {\n          \"line\": 5,\n          \"column\": 5\n        }\n      ]\n    }\n  ]\n}\n"
						}
					]
				},
				{
					"name": "Одна книга по id",
					"request": {
						"method": "POST",
						"header": [],
						"body": {
							"mode": "graphql",
							"graphql": {
								"query": "query Book($id: ID!) {\n  book(id: $id) {\n    title\n    year\n    author {\n      name\n    }\n  }\n}",
								"variables": "{\n  \"id\": \"3\"\n}"
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/graphql"
						},
						"description": "Возвращает одну книгу. Для неизвестного id придёт `\"book\": null`, а не ошибка."
					},
					"response": [
						{
							"name": "Одна книга",
							"originalRequest": {
								"method": "POST",
								"header": [],
								"body": {
									"mode": "graphql",
									"graphql": {
										"query": "query Book($id: ID!) {\n  book(id: $id) {\n    title\n    year\n    author {\n      name\n    }\n  }\n}",
										"variables": "{\n  \"id\": \"3\"\n}"
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/graphql"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "151"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"data\": {\n    \"book\": {\n      \"title\": \"The Time Machine\",\n      \"year\": 1895,\n      \"author\": {\n        \"name\": \"H. G. Wells\"\n      }\n    }\n  }\n}\n"
						}
					]
				},
				{
					"name": "Добавить книгу",
					"request": {
						"method": "POST",
						"header": [],
						"body": {
							"mode": "graphql",
							"graphql": {
								"query": "mutation AddBook($title: String!, $authorId: ID!) {\n  addBook(title: $title, authorId: $authorId) {\n    id\n    title\n    author {\n      name\n    }\n  }\n}",
								"variables": "{\n  \"title\": \"Carmilla\",\n  \"authorId\": \"a5\"\n}"
							}
						},
						"url": {
							"raw": "https://playground.tetiva.app/graphql"
						},
						"description": "Мутация возвращает новую книгу с id `6`. Ничего не сохраняется: `extensions.stored` равен `false`."
					},
					"response": [
						{
							"name": "Добавлена, но не сохранена",
							"originalRequest": {
								"method": "POST",
								"header": [],
								"body": {
									"mode": "graphql",
									"graphql": {
										"query": "mutation AddBook($title: String!, $authorId: ID!) {\n  addBook(title: $title, authorId: $authorId) {\n    id\n    title\n    author {\n      name\n    }\n  }\n}",
										"variables": "{\n  \"title\": \"Carmilla\",\n  \"authorId\": \"a5\"\n}"
									}
								},
								"url": {
									"raw": "https://playground.tetiva.app/graphql"
								}
							},
							"status": "OK",
							"code": 200,
							"_postman_previewlanguage": "json",
							"header": [
								{
									"key": "content-type",
									"value": "application/json; charset=utf-8"
								},
								{
									"key": "content-length",
									"value": "191"
								},
								{
									"key": "x-request-id",
									"value": "00000000-0000-4000-8000-000000000001"
								},
								{
									"key": "access-control-allow-origin",
									"value": "*"
								},
								{
									"key": "ratelimit-limit",
									"value": "60"
								},
								{
									"key": "ratelimit-remaining",
									"value": "59"
								}
							],
							"body": "{\n  \"data\": {\n    \"addBook\": {\n      \"id\": \"6\",\n      \"title\": \"Carmilla\",\n      \"author\": {\n        \"name\": \"Sheridan Le Fanu\"\n      }\n    }\n  },\n  \"extensions\": {\n    \"stored\": false\n  }\n}\n"
						}
					]
				}
			]
		},
		{
			"name": "gRPC",
			"description": "`echo.v1.EchoService` на `playground.tetiva.app:443` с TLS и server reflection: клиенты находят методы без `.proto`-файла.\n\n**Reflection**\n\n```bash\ngrpcurl playground.tetiva.app:443 list\ngrpcurl playground.tetiva.app:443 describe echo.v1.EchoService\n```\n\n**Стримы.** `ServerStream` и `Chat` стримят, поэтому в эту коллекцию не вошли. Их можно запустить через grpcurl:\n\n```bash\ngrpcurl -d '{\"text\":\"ping\",\"count\":3,\"interval_ms\":500}' playground.tetiva.app:443 echo.v1.EchoService/ServerStream\ngrpcurl -d @ playground.tetiva.app:443 echo.v1.EchoService/Chat <<'EOF'\n{\"text\":\"hello\"}\n{\"text\":\"still there?\"}\nEOF\n```",
			"item": []
		},
		{
			"name": "WebSocket",
			"description": "Текстовые и бинарные кадры до 64 КБ. `/ws` закрывается кодом `1000 Normal Closure`, если 60 секунд не было сообщений; любая сессия заканчивается через 10 минут.",
			"item": []
		}
	]
}
