[{"data":1,"prerenderedAt":29434},["ShallowReactive",2],{"navigation_docs":3,"-client-server-architecture-rest-api-design-and-chi-routing":5180,"-client-server-architecture-rest-api-design-and-chi-routing-surround":29429},[4,1707,2084,2556,2737,2863,3070,3192,3242,3299,3333,3459,3536,3550,3689,3983,4060,4793,4968,5061,5114,5176],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908,1912,1916,1920,1924,1928,1932,1936,1940,1944,1948,1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000,2004,2008,2012,2016,2020,2024,2028,2032,2036,2040,2044,2048,2052,2056,2060,2064,2068,2072,2076,2080],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"Введення в ООП: від процедур до об'єктів","\u002Fcpp\u002Foop-intro","02.cpp\u002F49.oop-intro",{"title":1913,"path":1914,"stem":1915},"Класи, об'єкти та методи","\u002Fcpp\u002Fclasses-objects-methods","02.cpp\u002F50.classes-objects-methods",{"title":1917,"path":1918,"stem":1919},"Специфікатори доступу та інкапсуляція","\u002Fcpp\u002Faccess-specifiers-encapsulation","02.cpp\u002F51.access-specifiers-encapsulation",{"title":1921,"path":1922,"stem":1923},"Конструктори: гарантована ініціалізація об'єктів","\u002Fcpp\u002Fconstructors","02.cpp\u002F52.constructors",{"title":1925,"path":1926,"stem":1927},"Списки ініціалізації та делегуючі конструктори","\u002Fcpp\u002Finit-lists-delegating","02.cpp\u002F53.init-lists-delegating",{"title":1929,"path":1930,"stem":1931},"Деструктори та ідіома RAII","\u002Fcpp\u002Fdestructors-raii","02.cpp\u002F54.destructors-raii",{"title":1933,"path":1934,"stem":1935},"Прихований покажчик this","\u002Fcpp\u002Fthis-pointer","02.cpp\u002F55.this-pointer",{"title":1937,"path":1938,"stem":1939},"Розподіл класу на заголовковий файл та файл реалізації","\u002Fcpp\u002Fclass-header-source","02.cpp\u002F56.class-header-source",{"title":1941,"path":1942,"stem":1943},"Класи та const","\u002Fcpp\u002Fconst-classes","02.cpp\u002F57.const-classes",{"title":1945,"path":1946,"stem":1947},"Статичні члени класу","\u002Fcpp\u002Fstatic-members","02.cpp\u002F58.static-members",{"title":1949,"path":1950,"stem":1951},"Конструктор копіювання та запобігання копіюванню","\u002Fcpp\u002Fcopy-constructor","02.cpp\u002F59.copy-constructor",{"title":1953,"path":1954,"stem":1955},"Дружні функції та класи","\u002Fcpp\u002Ffriend-functions-classes","02.cpp\u002F60.friend-functions-classes",{"title":1957,"path":1958,"stem":1959},"Анонімні об'єкти та вкладені типи","\u002Fcpp\u002Fanonymous-objects-nested-types","02.cpp\u002F61.anonymous-objects-nested-types",{"title":1961,"path":1962,"stem":1963},"Вимірювання часу виконання: RAII-таймер","\u002Fcpp\u002Ftiming-raii-timer","02.cpp\u002F62.timing-raii-timer",{"title":1965,"path":1966,"stem":1967},"Перевантаження операторів: основи та арифметика","\u002Fcpp\u002Foperator-overloading-basics","02.cpp\u002F63.operator-overloading-basics",{"title":1969,"path":1970,"stem":1971},"Перевантаження операторів: методи класу та спеціальні оператори","\u002Fcpp\u002Foperator-overloading-methods","02.cpp\u002F64.operator-overloading-methods",{"title":1973,"path":1974,"stem":1975},"Приведення типів, explicit та delete","\u002Fcpp\u002Ftypecast-explicit-delete","02.cpp\u002F65.typecast-explicit-delete",{"title":1977,"path":1978,"stem":1979},"Глибоке копіювання та оператор присвоювання","\u002Fcpp\u002Fdeep-copy-assignment","02.cpp\u002F66.deep-copy-assignment",{"title":1981,"path":1982,"stem":1983},"Зв'язки між об'єктами: композиція та агрегація","\u002Fcpp\u002Fcomposition-aggregation","02.cpp\u002F67.composition-aggregation",{"title":1985,"path":1986,"stem":1987},"Асоціація та залежність між об","\u002Fcpp\u002Fassociation-dependency","02.cpp\u002F68.association-dependency",{"title":1989,"path":1990,"stem":1991},"Контейнерні класи та `std::initializer_list`","\u002Fcpp\u002Fcontainer-classes-initializer-list","02.cpp\u002F69.container-classes-initializer-list",{"title":1993,"path":1994,"stem":1995},"Вступ до наслідування: базові поняття та відношення «is-a»","\u002Fcpp\u002Finheritance-intro","02.cpp\u002F70.inheritance-intro",{"title":1997,"path":1998,"stem":1999},"Конструктори, деструктори та порядок ініціалізації в ієрархіях","\u002Fcpp\u002Finheritance-constructors-destructors","02.cpp\u002F71.inheritance-constructors-destructors",{"title":2001,"path":2002,"stem":2003},"Специфікатор `protected` та види наслідування","\u002Fcpp\u002Finheritance-access-specifiers","02.cpp\u002F72.inheritance-access-specifiers",{"title":2005,"path":2006,"stem":2007},"Перевизначення методів та приховування імен","\u002Fcpp\u002Fmethod-overriding-hiding","02.cpp\u002F73.method-overriding-hiding",{"title":2009,"path":2010,"stem":2011},"Множинне наслідування та проблема ромба","\u002Fcpp\u002Fmultiple-inheritance-diamond","02.cpp\u002F74.multiple-inheritance-diamond",{"title":2013,"path":2014,"stem":2015},"Вказівники на базовий клас та віртуальні функції","\u002Fcpp\u002Fvirtual-functions-polymorphism","02.cpp\u002F75.virtual-functions-polymorphism",{"title":2017,"path":2018,"stem":2019},"Специфікатори override, final та віртуальні деструктори","\u002Fcpp\u002Foverride-final-virtual-destructors","02.cpp\u002F76.override-final-virtual-destructors",{"title":2021,"path":2022,"stem":2023},"Внутрішні механізми поліморфізму: vtable, vptr та зв'язування","\u002Fcpp\u002Fvirtual-table-binding","02.cpp\u002F77.virtual-table-binding",{"title":2025,"path":2026,"stem":2027},"Абстрактні класи та чисті віртуальні функції","\u002Fcpp\u002Fabstract-classes-interfaces","02.cpp\u002F78.abstract-classes-interfaces",{"title":2029,"path":2030,"stem":2031},"Зрізка об'єктів, віртуальне наслідування та поліморфний вивід","\u002Fcpp\u002Fslicing-virtual-base-io","02.cpp\u002F79.slicing-virtual-base-io",{"title":2033,"path":2034,"stem":2035},"Динамічне приведення типів (`dynamic_cast`) та RTTI","\u002Fcpp\u002Fdynamic-cast-rtti","02.cpp\u002F80.dynamic-cast-rtti",{"title":2037,"path":2038,"stem":2039},"Шаблони функцій: узагальнене програмування","\u002Fcpp\u002Ffunction-templates","02.cpp\u002F81.function-templates",{"title":2041,"path":2042,"stem":2043},"Шаблони класів та NTTP-параметри","\u002Fcpp\u002Fclass-templates-nttp","02.cpp\u002F82.class-templates-nttp",{"title":2045,"path":2046,"stem":2047},"Повна (явна) спеціалізація шаблонів","\u002Fcpp\u002Ffull-template-specialization","02.cpp\u002F83.full-template-specialization",{"title":2049,"path":2050,"stem":2051},"Часткова спеціалізація шаблонів класів","\u002Fcpp\u002Fpartial-template-specialization","02.cpp\u002F84.partial-template-specialization",{"title":2053,"path":2054,"stem":2055},"Механізм винятків: try, catch, throw та розкручування стеку","\u002Fcpp\u002Fexceptions-basics","02.cpp\u002F85.exceptions-basics",{"title":2057,"path":2058,"stem":2059},"Ієрархія std::exception та власні класи винятків","\u002Fcpp\u002Fexception-hierarchy-custom","02.cpp\u002F86.exception-hierarchy-custom",{"title":2061,"path":2062,"stem":2063},"Повторне генерування винятків та функціональний try-блок","\u002Fcpp\u002Frethrow-function-try","02.cpp\u002F87.rethrow-function-try",{"title":2065,"path":2066,"stem":2067},"Безпека винятків, noexcept та деструктори","\u002Fcpp\u002Fsafety-noexcept","02.cpp\u002F88.safety-noexcept",{"title":2069,"path":2070,"stem":2071},"Стаття 89 — Власні структури даних: стек та черга","\u002Fcpp\u002Fcustom-stack-queue","02.cpp\u002F89.custom-stack-queue",{"title":2073,"path":2074,"stem":2075},"Стаття 90 — Власні структури даних: однозв'язаний список","\u002Fcpp\u002Flinked-list","02.cpp\u002F90.linked-list",{"title":2077,"path":2078,"stem":2079},"Стаття 91 — Власні структури даних: бінарне дерево пошуку","\u002Fcpp\u002Fbinary-search-tree","02.cpp\u002F91.binary-search-tree",{"title":2081,"path":2082,"stem":2083},"Стаття 92 — Власні структури даних: хеш-таблиця","\u002Fcpp\u002Fhash-table","02.cpp\u002F92.hash-table",{"title":2085,"icon":2086,"path":2087,"stem":2088,"children":2089,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[2090,2116,2170,2192,2496,2534,2552],{"title":2091,"icon":2092,"path":2093,"stem":2094,"children":2095,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[2096,2100,2104,2108,2112],{"title":2097,"path":2098,"stem":2099},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":2101,"path":2102,"stem":2103},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":2105,"path":2106,"stem":2107},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":2109,"path":2110,"stem":2111},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":2113,"path":2114,"stem":2115},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":2117,"icon":2118,"path":2119,"stem":2120,"children":2121,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[2122,2126,2130,2134,2138,2142,2146,2150,2154,2158,2162,2166],{"title":2123,"path":2124,"stem":2125},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":2127,"path":2128,"stem":2129},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":2131,"path":2132,"stem":2133},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":2135,"path":2136,"stem":2137},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":2139,"path":2140,"stem":2141},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":2143,"path":2144,"stem":2145},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":2147,"path":2148,"stem":2149},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":2151,"path":2152,"stem":2153},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":2155,"path":2156,"stem":2157},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":2159,"path":2160,"stem":2161},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":2163,"path":2164,"stem":2165},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":2167,"path":2168,"stem":2169},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":2171,"icon":2172,"path":2173,"stem":2174,"children":2175,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2176,2180,2184,2188],{"title":2177,"path":2178,"stem":2179},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2181,"path":2182,"stem":2183},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2185,"path":2186,"stem":2187},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2189,"path":2190,"stem":2191},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2193,"icon":2194,"path":2195,"stem":2196,"children":2197},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2198,2199,2203,2207,2211,2215,2278,2313,2465],{"title":2193,"path":2195,"stem":2196},{"title":2200,"path":2201,"stem":2202},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2204,"path":2205,"stem":2206},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2208,"path":2209,"stem":2210},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2212,"path":2213,"stem":2214},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2216,"icon":132,"path":2217,"stem":2218,"children":2219},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2220,2222,2226,2230,2234,2238,2242,2246,2250,2254,2258,2262,2266,2270,2274],{"title":2221,"path":2217,"stem":2218},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2223,"path":2224,"stem":2225},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2227,"path":2228,"stem":2229},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2231,"path":2232,"stem":2233},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2235,"path":2236,"stem":2237},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2239,"path":2240,"stem":2241},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2243,"path":2244,"stem":2245},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2247,"path":2248,"stem":2249},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2251,"path":2252,"stem":2253},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2255,"path":2256,"stem":2257},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2259,"path":2260,"stem":2261},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2263,"path":2264,"stem":2265},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2267,"path":2268,"stem":2269},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2271,"path":2272,"stem":2273},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2275,"path":2276,"stem":2277},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2279,"icon":2194,"path":2280,"stem":2281,"children":2282},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2283,2285,2289,2293,2297,2301,2305,2309],{"title":2284,"path":2280,"stem":2281},"React Router: Навігаційна система сучасного вебу",{"title":2286,"path":2287,"stem":2288},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2290,"path":2291,"stem":2292},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2294,"path":2295,"stem":2296},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2298,"path":2299,"stem":2300},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2302,"path":2303,"stem":2304},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2306,"path":2307,"stem":2308},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2310,"path":2311,"stem":2312},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2314,"icon":132,"path":2315,"stem":2316,"children":2317},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2318,2320,2336,2365,2374,2395,2411,2440],{"title":2319,"path":2315,"stem":2316},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2321,"stem":2322,"children":2323,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2324,2328,2332],{"title":2325,"path":2326,"stem":2327},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2329,"path":2330,"stem":2331},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2333,"path":2334,"stem":2335},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2337,"icon":132,"path":2338,"stem":2339,"children":2340,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2341,2345,2349,2353,2357,2361],{"title":2342,"path":2343,"stem":2344},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2346,"path":2347,"stem":2348},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2350,"path":2351,"stem":2352},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2354,"path":2355,"stem":2356},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2358,"path":2359,"stem":2360},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2362,"path":2363,"stem":2364},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2366,"icon":132,"path":2367,"stem":2368,"children":2369,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2370],{"title":2371,"path":2372,"stem":2373},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2375,"icon":132,"path":2376,"stem":2377,"children":2378,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2379,2383,2387,2391],{"title":2380,"path":2381,"stem":2382},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2384,"path":2385,"stem":2386},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2388,"path":2389,"stem":2390},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2392,"path":2393,"stem":2394},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2396,"icon":92,"path":2397,"stem":2398,"children":2399,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2400,2404,2408],{"title":2401,"path":2402,"stem":2403},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2405,"path":2406,"stem":2407},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2255,"path":2409,"stem":2410},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2412,"icon":132,"path":2413,"stem":2414,"children":2415,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2416,2420,2424,2428,2432,2436],{"title":2417,"path":2418,"stem":2419},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2421,"path":2422,"stem":2423},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2425,"path":2426,"stem":2427},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2429,"path":2430,"stem":2431},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2433,"path":2434,"stem":2435},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2437,"path":2438,"stem":2439},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2441,"icon":132,"path":2442,"stem":2443,"children":2444,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2445,2449,2453,2457,2461],{"title":2446,"path":2447,"stem":2448},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2450,"path":2451,"stem":2452},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2454,"path":2455,"stem":2456},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2458,"path":2459,"stem":2460},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2462,"path":2463,"stem":2464},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2466,"icon":132,"path":2467,"stem":2468,"children":2469},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2470,2472,2476,2480,2484,2488,2492],{"title":2471,"path":2467,"stem":2468},"UI Бібліотеки в React",{"title":2473,"path":2474,"stem":2475},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2477,"path":2478,"stem":2479},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2481,"path":2482,"stem":2483},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2485,"path":2486,"stem":2487},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2489,"path":2490,"stem":2491},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2493,"path":2494,"stem":2495},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2497,"icon":2498,"path":2499,"stem":2500,"children":2501,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2502,2506,2510,2514,2518,2522,2526,2530],{"title":2503,"path":2504,"stem":2505},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2507,"path":2508,"stem":2509},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2511,"path":2512,"stem":2513},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2515,"path":2516,"stem":2517},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2519,"path":2520,"stem":2521},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2523,"path":2524,"stem":2525},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2527,"path":2528,"stem":2529},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2531,"path":2532,"stem":2533},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2535,"icon":2536,"path":2537,"stem":2538,"children":2539,"page":59},"Асинхронність","i-lucide-refresh-cw","\u002Fjavascript\u002Fasync-programming","03.javascript\u002F06.async-programming",[2540,2544,2548],{"title":2541,"path":2542,"stem":2543},"Event Loop: серце асинхронності в JavaScript","\u002Fjavascript\u002Fasync-programming\u002Fevent-loop-fundamentals","03.javascript\u002F06.async-programming\u002F01.event-loop-fundamentals",{"title":2545,"path":2546,"stem":2547},"Task Queue та Microtask Queue: пріоритети виконання","\u002Fjavascript\u002Fasync-programming\u002Ftask-queues","03.javascript\u002F06.async-programming\u002F02.task-queues",{"title":2549,"path":2550,"stem":2551},"Асинхронні патерни: від Callbacks до Async\u002FAwait","\u002Fjavascript\u002Fasync-programming\u002Fasync-patterns","03.javascript\u002F06.async-programming\u002F03.async-patterns",{"title":2553,"path":2554,"stem":2555},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2557,"icon":2558,"path":2559,"stem":2560,"children":2561,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2562,2565,2568,2572,2576,2580,2584],{"title":162,"path":2563,"stem":2564},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2566,"stem":2567},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2569,"path":2570,"stem":2571},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2573,"path":2574,"stem":2575},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2577,"path":2578,"stem":2579},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2581,"path":2582,"stem":2583},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2585,"path":2586,"stem":2587,"children":2588,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2589,2593,2597,2601,2605,2609,2613,2617,2621,2625,2629,2633,2637,2641,2645,2649,2653,2657,2661,2665,2669,2673,2677,2681,2685,2689,2693,2697,2701,2705,2709,2713,2717,2721,2725,2729,2733],{"title":2590,"path":2591,"stem":2592},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2594,"path":2595,"stem":2596},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2598,"path":2599,"stem":2600},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2602,"path":2603,"stem":2604},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2606,"path":2607,"stem":2608},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2610,"path":2611,"stem":2612},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2614,"path":2615,"stem":2616},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2618,"path":2619,"stem":2620},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2622,"path":2623,"stem":2624},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2626,"path":2627,"stem":2628},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2630,"path":2631,"stem":2632},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2634,"path":2635,"stem":2636},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2638,"path":2639,"stem":2640},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2642,"path":2643,"stem":2644},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2646,"path":2647,"stem":2648},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2650,"path":2651,"stem":2652},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2654,"path":2655,"stem":2656},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2658,"path":2659,"stem":2660},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2662,"path":2663,"stem":2664},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2666,"path":2667,"stem":2668},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2670,"path":2671,"stem":2672},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2674,"path":2675,"stem":2676},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2678,"path":2679,"stem":2680},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2682,"path":2683,"stem":2684},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2686,"path":2687,"stem":2688},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2690,"path":2691,"stem":2692},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2694,"path":2695,"stem":2696},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2698,"path":2699,"stem":2700},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2702,"path":2703,"stem":2704},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2706,"path":2707,"stem":2708},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2710,"path":2711,"stem":2712},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2714,"path":2715,"stem":2716},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2718,"path":2719,"stem":2720},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2722,"path":2723,"stem":2724},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2726,"path":2727,"stem":2728},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2730,"path":2731,"stem":2732},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2734,"path":2735,"stem":2736},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2738,"icon":2739,"path":2740,"stem":2741,"children":2742,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2743,2747,2750,2754,2758,2762,2766,2770,2774,2778,2782,2786,2790,2794,2798,2859],{"title":2744,"path":2745,"stem":2746},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2748,"stem":2749},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2751,"path":2752,"stem":2753},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2755,"path":2756,"stem":2757},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2759,"path":2760,"stem":2761},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2763,"path":2764,"stem":2765},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2767,"path":2768,"stem":2769},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2771,"path":2772,"stem":2773},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2775,"path":2776,"stem":2777},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2779,"path":2780,"stem":2781},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2783,"path":2784,"stem":2785},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2787,"path":2788,"stem":2789},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2791,"path":2792,"stem":2793},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2795,"path":2796,"stem":2797},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2799,"icon":92,"path":2800,"stem":2801,"children":2802,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2803,2807,2811,2815,2819,2823,2827,2831,2835,2839,2843,2847,2851,2855],{"title":2804,"path":2805,"stem":2806},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2808,"path":2809,"stem":2810},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2812,"path":2813,"stem":2814},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2816,"path":2817,"stem":2818},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2820,"path":2821,"stem":2822},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2824,"path":2825,"stem":2826},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2828,"path":2829,"stem":2830},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2832,"path":2833,"stem":2834},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2836,"path":2837,"stem":2838},"Alembic — міграції бази даних","\u002Fpython\u002Ffastapi\u002Falembic-migrations","05.python\u002Ffastapi\u002F23.alembic-migrations",{"title":2840,"path":2841,"stem":2842},"Repository Pattern та Clean Architecture у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-repository-clean-arch","05.python\u002Ffastapi\u002F24.fastapi-repository-clean-arch",{"title":2844,"path":2845,"stem":2846},"Автентифікація та авторизація — JWT, OAuth2, RBAC","\u002Fpython\u002Ffastapi\u002Ffastapi-auth-security","05.python\u002Ffastapi\u002F25.fastapi-auth-security",{"title":2848,"path":2849,"stem":2850},"Тестування FastAPI — pytest, httpx, fixtures","\u002Fpython\u002Ffastapi\u002Ffastapi-testing","05.python\u002Ffastapi\u002F26.fastapi-testing",{"title":2852,"path":2853,"stem":2854},"Async на повну — Background Tasks, WebSockets, SSE та Celery","\u002Fpython\u002Ffastapi\u002Ffastapi-async-advanced","05.python\u002Ffastapi\u002F27.fastapi-async-advanced",{"title":2856,"path":2857,"stem":2858},"Deployment — Docker, CI\u002FCD, Monitoring","\u002Fpython\u002Ffastapi\u002Ffastapi-deployment","05.python\u002Ffastapi\u002F28.fastapi-deployment",{"title":2860,"path":2861,"stem":2862},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2864,"icon":2865,"path":2866,"stem":2867,"children":2868,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2869,2899,2922,2959,2988,3006,3040,3052,3061],{"title":2870,"icon":2871,"path":2872,"stem":2873,"children":2874,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2875,2879,2883,2887,2891,2895],{"title":2876,"path":2877,"stem":2878},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2880,"path":2881,"stem":2882},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2884,"path":2885,"stem":2886},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2888,"path":2889,"stem":2890},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2892,"path":2893,"stem":2894},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2896,"path":2897,"stem":2898},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2900,"icon":2865,"path":2901,"stem":2902,"children":2903,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2904,2908,2914,2918],{"title":2905,"path":2906,"stem":2907},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2909,"path":2910,"stem":2911,"children":2912},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2913],{"title":2909,"path":2910,"stem":2911},{"title":2915,"path":2916,"stem":2917},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2919,"path":2920,"stem":2921},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2923,"icon":2865,"path":2924,"stem":2925,"children":2926,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2927,2931,2935,2939,2943,2947,2951,2955],{"title":2928,"path":2929,"stem":2930},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2932,"path":2933,"stem":2934},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2936,"path":2937,"stem":2938},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2940,"path":2941,"stem":2942},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2944,"path":2945,"stem":2946},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2948,"path":2949,"stem":2950},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2952,"path":2953,"stem":2954},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2956,"path":2957,"stem":2958},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2960,"icon":2865,"path":2961,"stem":2962,"children":2963,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2964,2968,2972,2976,2980,2984],{"title":2965,"path":2966,"stem":2967},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2969,"path":2970,"stem":2971},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2973,"path":2974,"stem":2975},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2977,"path":2978,"stem":2979},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2981,"path":2982,"stem":2983},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2985,"path":2986,"stem":2987},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2989,"icon":2990,"path":2991,"stem":2992,"children":2993,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2994,2998,3002],{"title":2995,"path":2996,"stem":2997},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2999,"path":3000,"stem":3001},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":3003,"path":3004,"stem":3005},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":3007,"icon":3008,"path":3009,"stem":3010,"children":3011,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[3012,3016,3020,3024,3028,3032,3036],{"title":3013,"path":3014,"stem":3015},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":3017,"path":3018,"stem":3019},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":3021,"path":3022,"stem":3023},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":3025,"path":3026,"stem":3027},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":3029,"path":3030,"stem":3031},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":3033,"path":3034,"stem":3035},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":3037,"path":3038,"stem":3039},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":3037,"icon":793,"path":3041,"stem":3042,"children":3043,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[3044,3048],{"title":3045,"path":3046,"stem":3047},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":3049,"path":3050,"stem":3051},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":3053,"icon":3054,"path":3055,"stem":3056,"children":3057,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[3058],{"title":3053,"path":3059,"stem":3060},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":3062,"icon":3063,"path":3064,"stem":3065,"children":3066,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[3067],{"title":3062,"path":3068,"stem":3069},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":3071,"icon":3072,"path":3073,"stem":3074,"children":3075,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[3076,3152],{"title":3077,"icon":3078,"path":3079,"stem":3080,"children":3081},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[3082,3084,3088,3092,3096,3100,3104,3108,3112,3116,3120,3124,3128,3132,3136,3140,3144,3148],{"title":3083,"path":3079,"stem":3080},"Docker: від нуля до production",{"title":3085,"path":3086,"stem":3087},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":3089,"path":3090,"stem":3091},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":3093,"path":3094,"stem":3095},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":3097,"path":3098,"stem":3099},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":3101,"path":3102,"stem":3103},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":3105,"path":3106,"stem":3107},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":3109,"path":3110,"stem":3111},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":3113,"path":3114,"stem":3115},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":3117,"path":3118,"stem":3119},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":3121,"path":3122,"stem":3123},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":3125,"path":3126,"stem":3127},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":3129,"path":3130,"stem":3131},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":3133,"path":3134,"stem":3135},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":3137,"path":3138,"stem":3139},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":3141,"path":3142,"stem":3143},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":3145,"path":3146,"stem":3147},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":3149,"path":3150,"stem":3151},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":3153,"icon":3154,"path":3155,"stem":3156,"children":3157},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[3158,3160,3164,3168,3172,3176,3180,3184,3188],{"title":3159,"path":3155,"stem":3156},"Kubernetes: від розробки до production",{"title":3161,"path":3162,"stem":3163},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":3165,"path":3166,"stem":3167},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":3169,"path":3170,"stem":3171},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":3173,"path":3174,"stem":3175},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":3177,"path":3178,"stem":3179},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":3181,"path":3182,"stem":3183},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":3185,"path":3186,"stem":3187},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":3189,"path":3190,"stem":3191},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":3193,"icon":3194,"path":3195,"stem":3196,"children":3197,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[3198,3202,3206,3210,3214,3218,3222,3226,3230,3234,3238],{"title":3199,"path":3200,"stem":3201},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":3203,"path":3204,"stem":3205},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":3207,"path":3208,"stem":3209},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":3211,"path":3212,"stem":3213},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3215,"path":3216,"stem":3217},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3219,"path":3220,"stem":3221},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3223,"path":3224,"stem":3225},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3227,"path":3228,"stem":3229},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3231,"path":3232,"stem":3233},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3235,"path":3236,"stem":3237},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3239,"path":3240,"stem":3241},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3243,"icon":943,"path":3244,"stem":3245,"children":3246,"page":59},"DDD","\u002Fddd","10.ddd",[3247,3251,3255,3259,3263,3267,3271,3275,3279,3283,3287,3291,3295],{"title":3248,"path":3249,"stem":3250},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3252,"path":3253,"stem":3254},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3256,"path":3257,"stem":3258},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3260,"path":3261,"stem":3262},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3264,"path":3265,"stem":3266},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3268,"path":3269,"stem":3270},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3272,"path":3273,"stem":3274},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3276,"path":3277,"stem":3278},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3280,"path":3281,"stem":3282},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3284,"path":3285,"stem":3286},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3288,"path":3289,"stem":3290},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3292,"path":3293,"stem":3294},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3296,"path":3297,"stem":3298},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3300,"icon":3301,"path":3302,"stem":3303,"children":3304,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3305,3309,3313,3317,3321,3325,3329],{"title":3306,"path":3307,"stem":3308},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3310,"path":3311,"stem":3312},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3314,"path":3315,"stem":3316},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3318,"path":3319,"stem":3320},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3322,"path":3323,"stem":3324},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3326,"path":3327,"stem":3328},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3330,"path":3331,"stem":3332},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3334,"icon":3335,"path":3336,"stem":3337,"children":3338,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3339,3343,3347,3351,3355,3359,3363,3367,3371,3375,3379,3383,3387,3391,3395,3399,3403,3407,3411,3415,3419,3423,3427,3431,3435,3439,3443,3447,3451,3455],{"title":3340,"path":3341,"stem":3342},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3344,"path":3345,"stem":3346},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3348,"path":3349,"stem":3350},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3352,"path":3353,"stem":3354},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3356,"path":3357,"stem":3358},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3360,"path":3361,"stem":3362},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3364,"path":3365,"stem":3366},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3368,"path":3369,"stem":3370},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3372,"path":3373,"stem":3374},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3376,"path":3377,"stem":3378},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3380,"path":3381,"stem":3382},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3384,"path":3385,"stem":3386},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3388,"path":3389,"stem":3390},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3392,"path":3393,"stem":3394},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3396,"path":3397,"stem":3398},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3400,"path":3401,"stem":3402},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3404,"path":3405,"stem":3406},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3408,"path":3409,"stem":3410},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3412,"path":3413,"stem":3414},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3416,"path":3417,"stem":3418},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3420,"path":3421,"stem":3422},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3424,"path":3425,"stem":3426},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3428,"path":3429,"stem":3430},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3432,"path":3433,"stem":3434},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3436,"path":3437,"stem":3438},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3440,"path":3441,"stem":3442},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3444,"path":3445,"stem":3446},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3448,"path":3449,"stem":3450},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3452,"path":3453,"stem":3454},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3456,"path":3457,"stem":3458},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3460,"path":3461,"stem":3462,"children":3463,"page":59},"AWS","\u002Faws","13.aws",[3464,3468,3472,3476,3480,3484,3488,3492,3496,3500,3504,3508,3512,3516,3520,3524,3528,3532],{"title":3465,"path":3466,"stem":3467},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3469,"path":3470,"stem":3471},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3473,"path":3474,"stem":3475},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3477,"path":3478,"stem":3479},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3481,"path":3482,"stem":3483},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3485,"path":3486,"stem":3487},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3489,"path":3490,"stem":3491},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3493,"path":3494,"stem":3495},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3497,"path":3498,"stem":3499},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3501,"path":3502,"stem":3503},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3505,"path":3506,"stem":3507},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3509,"path":3510,"stem":3511},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3513,"path":3514,"stem":3515},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3517,"path":3518,"stem":3519},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3521,"path":3522,"stem":3523},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3525,"path":3526,"stem":3527},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3529,"path":3530,"stem":3531},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3533,"path":3534,"stem":3535},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3537,"path":3538,"stem":3539,"children":3540,"page":59},"Ai Development","\u002Fai-development","14.ai-development",[3541],{"title":3542,"path":3543,"stem":3544,"children":3545,"page":59},"Foundations","\u002Fai-development\u002Ffoundations","14.ai-development\u002F00.foundations",[3546],{"title":3547,"path":3548,"stem":3549},"Модуль 0.1. Що таке Large Language Model (LLM)","\u002Fai-development\u002Ffoundations\u002Fwhat-is-llm","14.ai-development\u002F00.foundations\u002F01.what-is-llm",{"title":3551,"path":3552,"stem":3553,"children":3554,"page":59},"React Native","\u002Freact-native","15.react-native",[3555,3576],{"title":3556,"path":3557,"stem":3558,"children":3559,"page":59},"Version1","\u002Freact-native\u002Fversion1","15.react-native\u002Fversion1",[3560,3564,3568,3572],{"title":3561,"path":3562,"stem":3563},"Що таке React Native","\u002Freact-native\u002Fversion1\u002Fwhat-is-react-native","15.react-native\u002Fversion1\u002F01.what-is-react-native",{"title":3565,"path":3566,"stem":3567},"Як влаштований React Native «під капотом»","\u002Freact-native\u002Fversion1\u002Freact-native-architecture","15.react-native\u002Fversion1\u002F02.react-native-architecture",{"title":3569,"path":3570,"stem":3571},"Від React до React Native: ключові відмінності","\u002Freact-native\u002Fversion1\u002Freact-native-vs-react","15.react-native\u002Fversion1\u002F03.react-native-vs-react",{"title":3573,"path":3574,"stem":3575},"View та Text — фундаментальні будівельні блоки","\u002Freact-native\u002Fversion1\u002Fview-and-text","15.react-native\u002Fversion1\u002F04.view-and-text",{"title":3577,"path":3578,"stem":3579,"children":3580,"page":59},"Version2","\u002Freact-native\u002Fversion2","15.react-native\u002Fversion2",[3581,3585,3589,3593,3597,3601,3605,3609,3613,3617,3621,3625,3629,3633,3637,3641,3645,3649,3653,3657,3661,3665,3669,3673,3677,3681,3685],{"title":3582,"path":3583,"stem":3584},"React Native — навіщо він потрібен","\u002Freact-native\u002Fversion2\u002Fwhy-react-native","15.react-native\u002Fversion2\u002F01.why-react-native",{"title":3586,"path":3587,"stem":3588},"Налаштування середовища розробки","\u002Freact-native\u002Fversion2\u002Fenvironment-setup","15.react-native\u002Fversion2\u002F02.environment-setup",{"title":3590,"path":3591,"stem":3592},"Expo і класичний React Native — два шляхи одного фреймворку","\u002Freact-native\u002Fversion2\u002Fexpo-vs-cli-landscape","15.react-native\u002Fversion2\u002F03.expo-vs-cli-landscape",{"title":3594,"path":3595,"stem":3596},"Середовище Expo — перший запуск","\u002Freact-native\u002Fversion2\u002Fexpo-setup-and-tooling","15.react-native\u002Fversion2\u002F04.expo-setup-and-tooling",{"title":3598,"path":3599,"stem":3600},"Структура проєкту та перші UI-примітиви","\u002Freact-native\u002Fversion2\u002Fproject-structure-and-conventions","15.react-native\u002Fversion2\u002F05.project-structure-and-conventions",{"title":3602,"path":3603,"stem":3604},"Базові компоненти React Native","\u002Freact-native\u002Fversion2\u002Fcore-components","15.react-native\u002Fversion2\u002F06.core-components",{"title":3606,"path":3607,"stem":3608},"Flexbox і layout у React Native","\u002Freact-native\u002Fversion2\u002Fflexbox-and-layout","15.react-native\u002Fversion2\u002F07.flexbox-and-layout",{"title":3610,"path":3611,"stem":3612},"StyleSheet і теми (light \u002F dark)","\u002Freact-native\u002Fversion2\u002Fstylesheet-and-theming","15.react-native\u002Fversion2\u002F08.stylesheet-and-theming",{"title":3614,"path":3615,"stem":3616},"Списки та віртуалізація","\u002Freact-native\u002Fversion2\u002Flists-and-virtualization","15.react-native\u002Fversion2\u002F09.lists-and-virtualization",{"title":3618,"path":3619,"stem":3620},"Форми, ввід і валідація","\u002Freact-native\u002Fversion2\u002Fforms-input-validation","15.react-native\u002Fversion2\u002F10.forms-input-validation",{"title":3622,"path":3623,"stem":3624},"Основи Expo Router","\u002Freact-native\u002Fversion2\u002Fexpo-router-basics","15.react-native\u002Fversion2\u002F11.expo-router-basics",{"title":3626,"path":3627,"stem":3628},"Вкладені навігатори та модалки","\u002Freact-native\u002Fversion2\u002Fnested-navigators-and-modals","15.react-native\u002Fversion2\u002F12.nested-navigators-and-modals",{"title":3630,"path":3631,"stem":3632},"Deep linking і параметри маршрутів","\u002Freact-native\u002Fversion2\u002Fdeep-linking-and-params","15.react-native\u002Fversion2\u002F13.deep-linking-and-params",{"title":3634,"path":3635,"stem":3636},"Робота з мережею та життєвий цикл застосунку","\u002Freact-native\u002Fversion2\u002Fnetworking-and-app-lifecycle","15.react-native\u002Fversion2\u002F14.networking-and-app-lifecycle",{"title":3638,"path":3639,"stem":3640},"Redux Toolkit на мобільних платформах","\u002Freact-native\u002Fversion2\u002Fredux-toolkit-on-mobile","15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile",{"title":3642,"path":3643,"stem":3644},"RTK Query на мобільних платформах","\u002Freact-native\u002Fversion2\u002Frtk-query-mobile","15.react-native\u002Fversion2\u002F16.rtk-query-mobile",{"title":3646,"path":3647,"stem":3648},"Автентифікація та Безпечне Зберігання","\u002Freact-native\u002Fversion2\u002Fauth-secure-storage","15.react-native\u002Fversion2\u002F18.auth-secure-storage",{"title":3650,"path":3651,"stem":3652},"Локальне сховище — AsyncStorage, MMKV, SQLite","\u002Freact-native\u002Fversion2\u002Flocal-storage-mmkv-sqlite","15.react-native\u002Fversion2\u002F19.local-storage-mmkv-sqlite",{"title":3654,"path":3655,"stem":3656},"Офлайн-First і синхронізація","\u002Freact-native\u002Fversion2\u002Foffline-first-sync","15.react-native\u002Fversion2\u002F20.offline-first-sync",{"title":3658,"path":3659,"stem":3660},"Камера, медіа та файлова система","\u002Freact-native\u002Fversion2\u002Fcamera-media-filesystem","15.react-native\u002Fversion2\u002F21.camera-media-filesystem",{"title":3662,"path":3663,"stem":3664},"Карти та геолокація","\u002Freact-native\u002Fversion2\u002Fmaps-and-location","15.react-native\u002Fversion2\u002F22.maps-and-location",{"title":3666,"path":3667,"stem":3668},"Жести та дотики","\u002Freact-native\u002Fversion2\u002Fgestures-and-touch","15.react-native\u002Fversion2\u002F23.gestures-and-touch",{"title":3670,"path":3671,"stem":3672},"Анімації з Reanimated","\u002Freact-native\u002Fversion2\u002Freanimated-animations","15.react-native\u002Fversion2\u002F24.reanimated-animations",{"title":3674,"path":3675,"stem":3676},"Push і локальні сповіщення","\u002Freact-native\u002Fversion2\u002Fpush-and-local-notifications","15.react-native\u002Fversion2\u002F25.push-and-local-notifications",{"title":3678,"path":3679,"stem":3680},"Інтернаціоналізація та доступність","\u002Freact-native\u002Fversion2\u002Faccessibility-and-i18n","15.react-native\u002Fversion2\u002F26.accessibility-and-i18n",{"title":3682,"path":3683,"stem":3684},"EAS Build та профілі збірки","\u002Freact-native\u002Fversion2\u002Feas-build-and-profiles","15.react-native\u002Fversion2\u002F29.eas-build-and-profiles",{"title":3686,"path":3687,"stem":3688},"Публікація в App Store та Google Play","\u002Freact-native\u002Fversion2\u002Fapp-store-play-release","15.react-native\u002Fversion2\u002F30.app-store-play-release",{"title":3690,"path":3691,"stem":3692,"children":3693,"page":59},"Ai Python","\u002Fai-python","16.ai-python",[3694,3703,3712,3721,3750,3776,3801,3834,3851,3864,3873,3886,3895,3916,3929,3950],{"title":3695,"path":3696,"stem":3697,"children":3698,"page":59},"Intro To Ai","\u002Fai-python\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai",[3699],{"title":3700,"path":3701,"stem":3702},"Вступ до штучного інтелекту та машинного навчання","\u002Fai-python\u002Fintro-to-ai\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai\u002F01.intro-to-ai",{"title":3704,"path":3705,"stem":3706,"children":3707,"page":59},"Jupyter Notebook","\u002Fai-python\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook",[3708],{"title":3709,"path":3710,"stem":3711},"Знайомство з Jupyter Notebook та JupyterLab","\u002Fai-python\u002Fjupyter-notebook\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook\u002F02.jupyter-notebook",{"title":3713,"path":3714,"stem":3715,"children":3716,"page":59},"Numpy Pandas","\u002Fai-python\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas",[3717],{"title":3718,"path":3719,"stem":3720},"Робота з даними з використанням NumPy і pandas","\u002Fai-python\u002Fnumpy-pandas\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas\u002F03.numpy-pandas",{"title":3722,"path":3723,"stem":3724,"children":3725,"page":59},"Statistics Basics","\u002Fai-python\u002Fstatistics-basics","16.ai-python\u002F04.statistics-basics",[3726,3730,3734,3738,3742,3746],{"title":3727,"path":3728,"stem":3729},"Випадкові величини та їх типи","\u002Fai-python\u002Fstatistics-basics\u002Frandom-variables","16.ai-python\u002F04.statistics-basics\u002F01.random-variables",{"title":3731,"path":3732,"stem":3733},"Міри центральної тенденції","\u002Fai-python\u002Fstatistics-basics\u002Fcentral-tendency","16.ai-python\u002F04.statistics-basics\u002F02.central-tendency",{"title":3735,"path":3736,"stem":3737},"Міри варіації (розсіювання)","\u002Fai-python\u002Fstatistics-basics\u002Fvariability","16.ai-python\u002F04.statistics-basics\u002F03.variability",{"title":3739,"path":3740,"stem":3741},"Розподіли випадкових величин","\u002Fai-python\u002Fstatistics-basics\u002Fdistributions","16.ai-python\u002F04.statistics-basics\u002F04.distributions",{"title":3743,"path":3744,"stem":3745},"Кореляція та взаємозв'язки","\u002Fai-python\u002Fstatistics-basics\u002Fcorrelation","16.ai-python\u002F04.statistics-basics\u002F05.correlation",{"title":3747,"path":3748,"stem":3749},"Викиди та аномалії","\u002Fai-python\u002Fstatistics-basics\u002Foutliers","16.ai-python\u002F04.statistics-basics\u002F06.outliers",{"title":3751,"path":3752,"stem":3753,"children":3754},"Візуалізація даних за допомогою matplotlib","\u002Fai-python\u002Fdata-visualization","16.ai-python\u002F05.data-visualization\u002Findex",[3755,3756,3760,3764,3768,3772],{"title":3751,"path":3752,"stem":3753},{"title":3757,"path":3758,"stem":3759},"Основи matplotlib — Figure, Axes та перший графік","\u002Fai-python\u002Fdata-visualization\u002Fmatplotlib-basics","16.ai-python\u002F05.data-visualization\u002F01.matplotlib-basics",{"title":3761,"path":3762,"stem":3763},"Візуалізація розподілів — гістограми та box plots","\u002Fai-python\u002Fdata-visualization\u002Fdistributions","16.ai-python\u002F05.data-visualization\u002F02.distributions",{"title":3765,"path":3766,"stem":3767},"Візуалізація залежностей — scatter plots та кореляція","\u002Fai-python\u002Fdata-visualization\u002Frelationships","16.ai-python\u002F05.data-visualization\u002F03.relationships",{"title":3769,"path":3770,"stem":3771},"Візуалізація категоріальних даних — bar charts та pie charts","\u002Fai-python\u002Fdata-visualization\u002Fcategorical","16.ai-python\u002F05.data-visualization\u002F04.categorical",{"title":3773,"path":3774,"stem":3775},"Композиції та стилізація — subplots та багатопанельні дашборди","\u002Fai-python\u002Fdata-visualization\u002Fsubplots-styling","16.ai-python\u002F05.data-visualization\u002F05.subplots-styling",{"title":3777,"path":3778,"stem":3779,"children":3780,"page":59},"Linear Regression","\u002Fai-python\u002Flinear-regression","16.ai-python\u002F06.linear-regression",[3781,3785,3789,3793,3797],{"title":3782,"path":3783,"stem":3784},"Регресійна задача та лінійна регресія з однією змінною","\u002Fai-python\u002Flinear-regression\u002Fregression-task","16.ai-python\u002F06.linear-regression\u002F01.regression-task",{"title":3786,"path":3787,"stem":3788},"Метрики якості регресії — як оцінити модель","\u002Fai-python\u002Flinear-regression\u002Fquality-metrics","16.ai-python\u002F06.linear-regression\u002F02.quality-metrics",{"title":3790,"path":3791,"stem":3792},"Градієнтний спуск — як модель навчається","\u002Fai-python\u002Flinear-regression\u002Fgradient-descent","16.ai-python\u002F06.linear-regression\u002F03.gradient-descent",{"title":3794,"path":3795,"stem":3796},"Множинна лінійна регресія — модель з багатьма ознаками","\u002Fai-python\u002Flinear-regression\u002Fmultiple-regression","16.ai-python\u002F06.linear-regression\u002F04.multiple-regression",{"title":3798,"path":3799,"stem":3800},"Практичні завдання та резюме модуля","\u002Fai-python\u002Flinear-regression\u002Fpractice","16.ai-python\u002F06.linear-regression\u002F05.practice",{"title":3802,"path":3803,"stem":3804,"children":3805,"page":59},"Practical Regression","\u002Fai-python\u002Fpractical-regression","16.ai-python\u002F07.practical-regression",[3806,3810,3814,3818,3822,3826,3830],{"title":3807,"path":3808,"stem":3809},"Знайомство з scikit-learn","\u002Fai-python\u002Fpractical-regression\u002Fintro-scikit-learn","16.ai-python\u002F07.practical-regression\u002F01.intro-scikit-learn",{"title":3811,"path":3812,"stem":3813},"Exploratory Data Analysis датасету Housing Prices","\u002Fai-python\u002Fpractical-regression\u002Fhousing-dataset-eda","16.ai-python\u002F07.practical-regression\u002F02.housing-dataset-eda",{"title":3815,"path":3816,"stem":3817},"Попередня обробка даних (Data Preprocessing)","\u002Fai-python\u002Fpractical-regression\u002Fdata-preprocessing","16.ai-python\u002F07.practical-regression\u002F03.data-preprocessing",{"title":3819,"path":3820,"stem":3821},"Train\u002FTest Split та перша повноцінна модель","\u002Fai-python\u002Fpractical-regression\u002Ftrain-test-split","16.ai-python\u002F07.practical-regression\u002F04.train-test-split",{"title":3823,"path":3824,"stem":3825},"Перенавчання та недонавчання","\u002Fai-python\u002Fpractical-regression\u002Foverfitting-underfitting","16.ai-python\u002F07.practical-regression\u002F05.overfitting-underfitting",{"title":3827,"path":3828,"stem":3829},"Крос-валідація (Cross-Validation)","\u002Fai-python\u002Fpractical-regression\u002Fcross-validation","16.ai-python\u002F07.practical-regression\u002F06.cross-validation",{"title":3831,"path":3832,"stem":3833},"Гіперпараметри та їх оптимізація","\u002Fai-python\u002Fpractical-regression\u002Fhyperparameter-tuning","16.ai-python\u002F07.practical-regression\u002F07.hyperparameter-tuning",{"title":3835,"path":3836,"stem":3837,"children":3838,"page":59},"Polynomial Regression","\u002Fai-python\u002Fpolynomial-regression","16.ai-python\u002F08.polynomial-regression",[3839,3843,3847],{"title":3840,"path":3841,"stem":3842},"Нелінійні залежності та поліноміальна регресія","\u002Fai-python\u002Fpolynomial-regression\u002Fnonlinear-patterns","16.ai-python\u002F08.polynomial-regression\u002F01.nonlinear-patterns",{"title":3844,"path":3845,"stem":3846},"Регуляризація в регресії — Ridge та Lasso","\u002Fai-python\u002Fpolynomial-regression\u002Fregularization-methods","16.ai-python\u002F08.polynomial-regression\u002F02.regularization-methods",{"title":3848,"path":3849,"stem":3850},"Практика — поліноміальна регресія та регуляризація на Housing Prices","\u002Fai-python\u002Fpolynomial-regression\u002Fhousing-prices-practice","16.ai-python\u002F08.polynomial-regression\u002F03.housing-prices-practice",{"title":3852,"path":3853,"stem":3854,"children":3855,"page":59},"Decision Trees Random Forest","\u002Fai-python\u002Fdecision-trees-random-forest","16.ai-python\u002F09.decision-trees-random-forest",[3856,3860],{"title":3857,"path":3858,"stem":3859},"Дерева рішень — моделі з прозорою та зрозумілою логікою","\u002Fai-python\u002Fdecision-trees-random-forest\u002Fdecision-trees","16.ai-python\u002F09.decision-trees-random-forest\u002F01.decision-trees",{"title":3861,"path":3862,"stem":3863},"Random Forest — ансамблі дерев рішень","\u002Fai-python\u002Fdecision-trees-random-forest\u002Frandom-forest","16.ai-python\u002F09.decision-trees-random-forest\u002F02.random-forest",{"title":3865,"path":3866,"stem":3867,"children":3868,"page":59},"Gradient Boosting","\u002Fai-python\u002Fgradient-boosting","16.ai-python\u002F10.gradient-boosting",[3869],{"title":3870,"path":3871,"stem":3872},"Градієнтний бустинг та XGBoost — послідовне виправлення помилок","\u002Fai-python\u002Fgradient-boosting\u002Fgradient-boosting-xgboost","16.ai-python\u002F10.gradient-boosting\u002F01.gradient-boosting-xgboost",{"title":3874,"path":3875,"stem":3876,"children":3877,"page":59},"Logistic Regression Classification","\u002Fai-python\u002Flogistic-regression-classification","16.ai-python\u002F11.logistic-regression-classification",[3878,3882],{"title":3879,"path":3880,"stem":3881},"Основи класифікації та логістична регресія","\u002Fai-python\u002Flogistic-regression-classification\u002Fclassification-basics","16.ai-python\u002F11.logistic-regression-classification\u002F01.classification-basics",{"title":3883,"path":3884,"stem":3885},"Метрики якості класифікації","\u002Fai-python\u002Flogistic-regression-classification\u002Fclassification-metrics","16.ai-python\u002F11.logistic-regression-classification\u002F02.classification-metrics",{"title":3887,"path":3888,"stem":3889,"children":3890,"page":59},"Neural Networks Basics","\u002Fai-python\u002Fneural-networks-basics","16.ai-python\u002F12.neural-networks-basics",[3891],{"title":3892,"path":3893,"stem":3894},"Вступ до нейронних мереж — від персептрона до багатошарових мереж","\u002Fai-python\u002Fneural-networks-basics\u002Fperceptron-to-mlp","16.ai-python\u002F12.neural-networks-basics\u002F01.perceptron-to-mlp",{"title":3896,"path":3897,"stem":3898,"children":3899,"page":59},"Pytorch Intro","\u002Fai-python\u002Fpytorch-intro","16.ai-python\u002F13.pytorch-intro",[3900,3904,3908,3912],{"title":3901,"path":3902,"stem":3903},"Тензори та автоматичне диференціювання в PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Ftensors-and-autograd","16.ai-python\u002F13.pytorch-intro\u002F01.tensors-and-autograd",{"title":3905,"path":3906,"stem":3907},"Побудова та тренування нейронних мереж у PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Fbuilding-and-training","16.ai-python\u002F13.pytorch-intro\u002F02.building-and-training",{"title":3909,"path":3910,"stem":3911},"Робота з даними та регуляризація в PyTorch","\u002Fai-python\u002Fpytorch-intro\u002Fdata-and-regularization","16.ai-python\u002F13.pytorch-intro\u002F03.data-and-regularization",{"title":3913,"path":3914,"stem":3915},"Просунуті теми PyTorch — GPU, оптимізація та deployment","\u002Fai-python\u002Fpytorch-intro\u002Fadvanced-topics","16.ai-python\u002F13.pytorch-intro\u002F04.advanced-topics",{"title":3917,"path":3918,"stem":3919,"children":3920,"page":59},"Activation Functions Heart Disease","\u002Fai-python\u002Factivation-functions-heart-disease","16.ai-python\u002F14.activation-functions-heart-disease",[3921,3925],{"title":3922,"path":3923,"stem":3924},"Функції активації та побудова нейронної мережі для передбачення вад серця","\u002Fai-python\u002Factivation-functions-heart-disease\u002Fheart-disease-prediction","16.ai-python\u002F14.activation-functions-heart-disease\u002F01.heart-disease-prediction",{"title":3926,"path":3927,"stem":3928},"Бонус — Повний приклад Student Performance Prediction","\u002Fai-python\u002Factivation-functions-heart-disease\u002Fstudent-performance-bonus","16.ai-python\u002F14.activation-functions-heart-disease\u002F02.student-performance-bonus",{"title":3930,"path":3931,"stem":3932,"children":3933,"page":59},"Cnn Image Classification","\u002Fai-python\u002Fcnn-image-classification","16.ai-python\u002F15.cnn-image-classification",[3934,3938,3942,3946],{"title":3935,"path":3936,"stem":3937},"Основи згорткових нейронних мереж — чому не MLP?","\u002Fai-python\u002Fcnn-image-classification\u002Fcnn-fundamentals","16.ai-python\u002F15.cnn-image-classification\u002F01.cnn-fundamentals",{"title":3939,"path":3940,"stem":3941},"Практична імплементація CNN для класифікації MNIST","\u002Fai-python\u002Fcnn-image-classification\u002Fmnist-classification","16.ai-python\u002F15.cnn-image-classification\u002F02.mnist-classification",{"title":3943,"path":3944,"stem":3945},"Глибші CNN та аугментація даних для CIFAR-10","\u002Fai-python\u002Fcnn-image-classification\u002Fcifar10-and-data-augmentation","16.ai-python\u002F15.cnn-image-classification\u002F03.cifar10-and-data-augmentation",{"title":3947,"path":3948,"stem":3949},"Transfer Learning та візуалізація внутрішніх представлень CNN","\u002Fai-python\u002Fcnn-image-classification\u002Ftransfer-learning-and-visualization","16.ai-python\u002F15.cnn-image-classification\u002F04.transfer-learning-and-visualization",{"title":3951,"path":3952,"stem":3953,"children":3954,"page":59},"Batching Normalization Deep Networks","\u002Fai-python\u002Fbatching-normalization-deep-networks","16.ai-python\u002F16.batching-normalization-deep-networks",[3955,3959,3963,3967,3971,3975,3979],{"title":3956,"path":3957,"stem":3958},"Mini-batch Gradient Descent та ефективна обробка даних","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fmini-batch-gradient-descent","16.ai-python\u002F16.batching-normalization-deep-networks\u002F01.mini-batch-gradient-descent",{"title":3960,"path":3961,"stem":3962},"Ініціалізація ваг — фундамент стабільного навчання","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fweight-initialization","16.ai-python\u002F16.batching-normalization-deep-networks\u002F02.weight-initialization",{"title":3964,"path":3965,"stem":3966},"Batch Normalization — прорив у глибокому навчанні","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fbatch-normalization","16.ai-python\u002F16.batching-normalization-deep-networks\u002F03.batch-normalization",{"title":3968,"path":3969,"stem":3970},"Dropout та комбіновані стратегії регуляризації","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fdropout-and-regularization","16.ai-python\u002F16.batching-normalization-deep-networks\u002F04.dropout-and-regularization",{"title":3972,"path":3973,"stem":3974},"Проєктування глибоких мереж — від теорії до практики","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Fdeep-networks-architectures","16.ai-python\u002F16.batching-normalization-deep-networks\u002F05.deep-networks-architectures",{"title":3976,"path":3977,"stem":3978},"Планування learning rate — коли та як зменшувати крок навчання","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Flearning-rate-scheduling","16.ai-python\u002F16.batching-normalization-deep-networks\u002F06.learning-rate-scheduling",{"title":3980,"path":3981,"stem":3982},"Підсумковий проєкт — побудова сучасного класифікатора зображень","\u002Fai-python\u002Fbatching-normalization-deep-networks\u002Ffinal-project-deep-classifier","16.ai-python\u002F16.batching-normalization-deep-networks\u002F07.final-project-deep-classifier",{"title":3984,"icon":658,"path":3985,"stem":3986,"children":3987,"page":59},"Клієнт-серверна архітектура","\u002Fclient-server-architecture","17.client-server-architecture",[3988,3992,3996,4000,4004,4008,4012,4016,4020,4024,4028,4032,4036,4040,4044,4048,4052,4056],{"title":3989,"path":3990,"stem":3991},"Архітектура клієнт-серверних систем та основи Go","\u002Fclient-server-architecture\u002Fclient-server-architecture-and-go","17.client-server-architecture\u002F01.client-server-architecture-and-go",{"title":3993,"path":3994,"stem":3995},"Система типів та модель пам’яті мови Go","\u002Fclient-server-architecture\u002Ftype-system-and-memory-model","17.client-server-architecture\u002F02.type-system-and-memory-model",{"title":3997,"path":3998,"stem":3999},"Інтерфейси та модель конкурентності мови Go","\u002Fclient-server-architecture\u002Finterfaces-and-concurrency-model","17.client-server-architecture\u002F03.interfaces-and-concurrency-model",{"title":4001,"path":4002,"stem":4003},"Сокетне програмування та протокол TCP у Go","\u002Fclient-server-architecture\u002Ftcp-socket-programming","17.client-server-architecture\u002F04.tcp-socket-programming",{"title":4005,"path":4006,"stem":4007},"Протокол UDP та датаграмна передача даних","\u002Fclient-server-architecture\u002Fudp-datagram-transmission","17.client-server-architecture\u002F05.udp-datagram-transmission",{"title":4009,"path":4010,"stem":4011},"Криптографічний захист каналів зв","\u002Fclient-server-architecture\u002Ftls-cryptographic-channel-protection","17.client-server-architecture\u002F06.tls-cryptographic-channel-protection",{"title":4013,"path":4014,"stem":4015},"Прикладні мережеві протоколи DNS та SMTP","\u002Fclient-server-architecture\u002Fdns-smtp-application-protocols","17.client-server-architecture\u002F07.dns-smtp-application-protocols",{"title":4017,"path":4018,"stem":4019},"Протокол HTTP та стандартний вебсервер Go","\u002Fclient-server-architecture\u002Fhttp-protocol-and-web-server","17.client-server-architecture\u002F08.http-protocol-and-web-server",{"title":4021,"path":4022,"stem":4023},"Проєктування REST API та маршрутизація засобами Chi","\u002Fclient-server-architecture\u002Frest-api-design-and-chi-routing","17.client-server-architecture\u002F09.rest-api-design-and-chi-routing",{"title":4025,"path":4026,"stem":4027},"Лекція 10. Шарувата архітектура та конвеєри обробки запитів","\u002Fclient-server-architecture\u002Flayered-architecture-and-middleware-pipelines","17.client-server-architecture\u002F10.layered-architecture-and-middleware-pipelines",{"title":4029,"path":4030,"stem":4031},"Лекція 11. Архітектура та маршрутизація фреймворку Gin","\u002Fclient-server-architecture\u002Fgin-framework-architecture-and-routing","17.client-server-architecture\u002F11.gin-framework-architecture-and-routing",{"title":4033,"path":4034,"stem":4035},"Лекція 12. Валідація даних, безпека та документування у Gin","\u002Fclient-server-architecture\u002Fdata-validation-security-and-documentation-in-gin","17.client-server-architecture\u002F12.data-validation-security-and-documentation-in-gin",{"title":4037,"path":4038,"stem":4039},"Лекція 13. Взаємодія з реляційними СУБД та технології ORM","\u002Fclient-server-architecture\u002Frelational-databases-and-orm","17.client-server-architecture\u002F13.relational-databases-and-orm",{"title":4041,"path":4042,"stem":4043},"Потокова передача даних та протокол WebSocket","\u002Fclient-server-architecture\u002Fstreaming-data-and-websockets","17.client-server-architecture\u002F14.streaming-data-and-websockets",{"title":4045,"path":4046,"stem":4047},"Міжсервісна взаємодія на основі протоколу gRPC","\u002Fclient-server-architecture\u002Fgrpc-inter-service-communication","17.client-server-architecture\u002F15.grpc-inter-service-communication",{"title":4049,"path":4050,"stem":4051},"Асинхронний обмін повідомленнями та протоколи черг","\u002Fclient-server-architecture\u002Fasynchronous-message-exchange-and-queue-protocols","17.client-server-architecture\u002F16.asynchronous-message-exchange-and-queue-protocols",{"title":4053,"path":4054,"stem":4055},"Протоколи потокового медіа та технологія WebRTC","\u002Fclient-server-architecture\u002Fstreaming-media-protocols-and-webrtc","17.client-server-architecture\u002F17.streaming-media-protocols-and-webrtc",{"title":4057,"path":4058,"stem":4059},"Моніторинг, безпека та контейнеризація застосунків","\u002Fclient-server-architecture\u002Fmonitoring-security-and-containerization","17.client-server-architecture\u002F18.monitoring-security-and-containerization",{"title":4061,"icon":2118,"path":4062,"stem":4063,"children":4064,"page":59},"Розробка WEB-застосувань","\u002Fweb-development","18.web-development",[4065,4110,4148,4177,4206,4263,4313,4407,4473,4555,4588,4616,4658,4704,4747],{"title":4066,"icon":658,"path":4067,"stem":4068,"children":4069,"page":59},"Архітектура комп'ютерних мереж та мережеві протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols","18.web-development\u002F01.network-architecture-and-protocols",[4070,4074,4078,4082,4086,4090,4094,4098,4102,4106],{"title":4071,"path":4072,"stem":4073},"Еволюція веброзробки та модель клієнт-сервер","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fweb-evolution-client-server","18.web-development\u002F01.network-architecture-and-protocols\u002F01.web-evolution-client-server",{"title":4075,"path":4076,"stem":4077},"Еталонна модель OSI","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fosi-model","18.web-development\u002F01.network-architecture-and-protocols\u002F02.osi-model",{"title":4079,"path":4080,"stem":4081},"Стек протоколів TCP\u002FIP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-ip-stack","18.web-development\u002F01.network-architecture-and-protocols\u002F03.tcp-ip-stack",{"title":4083,"path":4084,"stem":4085},"IP-адресація, порти та сокети","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fip-addressing-ports-sockets","18.web-development\u002F01.network-architecture-and-protocols\u002F04.ip-addressing-ports-sockets",{"title":4087,"path":4088,"stem":4089},"Протоколи TCP та UDP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-udp-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F05.tcp-udp-protocols",{"title":4091,"path":4092,"stem":4093},"Система доменних імен DNS","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fdns-system","18.web-development\u002F01.network-architecture-and-protocols\u002F06.dns-system",{"title":4095,"path":4096,"stem":4097},"Протокол SMTP та поштові протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fsmtp-email-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F07.smtp-email-protocols",{"title":4099,"path":4100,"stem":4101},"Протокол WebSocket","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fwebsocket-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F08.websocket-protocol",{"title":4103,"path":4104,"stem":4105},"Протокол SSH","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fssh-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F09.ssh-protocol",{"title":4107,"path":4108,"stem":4109},"Огляд сучасних серверних технологій","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fmodern-backend-technologies","18.web-development\u002F01.network-architecture-and-protocols\u002F10.modern-backend-technologies",{"title":4111,"icon":4112,"path":4113,"stem":4114,"children":4115,"page":59},"Протокол HTTP та захищена передача даних HTTPS","i-lucide-lock","\u002Fweb-development\u002Fhttp-and-https","18.web-development\u002F02.http-and-https",[4116,4120,4124,4128,4132,4136,4140,4144],{"title":4117,"path":4118,"stem":4119},"Вступ до протоколу HTTP та еволюція веб-технологій","\u002Fweb-development\u002Fhttp-and-https\u002Fintroduction-and-evolution","18.web-development\u002F02.http-and-https\u002F01.introduction-and-evolution",{"title":4121,"path":4122,"stem":4123},"Анатомія HTTP-запиту","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-request-structure","18.web-development\u002F02.http-and-https\u002F02.http-request-structure",{"title":4125,"path":4126,"stem":4127},"Анатомія HTTP-відповіді","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-response-structure","18.web-development\u002F02.http-and-https\u002F03.http-response-structure",{"title":4129,"path":4130,"stem":4131},"Методи HTTP та їхня семантика","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-methods","18.web-development\u002F02.http-and-https\u002F04.http-methods",{"title":4133,"path":4134,"stem":4135},"Коди статусу HTTP та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-status-codes","18.web-development\u002F02.http-and-https\u002F05.http-status-codes",{"title":4137,"path":4138,"stem":4139},"HTTP-заголовки та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-headers","18.web-development\u002F02.http-and-https\u002F06.http-headers",{"title":4141,"path":4142,"stem":4143},"CORS та механізми безпеки HTTP","\u002Fweb-development\u002Fhttp-and-https\u002Fcors-and-security","18.web-development\u002F02.http-and-https\u002F07.cors-and-security",{"title":4145,"path":4146,"stem":4147},"HTTPS та криптографічні основи TLS","\u002Fweb-development\u002Fhttp-and-https\u002Fhttps-and-tls","18.web-development\u002F02.http-and-https\u002F08.https-and-tls",{"title":4149,"icon":2498,"path":4150,"stem":4151,"children":4152,"page":59},"Система типів мови TypeScript","\u002Fweb-development\u002Ftypescript-type-system","18.web-development\u002F03.typescript-type-system",[4153,4157,4161,4165,4169,4173],{"title":4154,"path":4155,"stem":4156},"Знайомство з TypeScript Compiler","\u002Fweb-development\u002Ftypescript-type-system\u002Fintroduction-compiler-config","18.web-development\u002F03.typescript-type-system\u002F01.introduction-compiler-config",{"title":4158,"path":4159,"stem":4160},"Примітивні типи даних: string, number, boolean","\u002Fweb-development\u002Ftypescript-type-system\u002Fprimitive-special-types","18.web-development\u002F03.typescript-type-system\u002F02.primitive-special-types",{"title":4162,"path":4163,"stem":4164},"Масиви, кортежі та об","\u002Fweb-development\u002Ftypescript-type-system\u002Farrays-tuples-objects","18.web-development\u002F03.typescript-type-system\u002F03.arrays-tuples-objects",{"title":4166,"path":4167,"stem":4168},"Псевдоніми типів, Union типи, Intersection типи та літеральні типи","\u002Fweb-development\u002Ftypescript-type-system\u002Funion-intersection-literals","18.web-development\u002F03.typescript-type-system\u002F04.union-intersection-literals",{"title":4170,"path":4171,"stem":4172},"Type Narrowing (звуження типів)","\u002Fweb-development\u002Ftypescript-type-system\u002Ftype-narrowing","18.web-development\u002F03.typescript-type-system\u002F05.type-narrowing",{"title":4174,"path":4175,"stem":4176},"Типізація функцій","\u002Fweb-development\u002Ftypescript-type-system\u002Ffunctions-typing","18.web-development\u002F03.typescript-type-system\u002F06.functions-typing",{"title":4178,"icon":2498,"path":4179,"stem":4180,"children":4181,"page":59},"Розширені засоби мови TypeScript","\u002Fweb-development\u002Ftypescript-advanced","18.web-development\u002F04.typescript-advanced",[4182,4186,4190,4194,4198,4202],{"title":4183,"path":4184,"stem":4185},"Interfaces та Classes","\u002Fweb-development\u002Ftypescript-advanced\u002Finterfaces-classes","18.web-development\u002F04.typescript-advanced\u002F01.interfaces-classes",{"title":4187,"path":4188,"stem":4189},"Основи Generic типів","\u002Fweb-development\u002Ftypescript-advanced\u002Fgenerics-fundamentals","18.web-development\u002F04.typescript-advanced\u002F02.generics-fundamentals",{"title":4191,"path":4192,"stem":4193},"Enums та Decorators","\u002Fweb-development\u002Ftypescript-advanced\u002Fenums-decorators","18.web-development\u002F04.typescript-advanced\u002F03.enums-decorators",{"title":4195,"path":4196,"stem":4197},"Utility Types","\u002Fweb-development\u002Ftypescript-advanced\u002Futility-types","18.web-development\u002F04.typescript-advanced\u002F04.utility-types",{"title":4199,"path":4200,"stem":4201},"Mapped та Conditional Types","\u002Fweb-development\u002Ftypescript-advanced\u002Fmapped-conditional-types","18.web-development\u002F04.typescript-advanced\u002F05.mapped-conditional-types",{"title":4203,"path":4204,"stem":4205},"Модулі та Strict Mode","\u002Fweb-development\u002Ftypescript-advanced\u002Fmodules-strict-mode","18.web-development\u002F04.typescript-advanced\u002F06.modules-strict-mode",{"title":4207,"icon":4208,"path":4209,"stem":4210,"children":4211,"page":59},"Платформа Node.js як середовище виконання","i-devicon-nodejs","\u002Fweb-development\u002Fnodejs-platform","18.web-development\u002F05.nodejs-platform",[4212,4216,4220,4224,4228,4232,4236,4240,4244,4248,4252,4255,4259],{"title":4213,"path":4214,"stem":4215},"Що таке Node.js та його архітектура","\u002Fweb-development\u002Fnodejs-platform\u002Fwhat-is-nodejs","18.web-development\u002F05.nodejs-platform\u002F01.what-is-nodejs",{"title":4217,"path":4218,"stem":4219},"Event Loop — серце Node.js","\u002Fweb-development\u002Fnodejs-platform\u002Fevent-loop","18.web-development\u002F05.nodejs-platform\u002F02.event-loop",{"title":4221,"path":4222,"stem":4223},"Модульні системи: CommonJS vs ES Modules","\u002Fweb-development\u002Fnodejs-platform\u002Fmodule-systems","18.web-development\u002F05.nodejs-platform\u002F03.module-systems",{"title":4225,"path":4226,"stem":4227},"npm та package.json","\u002Fweb-development\u002Fnodejs-platform\u002Fnpm-package-json","18.web-development\u002F05.nodejs-platform\u002F04.npm-package-json",{"title":4229,"path":4230,"stem":4231},"Глобальні об\\","\u002Fweb-development\u002Fnodejs-platform\u002Fglobal-objects","18.web-development\u002F05.nodejs-platform\u002F05.global-objects",{"title":4233,"path":4234,"stem":4235},"Вбудований модуль fs (File System)","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-fs","18.web-development\u002F05.nodejs-platform\u002F06.built-in-modules-fs",{"title":4237,"path":4238,"stem":4239},"Вбудований модуль path","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-path","18.web-development\u002F05.nodejs-platform\u002F07.built-in-modules-path",{"title":4241,"path":4242,"stem":4243},"Вбудований модуль http","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-http","18.web-development\u002F05.nodejs-platform\u002F08.built-in-modules-http",{"title":4245,"path":4246,"stem":4247},"Streams — потоки даних у Node.js","\u002Fweb-development\u002Fnodejs-platform\u002Fstreams","18.web-development\u002F05.nodejs-platform\u002F09.streams",{"title":4249,"path":4250,"stem":4251},"Вбудований модуль util (Utilities)","\u002Fweb-development\u002Fnodejs-platform\u002Fbuilt-in-modules-util","18.web-development\u002F05.nodejs-platform\u002F10.built-in-modules-util",{"title":3141,"path":4253,"stem":4254},"\u002Fweb-development\u002Fnodejs-platform\u002Fenvironment-variables","18.web-development\u002F05.nodejs-platform\u002F11.environment-variables",{"title":4256,"path":4257,"stem":4258},"Інструменти налагодження та розробки","\u002Fweb-development\u002Fnodejs-platform\u002Fdebugging-tools","18.web-development\u002F05.nodejs-platform\u002F12.debugging-tools",{"title":4260,"path":4261,"stem":4262},"Продуктивність та Best Practices","\u002Fweb-development\u002Fnodejs-platform\u002Fperformance-best-practices","18.web-development\u002F05.nodejs-platform\u002F13.performance-best-practices",{"title":4264,"icon":4265,"path":4266,"stem":4267,"children":4268,"page":59},"Асинхронне програмування у Node.js","i-lucide-clock","\u002Fweb-development\u002Fasync-programming-nodejs","18.web-development\u002F06.async-programming-nodejs",[4269,4273,4277,4281,4285,4289,4293,4297,4301,4305,4309],{"title":4270,"path":4271,"stem":4272},"Синхронний vs асинхронний код","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fsync-vs-async","18.web-development\u002F06.async-programming-nodejs\u002F01.sync-vs-async",{"title":4274,"path":4275,"stem":4276},"Callbacks — перша парадигма асинхронності","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fcallbacks","18.web-development\u002F06.async-programming-nodejs\u002F02.callbacks",{"title":4278,"path":4279,"stem":4280},"Promises — стандарт асинхронності","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fpromises","18.web-development\u002F06.async-programming-nodejs\u002F03.promises",{"title":4282,"path":4283,"stem":4284},"Promise комбінатори","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fpromise-combinators","18.web-development\u002F06.async-programming-nodejs\u002F04.promise-combinators",{"title":4286,"path":4287,"stem":4288},"Async\u002FAwait — синтаксичний цукор над Promises","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fasync-await","18.web-development\u002F06.async-programming-nodejs\u002F05.async-await",{"title":4290,"path":4291,"stem":4292},"Паралельне vs послідовне виконання","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fparallel-vs-sequential","18.web-development\u002F06.async-programming-nodejs\u002F06.parallel-vs-sequential",{"title":4294,"path":4295,"stem":4296},"EventEmitter — подієва модель Node.js","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fevent-emitter","18.web-development\u002F06.async-programming-nodejs\u002F07.event-emitter",{"title":4298,"path":4299,"stem":4300},"Worker Threads — багатопотоковість у Node.js","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fworker-threads","18.web-development\u002F06.async-programming-nodejs\u002F08.worker-threads",{"title":4302,"path":4303,"stem":4304},"Child Processes — запуск зовнішніх процесів","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fchild-processes","18.web-development\u002F06.async-programming-nodejs\u002F09.child-processes",{"title":4306,"path":4307,"stem":4308},"Обробка помилок у асинхронному коді","\u002Fweb-development\u002Fasync-programming-nodejs\u002Ferror-handling","18.web-development\u002F06.async-programming-nodejs\u002F10.error-handling",{"title":4310,"path":4311,"stem":4312},"Порівняння Node.js фреймворків","\u002Fweb-development\u002Fasync-programming-nodejs\u002Fnodejs-frameworks","18.web-development\u002F06.async-programming-nodejs\u002F11.nodejs-frameworks",{"title":4314,"icon":4315,"path":4316,"stem":4317,"children":4318,"page":59},"Тема 7. Фреймворк NestJS. Контролери та маршрутизація","i-lucide-route","\u002Fweb-development\u002Fnestjs-controllers-routing","18.web-development\u002F07.nestjs-controllers-routing",[4319,4323,4327,4331,4335,4339,4343,4347,4351,4355,4359,4363,4367,4371,4375,4379,4383,4387,4391,4395,4399,4403],{"title":4320,"path":4321,"stem":4322},"Філософія та архітектура NestJS","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-philosophy","18.web-development\u002F07.nestjs-controllers-routing\u002F01.nestjs-philosophy",{"title":4324,"path":4325,"stem":4326},"Три стовпи архітектури: модулі, контролери, провайдери","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fthree-pillars","18.web-development\u002F07.nestjs-controllers-routing\u002F02.three-pillars",{"title":4328,"path":4329,"stem":4330},"Інверсія керування (IoC) та ін","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fioc-and-di","18.web-development\u002F07.nestjs-controllers-routing\u002F03.ioc-and-di",{"title":4332,"path":4333,"stem":4334},"Встановлення NestJS CLI та створення проєкту","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-cli-setup","18.web-development\u002F07.nestjs-controllers-routing\u002F04.nestjs-cli-setup",{"title":4336,"path":4337,"stem":4338},"Структура проєкту NestJS та конвенції","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fproject-structure","18.web-development\u002F07.nestjs-controllers-routing\u002F05.project-structure",{"title":4340,"path":4341,"stem":4342},"Контролери: основи маршрутизації","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcontrollers-basics","18.web-development\u002F07.nestjs-controllers-routing\u002F06.controllers-basics",{"title":4344,"path":4345,"stem":4346},"Декоратори маршрутизації HTTP-методів","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Froute-decorators","18.web-development\u002F07.nestjs-controllers-routing\u002F07.route-decorators",{"title":4348,"path":4349,"stem":4350},"Параметри маршруту та декоратор @Param","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Froute-parameters","18.web-development\u002F07.nestjs-controllers-routing\u002F08.route-parameters",{"title":4352,"path":4353,"stem":4354},"Query-параметри та декоратор @Query","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fquery-parameters","18.web-development\u002F07.nestjs-controllers-routing\u002F09.query-parameters",{"title":4356,"path":4357,"stem":4358},"Тіло запиту та декоратор @Body","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Frequest-body","18.web-development\u002F07.nestjs-controllers-routing\u002F10.request-body",{"title":4360,"path":4361,"stem":4362},"Робота з заголовками запиту та відповіді","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fheaders-decorators","18.web-development\u002F07.nestjs-controllers-routing\u002F11.headers-decorators",{"title":4364,"path":4365,"stem":4366},"Data Transfer Objects (DTO): визначення та призначення","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fdto-introduction","18.web-development\u002F07.nestjs-controllers-routing\u002F12.dto-introduction",{"title":4368,"path":4369,"stem":4370},"Об'єкти Request та Response","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Frequest-response-objects","18.web-development\u002F07.nestjs-controllers-routing\u002F13.request-response-objects",{"title":4372,"path":4373,"stem":4374},"HTTP-статус коди та декоратор @HttpCode","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fhttp-status-codes","18.web-development\u002F07.nestjs-controllers-routing\u002F14.http-status-codes",{"title":4376,"path":4377,"stem":4378},"Перенаправлення (Redirects) та декоратор @Redirect","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fredirects","18.web-development\u002F07.nestjs-controllers-routing\u002F15.redirects",{"title":4380,"path":4381,"stem":4382},"Асинхронні обробники та Observables","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fasync-handlers","18.web-development\u002F07.nestjs-controllers-routing\u002F16.async-handlers",{"title":4384,"path":4385,"stem":4386},"Маршрутизація за піддоменами та версіонування API","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fsub-domain-routing","18.web-development\u002F07.nestjs-controllers-routing\u002F17.sub-domain-routing",{"title":4388,"path":4389,"stem":4390},"Області видимості контролерів (Scopes)","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcontroller-scopes","18.web-development\u002F07.nestjs-controllers-routing\u002F18.controller-scopes",{"title":4392,"path":4393,"stem":4394},"Основні команди NestJS CLI","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fnestjs-cli-commands","18.web-development\u002F07.nestjs-controllers-routing\u002F19.nestjs-cli-commands",{"title":4396,"path":4397,"stem":4398},"Практичний приклад: створення CRUD-контролера","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fcrud-example","18.web-development\u002F07.nestjs-controllers-routing\u002F20.crud-example",{"title":4400,"path":4401,"stem":4402},"Тестування контролерів","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Ftesting-controllers","18.web-development\u002F07.nestjs-controllers-routing\u002F21.testing-controllers",{"title":4404,"path":4405,"stem":4406},"Best Practices для контролерів та маршрутизації","\u002Fweb-development\u002Fnestjs-controllers-routing\u002Fbest-practices","18.web-development\u002F07.nestjs-controllers-routing\u002F22.best-practices",{"title":4408,"icon":4409,"path":4410,"stem":4411,"children":4412,"page":59},"Тема 8. Провайдери, сервіси та модульна система NestJS","i-lucide-package","\u002Fweb-development\u002Fnestjs-providers-modules","18.web-development\u002F08.nestjs-providers-modules",[4413,4417,4421,4425,4429,4433,4437,4441,4445,4449,4453,4457,4461,4465,4469],{"title":4414,"path":4415,"stem":4416},"Концепція провайдерів у NestJS","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fproviders-concept","18.web-development\u002F08.nestjs-providers-modules\u002F01.providers-concept",{"title":4418,"path":4419,"stem":4420},"Сервіси: інкапсуляція бізнес-логіки","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fservices-business-logic","18.web-development\u002F08.nestjs-providers-modules\u002F02.services-business-logic",{"title":4422,"path":4423,"stem":4424},"Практика ін","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fdependency-injection-practice","18.web-development\u002F08.nestjs-providers-modules\u002F03.dependency-injection-practice",{"title":4426,"path":4427,"stem":4428},"Custom Providers: useValue, useClass, useFactory, useExisting","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fcustom-providers","18.web-development\u002F08.nestjs-providers-modules\u002F04.custom-providers",{"title":4430,"path":4431,"stem":4432},"Injection Tokens: рядкові та символьні токени","\u002Fweb-development\u002Fnestjs-providers-modules\u002Finjection-tokens","18.web-development\u002F08.nestjs-providers-modules\u002F05.injection-tokens",{"title":4434,"path":4435,"stem":4436},"Опціональні провайдери та декоратор @Optional","\u002Fweb-development\u002Fnestjs-providers-modules\u002Foptional-providers","18.web-development\u002F08.nestjs-providers-modules\u002F07.optional-providers",{"title":4438,"path":4439,"stem":4440},"Структура модулів: imports, controllers, providers, exports","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fmodules-structure","18.web-development\u002F08.nestjs-providers-modules\u002F08.modules-structure",{"title":4442,"path":4443,"stem":4444},"Feature Modules: ізоляція функціональності","\u002Fweb-development\u002Fnestjs-providers-modules\u002Ffeature-modules","18.web-development\u002F08.nestjs-providers-modules\u002F09.feature-modules",{"title":4446,"path":4447,"stem":4448},"Shared Modules: перевикористання провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fshared-modules","18.web-development\u002F08.nestjs-providers-modules\u002F10.shared-modules",{"title":4450,"path":4451,"stem":4452},"Global Modules та декоратор @Global","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fglobal-modules","18.web-development\u002F08.nestjs-providers-modules\u002F11.global-modules",{"title":4454,"path":4455,"stem":4456},"Dynamic Modules: конфігурація під час виконання","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fdynamic-modules","18.web-development\u002F08.nestjs-providers-modules\u002F12.dynamic-modules",{"title":4458,"path":4459,"stem":4460},"Циклічні залежності та forwardRef","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fcircular-dependencies","18.web-development\u002F08.nestjs-providers-modules\u002F13.circular-dependencies",{"title":4462,"path":4463,"stem":4464},"Lifecycle Hooks: хуки життєвого циклу","\u002Fweb-development\u002Fnestjs-providers-modules\u002Flifecycle-hooks","18.web-development\u002F08.nestjs-providers-modules\u002F14.lifecycle-hooks",{"title":4466,"path":4467,"stem":4468},"ModuleRef: динамічний доступ до провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Fmodule-reference","18.web-development\u002F08.nestjs-providers-modules\u002F15.module-reference",{"title":4470,"path":4471,"stem":4472},"Тестування сервісів та провайдерів","\u002Fweb-development\u002Fnestjs-providers-modules\u002Ftesting-services","18.web-development\u002F08.nestjs-providers-modules\u002F16.testing-services",{"title":4474,"icon":4475,"path":4476,"stem":4477,"children":4478,"page":59},"Тема 9. Валідація даних та конвеєр обробки запитів у NestJS","i-lucide-filter","\u002Fweb-development\u002Fnestjs-validation-pipeline","18.web-development\u002F09.nestjs-validation-pipeline",[4479,4483,4487,4491,4495,4499,4503,4507,4511,4515,4519,4523,4527,4531,4535,4539,4543,4547,4551],{"title":4480,"path":4481,"stem":4482},"Request Pipeline: конвеєр обробки запитів","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Frequest-pipeline","18.web-development\u002F09.nestjs-validation-pipeline\u002F01.request-pipeline",{"title":4484,"path":4485,"stem":4486},"Pipes: концепція трансформації та валідації","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fpipes-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F02.pipes-concept",{"title":4488,"path":4489,"stem":4490},"Вбудовані pipes: ParseIntPipe, ParseBoolPipe, ParseUUIDPipe","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fbuilt-in-pipes","18.web-development\u002F09.nestjs-validation-pipeline\u002F03.built-in-pipes",{"title":4492,"path":4493,"stem":4494},"ValidationPipe: автоматична валідація DTO","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fvalidation-pipe","18.web-development\u002F09.nestjs-validation-pipeline\u002F04.validation-pipe",{"title":4496,"path":4497,"stem":4498},"Декоратори class-validator для DTO","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fclass-validator-decorators","18.web-development\u002F09.nestjs-validation-pipeline\u002F05.class-validator-decorators",{"title":4500,"path":4501,"stem":4502},"Створення кастомних валідаторів","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-validators","18.web-development\u002F09.nestjs-validation-pipeline\u002F06.custom-validators",{"title":4504,"path":4505,"stem":4506},"Створення власних Pipes","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-pipes","18.web-development\u002F09.nestjs-validation-pipeline\u002F07.custom-pipes",{"title":4508,"path":4509,"stem":4510},"Основи Middleware","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fmiddleware-basics","18.web-development\u002F09.nestjs-validation-pipeline\u002F08.middleware-basics",{"title":4512,"path":4513,"stem":4514},"Практичні приклади Middleware","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fmiddleware-examples","18.web-development\u002F09.nestjs-validation-pipeline\u002F09.middleware-examples",{"title":4516,"path":4517,"stem":4518},"Guards: захисні перехоплювачі доступу","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fguards-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F10.guards-concept",{"title":4520,"path":4521,"stem":4522},"Створення кастомних Guards","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-guards","18.web-development\u002F09.nestjs-validation-pipeline\u002F11.custom-guards",{"title":4524,"path":4525,"stem":4526},"Interceptors: перехоплення та трансформація відповідей","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Finterceptors-concept","18.web-development\u002F09.nestjs-validation-pipeline\u002F12.interceptors-concept",{"title":4528,"path":4529,"stem":4530},"Практичні приклади Interceptors","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Finterceptor-examples","18.web-development\u002F09.nestjs-validation-pipeline\u002F13.interceptor-examples",{"title":4532,"path":4533,"stem":4534},"Exception Filters: обробка виключень","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fexception-filters","18.web-development\u002F09.nestjs-validation-pipeline\u002F14.exception-filters",{"title":4536,"path":4537,"stem":4538},"Custom Exception Filters: спеціалізовані фільтри","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-exception-filters","18.web-development\u002F09.nestjs-validation-pipeline\u002F15.custom-exception-filters",{"title":4540,"path":4541,"stem":4542},"Execution Context: контекст виконання","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fexecution-context","18.web-development\u002F09.nestjs-validation-pipeline\u002F16.execution-context",{"title":4544,"path":4545,"stem":4546},"Custom Decorators: власні декоратори","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fcustom-decorators","18.web-development\u002F09.nestjs-validation-pipeline\u002F17.custom-decorators",{"title":4548,"path":4549,"stem":4550},"Global Components: глобальні компоненти","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fglobal-components","18.web-development\u002F09.nestjs-validation-pipeline\u002F18.global-components",{"title":4552,"path":4553,"stem":4554},"Pipeline Best Practices: найкращі практики","\u002Fweb-development\u002Fnestjs-validation-pipeline\u002Fpipeline-best-practices","18.web-development\u002F09.nestjs-validation-pipeline\u002F19.pipeline-best-practices",{"title":4556,"icon":2865,"path":4557,"stem":4558,"children":4559,"page":59},"Інтеграція реляційних баз даних засобами TypeORM","\u002Fweb-development\u002Ftypeorm-integration","18.web-development\u002F10.typeorm-integration",[4560,4564,4568,4572,4576,4580,4584],{"title":4561,"path":4562,"stem":4563},"Робота з базами даних у Node.js через нативні драйвери","\u002Fweb-development\u002Ftypeorm-integration\u002F01-nodejs-database-drivers","18.web-development\u002F10.typeorm-integration\u002F01-nodejs-database-drivers",{"title":4565,"path":4566,"stem":4567},"ORM та знайомство з TypeORM","\u002Fweb-development\u002Ftypeorm-integration\u002F02-orm-and-typeorm-intro","18.web-development\u002F10.typeorm-integration\u002F02-orm-and-typeorm-intro",{"title":4569,"path":4570,"stem":4571},"Налаштування TypeORM у NestJS проєкті","\u002Fweb-development\u002Ftypeorm-integration\u002F03-typeorm-setup-nestjs","18.web-development\u002F10.typeorm-integration\u002F03-typeorm-setup-nestjs",{"title":4573,"path":4574,"stem":4575},"Entity класи та декоратори TypeORM","\u002Fweb-development\u002Ftypeorm-integration\u002F04-entities-and-decorators","18.web-development\u002F10.typeorm-integration\u002F04-entities-and-decorators",{"title":4577,"path":4578,"stem":4579},"Repository Pattern та CRUD операції","\u002Fweb-development\u002Ftypeorm-integration\u002F05-repository-pattern-crud","18.web-development\u002F10.typeorm-integration\u002F05-repository-pattern-crud",{"title":4581,"path":4582,"stem":4583},"Пагінація та фільтрація даних","\u002Fweb-development\u002Ftypeorm-integration\u002F06-pagination-filtering","18.web-development\u002F10.typeorm-integration\u002F06-pagination-filtering",{"title":4585,"path":4586,"stem":4587},"QueryBuilder для складних запитів","\u002Fweb-development\u002Ftypeorm-integration\u002F07-query-builder","18.web-development\u002F10.typeorm-integration\u002F07-query-builder",{"title":4589,"icon":4590,"path":4591,"stem":4592,"children":4593,"page":59},"Зв'язки між сутностями, міграції та оптимізація запитів","i-lucide-git-branch","\u002Fweb-development\u002Fentity-relations-migrations","18.web-development\u002F11.entity-relations-migrations",[4594,4598,4602,4606,4610],{"title":4595,"path":4596,"stem":4597},"Зв'язки One-to-Many та Many-to-One","\u002Fweb-development\u002Fentity-relations-migrations\u002F01-one-to-many-many-to-one","18.web-development\u002F11.entity-relations-migrations\u002F01-one-to-many-many-to-one",{"title":4599,"path":4600,"stem":4601},"Зв'язки One-to-One та Many-to-Many","\u002Fweb-development\u002Fentity-relations-migrations\u002F02-one-to-one-many-to-many","18.web-development\u002F11.entity-relations-migrations\u002F02-one-to-one-many-to-many",{"title":4603,"path":4604,"stem":4605},"Керування міграціями бази даних","\u002Fweb-development\u002Fentity-relations-migrations\u002F03-migrations-management","18.web-development\u002F11.entity-relations-migrations\u002F03-migrations-management",{"title":4607,"path":4608,"stem":4609},"Транзакції у TypeORM","\u002Fweb-development\u002Fentity-relations-migrations\u002F04-transactions","18.web-development\u002F11.entity-relations-migrations\u002F04-transactions",{"title":4611,"path":4612,"stem":4613,"children":4614},"Індекси та оптимізація запитів","\u002Fweb-development\u002Fentity-relations-migrations\u002F05-indexes-optimization","18.web-development\u002F11.entity-relations-migrations\u002F05-indexes-optimization",[4615],{"title":4611,"path":4612,"stem":4613},{"title":4617,"icon":4618,"path":4619,"stem":4620,"children":4621,"page":59},"Механізми автентифікації у вебзастосунках","i-lucide-key","\u002Fweb-development\u002Fauthentication","18.web-development\u002F12.authentication",[4622,4626,4630,4634,4638,4642,4646,4650,4654],{"title":4623,"path":4624,"stem":4625},"Автентифікація vs Авторизація","\u002Fweb-development\u002Fauthentication\u002F01-authentication-vs-authorization","18.web-development\u002F12.authentication\u002F01-authentication-vs-authorization",{"title":4627,"path":4628,"stem":4629},"Стратегії автентифікації","\u002Fweb-development\u002Fauthentication\u002F02-authentication-strategies","18.web-development\u002F12.authentication\u002F02-authentication-strategies",{"title":4631,"path":4632,"stem":4633},"Автентифікація на основі сесій","\u002Fweb-development\u002Fauthentication\u002F03-session-based-authentication","18.web-development\u002F12.authentication\u002F03-session-based-authentication",{"title":4635,"path":4636,"stem":4637},"Структура JSON Web Token (JWT)","\u002Fweb-development\u002Fauthentication\u002F04-jwt-structure","18.web-development\u002F12.authentication\u002F04-jwt-structure",{"title":4639,"path":4640,"stem":4641},"Інтеграція JWT у NestJS","\u002Fweb-development\u002Fauthentication\u002F05-nestjs-jwt-integration","18.web-development\u002F12.authentication\u002F05-nestjs-jwt-integration",{"title":4643,"path":4644,"stem":4645},"Passport.js стратегії у NestJS","\u002Fweb-development\u002Fauthentication\u002F06-passport-strategies","18.web-development\u002F12.authentication\u002F06-passport-strategies",{"title":4647,"path":4648,"stem":4649},"Безпечне зберігання паролів: хешування та криптографічний захист","\u002Fweb-development\u002Fauthentication\u002F07-password-hashing","18.web-development\u002F12.authentication\u002F07-password-hashing",{"title":4651,"path":4652,"stem":4653},"Refresh Token та безпечне оновлення доступу","\u002Fweb-development\u002Fauthentication\u002F08-refresh-tokens","18.web-development\u002F12.authentication\u002F08-refresh-tokens",{"title":4655,"path":4656,"stem":4657},"OAuth 2.0 та OpenID Connect: делегована автентифікація","\u002Fweb-development\u002Fauthentication\u002F09-oauth2-openid","18.web-development\u002F12.authentication\u002F09-oauth2-openid",{"title":4659,"icon":4660,"path":4661,"stem":4662,"children":4663,"page":59},"Авторизація та безпека серверних застосунків","i-lucide-shield","\u002Fweb-development\u002Fauthorization-security","18.web-development\u002F13.authorization-security",[4664,4668,4672,4676,4680,4684,4688,4692,4696,4700],{"title":4665,"path":4666,"stem":4667},"Моделі авторизації","\u002Fweb-development\u002Fauthorization-security\u002F01-authorization-models","18.web-development\u002F13.authorization-security\u002F01-authorization-models",{"title":4669,"path":4670,"stem":4671},"Реалізація RBAC у NestJS","\u002Fweb-development\u002Fauthorization-security\u002F02-rbac-implementation","18.web-development\u002F13.authorization-security\u002F02-rbac-implementation",{"title":4673,"path":4674,"stem":4675},"Permission-Based Access Control","\u002Fweb-development\u002Fauthorization-security\u002F03-permission-based-access","18.web-development\u002F13.authorization-security\u002F03-permission-based-access",{"title":4677,"path":4678,"stem":4679},"ABAC та бібліотека CASL","\u002Fweb-development\u002Fauthorization-security\u002F04-abac-casl","18.web-development\u002F13.authorization-security\u002F04-abac-casl",{"title":4681,"path":4682,"stem":4683},"Кастомні декоратори та метадані","\u002Fweb-development\u002Fauthorization-security\u002F05-custom-decorators-metadata","18.web-development\u002F13.authorization-security\u002F05-custom-decorators-metadata",{"title":4685,"path":4686,"stem":4687},"Конфігурація CORS","\u002Fweb-development\u002Fauthorization-security\u002F06-cors-configuration","18.web-development\u002F13.authorization-security\u002F06-cors-configuration",{"title":4689,"path":4690,"stem":4691},"Захист через HTTP Security Headers (Helmet)","\u002Fweb-development\u002Fauthorization-security\u002F07-helmet-security-headers","18.web-development\u002F13.authorization-security\u002F07-helmet-security-headers",{"title":4693,"path":4694,"stem":4695},"Rate Limiting та Throttling","\u002Fweb-development\u002Fauthorization-security\u002F08-rate-limiting-throttling","18.web-development\u002F13.authorization-security\u002F08-rate-limiting-throttling",{"title":4697,"path":4698,"stem":4699},"Захист від поширених атак","\u002Fweb-development\u002Fauthorization-security\u002F09-common-attacks-protection","18.web-development\u002F13.authorization-security\u002F09-common-attacks-protection",{"title":4701,"path":4702,"stem":4703},"HTTPS у продакшені","\u002Fweb-development\u002Fauthorization-security\u002F10-https-production","18.web-development\u002F13.authorization-security\u002F10-https-production",{"title":4705,"icon":871,"path":4706,"stem":4707,"children":4708,"page":59},"Комунікація у реальному часі, нотифікації та фонові задачі","\u002Fweb-development\u002Frealtime-notifications-jobs","18.web-development\u002F14.realtime-notifications-jobs",[4709,4713,4717,4721,4725,4729,4732,4735,4739,4743],{"title":4710,"path":4711,"stem":4712},"Методи комунікації у реальному часі","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F01-realtime-communication-methods","18.web-development\u002F14.realtime-notifications-jobs\u002F01-realtime-communication-methods",{"title":4714,"path":4715,"stem":4716},"WebSocket Gateway у NestJS","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F02-websocket-gateway","18.web-development\u002F14.realtime-notifications-jobs\u002F02-websocket-gateway",{"title":4718,"path":4719,"stem":4720},"Lifecycle та Rooms у WebSocket","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F03-websocket-lifecycle-rooms","18.web-development\u002F14.realtime-notifications-jobs\u002F03-websocket-lifecycle-rooms",{"title":4722,"path":4723,"stem":4724},"Server-Sent Events (SSE)","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F04-server-sent-events","18.web-development\u002F14.realtime-notifications-jobs\u002F04-server-sent-events",{"title":4726,"path":4727,"stem":4728},"Архітектура системи нотифікацій","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F05-notification-system","18.web-development\u002F14.realtime-notifications-jobs\u002F05-notification-system",{"title":904,"path":4730,"stem":4731},"\u002Fweb-development\u002Frealtime-notifications-jobs\u002F06-email-notifications","18.web-development\u002F14.realtime-notifications-jobs\u002F06-email-notifications",{"title":900,"path":4733,"stem":4734},"\u002Fweb-development\u002Frealtime-notifications-jobs\u002F07-web-push-notifications","18.web-development\u002F14.realtime-notifications-jobs\u002F07-web-push-notifications",{"title":4736,"path":4737,"stem":4738},"Фонові задачі та черги","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F08-background-jobs-queues","18.web-development\u002F14.realtime-notifications-jobs\u002F08-background-jobs-queues",{"title":4740,"path":4741,"stem":4742},"Планувальники та Cron jobs","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F09-schedulers-cron","18.web-development\u002F14.realtime-notifications-jobs\u002F09-schedulers-cron",{"title":4744,"path":4745,"stem":4746},"Практичні сценарії застосування","\u002Fweb-development\u002Frealtime-notifications-jobs\u002F10-practical-scenarios","18.web-development\u002F14.realtime-notifications-jobs\u002F10-practical-scenarios",{"title":4748,"icon":4749,"path":4750,"stem":4751,"children":4752,"page":59},"Тестування, документування та розгортання застосунків","i-lucide-rocket","\u002Fweb-development\u002Ftesting-documentation-deployment","18.web-development\u002F15.testing-documentation-deployment",[4753,4757,4761,4765,4769,4773,4777,4781,4785,4789],{"title":4754,"path":4755,"stem":4756},"Піраміда тестування та стратегія","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F01-testing-pyramid-strategy","18.web-development\u002F15.testing-documentation-deployment\u002F01-testing-pyramid-strategy",{"title":4758,"path":4759,"stem":4760},"Основи Jest у NestJS","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F02-jest-nestjs-basics","18.web-development\u002F15.testing-documentation-deployment\u002F02-jest-nestjs-basics",{"title":4762,"path":4763,"stem":4764},"Unit-тестування сервісів","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F03-unit-testing-services","18.web-development\u002F15.testing-documentation-deployment\u002F03-unit-testing-services",{"title":4766,"path":4767,"stem":4768},"E2E тестування та покриття коду","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F04-e2e-testing-coverage","18.web-development\u002F15.testing-documentation-deployment\u002F04-e2e-testing-coverage",{"title":4770,"path":4771,"stem":4772},"Swagger, OpenAPI, Scalar та Arazzo","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F05-swagger-openapi","18.web-development\u002F15.testing-documentation-deployment\u002F05-swagger-openapi",{"title":4774,"path":4775,"stem":4776},"Керування конфігурацією","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F06-configuration-management","18.web-development\u002F15.testing-documentation-deployment\u002F06-configuration-management",{"title":4778,"path":4779,"stem":4780},"Docker та контейнеризація","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F07-docker-containerization","18.web-development\u002F15.testing-documentation-deployment\u002F07-docker-containerization",{"title":4782,"path":4783,"stem":4784},"CI\u002FCD Pipelines","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F08-cicd-pipelines","18.web-development\u002F15.testing-documentation-deployment\u002F08-cicd-pipelines",{"title":4786,"path":4787,"stem":4788},"Логування та моніторинг","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F09-logging-monitoring","18.web-development\u002F15.testing-documentation-deployment\u002F09-logging-monitoring",{"title":4790,"path":4791,"stem":4792},"Серіалізація та компресія","\u002Fweb-development\u002Ftesting-documentation-deployment\u002F10-serialization-compression","18.web-development\u002F15.testing-documentation-deployment\u002F10-serialization-compression",{"title":4794,"icon":4795,"path":4796,"stem":4797,"children":4798,"page":59},"AI Core: мислення AI","i-lucide-brain","\u002Fai-core","19.ai-core",[4799,4840,4889,4927],{"title":4800,"icon":4749,"path":4801,"stem":4802,"children":4803,"page":59},"Вхід у професію AI Native Developer","\u002Fai-core\u002Fai-native-developer","19.ai-core\u002F01.ai-native-developer",[4804,4808,4812,4816,4820,4824,4828,4832,4836],{"title":4805,"path":4806,"stem":4807},"Вступ до професії розробника цифрових продуктів","\u002Fai-core\u002Fai-native-developer\u002Fdigital-products","19.ai-core\u002F01.ai-native-developer\u002F01.digital-products",{"title":4809,"path":4810,"stem":4811},"Професія розробника програмного забезпечення","\u002Fai-core\u002Fai-native-developer\u002Fsoftware-developer","19.ai-core\u002F01.ai-native-developer\u002F02.software-developer",{"title":4813,"path":4814,"stem":4815},"Професія AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fai-native-developer","19.ai-core\u002F01.ai-native-developer\u002F03.ai-native-developer",{"title":4817,"path":4818,"stem":4819},"Вплив AI на розробку програмного забезпечення","\u002Fai-core\u002Fai-native-developer\u002Fai-impact-on-development","19.ai-core\u002F01.ai-native-developer\u002F04.ai-impact-on-development",{"title":4821,"path":4822,"stem":4823},"Життєвий цикл цифрового продукту","\u002Fai-core\u002Fai-native-developer\u002Fproduct-lifecycle","19.ai-core\u002F01.ai-native-developer\u002F05.product-lifecycle",{"title":4825,"path":4826,"stem":4827},"Застосування AI на етапах створення цифрового продукту","\u002Fai-core\u002Fai-native-developer\u002Fai-in-product-creation","19.ai-core\u002F01.ai-native-developer\u002F06.ai-in-product-creation",{"title":4829,"path":4830,"stem":4831},"Розподіл завдань між людиною та AI","\u002Fai-core\u002Fai-native-developer\u002Fhuman-vs-ai-tasks","19.ai-core\u002F01.ai-native-developer\u002F07.human-vs-ai-tasks",{"title":4833,"path":4834,"stem":4835},"Компетенції AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fcompetencies","19.ai-core\u002F01.ai-native-developer\u002F08.competencies",{"title":4837,"path":4838,"stem":4839},"Карта професійного розвитку AI Native Developer","\u002Fai-core\u002Fai-native-developer\u002Fcareer-roadmap","19.ai-core\u002F01.ai-native-developer\u002F09.career-roadmap",{"title":4841,"icon":255,"path":4842,"stem":4843,"children":4844,"page":59},"Штучний інтелект і машинне навчання","\u002Fai-core\u002Fai-and-machine-learning","19.ai-core\u002F02.ai-and-machine-learning",[4845,4849,4853,4857,4861,4865,4869,4873,4877,4881,4885],{"title":4846,"path":4847,"stem":4848},"Штучний інтелект","\u002Fai-core\u002Fai-and-machine-learning\u002Fwhat-is-ai","19.ai-core\u002F02.ai-and-machine-learning\u002F01.what-is-ai",{"title":4850,"path":4851,"stem":4852},"Відмінність AI від інших програмних систем","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-vs-automation","19.ai-core\u002F02.ai-and-machine-learning\u002F02.ai-vs-automation",{"title":4854,"path":4855,"stem":4856},"Завдання штучного інтелекту","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-tasks","19.ai-core\u002F02.ai-and-machine-learning\u002F03.ai-tasks",{"title":4858,"path":4859,"stem":4860},"Machine Learning","\u002Fai-core\u002Fai-and-machine-learning\u002Fmachine-learning","19.ai-core\u002F02.ai-and-machine-learning\u002F04.machine-learning",{"title":4862,"path":4863,"stem":4864},"Machine Learning Workflow","\u002Fai-core\u002Fai-and-machine-learning\u002Fml-workflow","19.ai-core\u002F02.ai-and-machine-learning\u002F05.ml-workflow",{"title":4866,"path":4867,"stem":4868},"Типи машинного навчання","\u002Fai-core\u002Fai-and-machine-learning\u002Fml-types","19.ai-core\u002F02.ai-and-machine-learning\u002F06.ml-types",{"title":4870,"path":4871,"stem":4872},"Generative AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fgenerative-ai","19.ai-core\u002F02.ai-and-machine-learning\u002F07.generative-ai",{"title":4874,"path":4875,"stem":4876},"Типи контенту, створюваного AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fai-content-types","19.ai-core\u002F02.ai-and-machine-learning\u002F08.ai-content-types",{"title":4878,"path":4879,"stem":4880},"Великі мовні моделі","\u002Fai-core\u002Fai-and-machine-learning\u002Flarge-language-models","19.ai-core\u002F02.ai-and-machine-learning\u002F09.large-language-models",{"title":4882,"path":4883,"stem":4884},"Можливості та обмеження Generative AI","\u002Fai-core\u002Fai-and-machine-learning\u002Fcapabilities-and-limitations","19.ai-core\u002F02.ai-and-machine-learning\u002F10.capabilities-and-limitations",{"title":4886,"path":4887,"stem":4888},"Сучасні AI-асистенти","\u002Fai-core\u002Fai-and-machine-learning\u002Fmodern-ai-assistants","19.ai-core\u002F02.ai-and-machine-learning\u002F11.modern-ai-assistants",{"title":4890,"icon":4891,"path":4892,"stem":4893,"children":4894,"page":59},"Постановка завдань для AI: принципи створення промптів","i-lucide-message-square-text","\u002Fai-core\u002Fprompt-engineering","19.ai-core\u002F03.prompt-engineering",[4895,4899,4903,4907,4911,4915,4919,4923],{"title":4896,"path":4897,"stem":4898},"Промпт як інструмент","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-as-tool","19.ai-core\u002F03.prompt-engineering\u002F01.prompt-as-tool",{"title":4900,"path":4901,"stem":4902},"Принципи створення промптів","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-principles","19.ai-core\u002F03.prompt-engineering\u002F02.prompt-principles",{"title":4904,"path":4905,"stem":4906},"Структура промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-structure","19.ai-core\u002F03.prompt-engineering\u002F03.prompt-structure",{"title":4908,"path":4909,"stem":4910},"Види промптів за типом задачі","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-types","19.ai-core\u002F03.prompt-engineering\u002F04.prompt-types",{"title":4912,"path":4913,"stem":4914},"Прийоми посилення промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-enhancement","19.ai-core\u002F03.prompt-engineering\u002F05.prompt-enhancement",{"title":4916,"path":4917,"stem":4918},"Розбір і покращення промпта","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-analysis","19.ai-core\u002F03.prompt-engineering\u002F06.prompt-analysis",{"title":4920,"path":4921,"stem":4922},"Типові помилки під час створення промптів","\u002Fai-core\u002Fprompt-engineering\u002Fcommon-mistakes","19.ai-core\u002F03.prompt-engineering\u002F07.common-mistakes",{"title":4924,"path":4925,"stem":4926},"Практикум: особиста бібліотека промптів","\u002Fai-core\u002Fprompt-engineering\u002Fprompt-library","19.ai-core\u002F03.prompt-engineering\u002F08.prompt-library",{"title":4928,"icon":793,"path":4929,"stem":4930,"children":4931,"page":59},"Перевірка результатів, безпека та AI Native Workflow","\u002Fai-core\u002Fverification-security-workflow","19.ai-core\u002F04.verification-security-workflow",[4932,4936,4940,4944,4948,4952,4956,4960,4964],{"title":4933,"path":4934,"stem":4935},"Межі можливостей AI","\u002Fai-core\u002Fverification-security-workflow\u002Fai-limitations","19.ai-core\u002F04.verification-security-workflow\u002F01.ai-limitations",{"title":4937,"path":4938,"stem":4939},"Галюцинації AI","\u002Fai-core\u002Fverification-security-workflow\u002Fai-hallucinations","19.ai-core\u002F04.verification-security-workflow\u002F02.ai-hallucinations",{"title":4941,"path":4942,"stem":4943},"Критичне мислення під час роботи з AI","\u002Fai-core\u002Fverification-security-workflow\u002Fcritical-thinking","19.ai-core\u002F04.verification-security-workflow\u002F03.critical-thinking",{"title":4945,"path":4946,"stem":4947},"Перевірка результатів роботи AI","\u002Fai-core\u002Fverification-security-workflow\u002Fresult-verification","19.ai-core\u002F04.verification-security-workflow\u002F04.result-verification",{"title":4949,"path":4950,"stem":4951},"Захист даних під час роботи з AI","\u002Fai-core\u002Fverification-security-workflow\u002Fdata-protection","19.ai-core\u002F04.verification-security-workflow\u002F05.data-protection",{"title":4953,"path":4954,"stem":4955},"Авторське право та навчальна доброчесність","\u002Fai-core\u002Fverification-security-workflow\u002Fcopyright-integrity","19.ai-core\u002F04.verification-security-workflow\u002F06.copyright-integrity",{"title":4957,"path":4958,"stem":4959},"Відповідальне використання AI","\u002Fai-core\u002Fverification-security-workflow\u002Fresponsible-use","19.ai-core\u002F04.verification-security-workflow\u002F07.responsible-use",{"title":4961,"path":4962,"stem":4963},"AI Native Workflow","\u002Fai-core\u002Fverification-security-workflow\u002Fai-native-workflow","19.ai-core\u002F04.verification-security-workflow\u002F08.ai-native-workflow",{"title":4965,"path":4966,"stem":4967},"Застосування AI Native Workflow під час створення цифрового продукту","\u002Fai-core\u002Fverification-security-workflow\u002Fworkflow-in-practice","19.ai-core\u002F04.verification-security-workflow\u002F09.workflow-in-practice",{"title":4969,"icon":4970,"path":4971,"stem":4972,"children":4973,"page":59},"AI Developer: Vibe Coding Sprint","i-lucide-code-xml","\u002Fai-developer","20.ai-developer",[4974,5000,5022,5043],{"title":4975,"icon":4976,"path":4977,"stem":4978,"children":4979,"page":59},"Проєктування і чорнова версія","i-lucide-pencil-ruler","\u002Fai-developer\u002Fdraft-creation","20.ai-developer\u002F01.draft-creation",[4980,4984,4988,4992,4996],{"title":4981,"path":4982,"stem":4983},"Парадигма Vibe Coding Workflow","\u002Fai-developer\u002Fdraft-creation\u002Fvibe-coding-workflow","20.ai-developer\u002F01.draft-creation\u002F01.vibe-coding-workflow",{"title":4985,"path":4986,"stem":4987},"AI-середовище швидкої розробки","\u002Fai-developer\u002Fdraft-creation\u002Fai-ide-environment","20.ai-developer\u002F01.draft-creation\u002F02.ai-ide-environment",{"title":4989,"path":4990,"stem":4991},"Користувацьке завдання та межі першої версії","\u002Fai-developer\u002Fdraft-creation\u002Fproduct-scope-and-mvp","20.ai-developer\u002F01.draft-creation\u002F03.product-scope-and-mvp",{"title":4993,"path":4994,"stem":4995},"Архітектура інтерфейсу та стани застосунку","\u002Fai-developer\u002Fdraft-creation\u002Fapplication-architecture-and-states","20.ai-developer\u002F01.draft-creation\u002F04.application-architecture-and-states",{"title":4997,"path":4998,"stem":4999},"Генерація та фіксація чорнової версії","\u002Fai-developer\u002Fdraft-creation\u002Fgenerating-draft-version","20.ai-developer\u002F01.draft-creation\u002F05.generating-draft-version",{"title":5001,"icon":5002,"path":5003,"stem":5004,"children":5005,"page":59},"Перша робоча версія","i-lucide-play-circle","\u002Fai-developer\u002Ffirst-working-version","20.ai-developer\u002F02.first-working-version",[5006,5010,5014,5018],{"title":5007,"path":5008,"stem":5009},"Уточнення контексту проєкту для AI","\u002Fai-developer\u002Ffirst-working-version\u002Frefining-project-context","20.ai-developer\u002F02.first-working-version\u002F01.refining-project-context",{"title":5011,"path":5012,"stem":5013},"Стратегія завдань для AI-розробки","\u002Fai-developer\u002Ffirst-working-version\u002Fai-prompting-strategy","20.ai-developer\u002F02.first-working-version\u002F02.ai-prompting-strategy",{"title":5015,"path":5016,"stem":5017},"Доопрацювання до першої робочої версії","\u002Fai-developer\u002Ffirst-working-version\u002Frefining-to-working-version","20.ai-developer\u002F02.first-working-version\u002F03.refining-to-working-version",{"title":5019,"path":5020,"stem":5021},"Перевірка першої робочої версії","\u002Fai-developer\u002Ffirst-working-version\u002Ftesting-first-working-version","20.ai-developer\u002F02.first-working-version\u002F04.testing-first-working-version",{"title":5023,"icon":3072,"path":5024,"stem":5025,"children":5026,"page":59},"Ітерації, дебагінг та відновлення","\u002Fai-developer\u002Fiteration-debugging-recovery","20.ai-developer\u002F03.iteration-debugging-recovery",[5027,5031,5035,5039],{"title":5028,"path":5029,"stem":5030},"Управління точковими змінами продукту","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fchange-management","20.ai-developer\u002F03.iteration-debugging-recovery\u002F01.change-management",{"title":5032,"path":5033,"stem":5034},"Надійність інтерфейсу та обробка помилок","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fscenario-reliability-and-errors","20.ai-developer\u002F03.iteration-debugging-recovery\u002F02.scenario-reliability-and-errors",{"title":5036,"path":5037,"stem":5038},"Керування контекстом і збереження версій","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fproject-context-and-versions","20.ai-developer\u002F03.iteration-debugging-recovery\u002F03.project-context-and-versions",{"title":5040,"path":5041,"stem":5042},"Збої AI-розробки, ліміти та аварійне відновлення","\u002Fai-developer\u002Fiteration-debugging-recovery\u002Fai-breakdowns-and-recovery","20.ai-developer\u002F03.iteration-debugging-recovery\u002F04.ai-breakdowns-and-recovery",{"title":5044,"icon":5045,"path":5046,"stem":5047,"children":5048,"page":59},"Перевірка та завершення продукту","i-lucide-check-check","\u002Fai-developer\u002Fverification-and-completion","20.ai-developer\u002F04.verification-and-completion",[5049,5053,5057],{"title":5050,"path":5051,"stem":5052},"Комплексний аудит та підсумкове тестування","\u002Fai-developer\u002Fverification-and-completion\u002Ffinal-product-testing","20.ai-developer\u002F04.verification-and-completion\u002F01.final-product-testing",{"title":5054,"path":5055,"stem":5056},"Підготовка підсумкової версії коду","\u002Fai-developer\u002Fverification-and-completion\u002Fpreparing-release-version","20.ai-developer\u002F04.verification-and-completion\u002F02.preparing-release-version",{"title":5058,"path":5059,"stem":5060},"Демонстрація, публікація та критерії оцінювання","\u002Fai-developer\u002Fverification-and-completion\u002Fproduct-showcase-and-publishing","20.ai-developer\u002F04.verification-and-completion\u002F03.product-showcase-and-publishing",{"title":5062,"path":5063,"stem":5064,"children":5065,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[5066,5070,5074,5078,5082,5086,5090,5094,5098,5102,5106,5110],{"title":5067,"path":5068,"stem":5069},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":5071,"path":5072,"stem":5073},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":5075,"path":5076,"stem":5077},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":5079,"path":5080,"stem":5081},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":5083,"path":5084,"stem":5085},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":5087,"path":5088,"stem":5089},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":5091,"path":5092,"stem":5093},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":5095,"path":5096,"stem":5097},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":5099,"path":5100,"stem":5101},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":5103,"path":5104,"stem":5105},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":5107,"path":5108,"stem":5109},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":5111,"path":5112,"stem":5113},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":5115,"path":5116,"stem":5117,"children":5118,"page":59},"React Typescript","\u002Freact-typescript","22.react-typescript",[5119,5144,5148,5152,5156,5160,5164,5168,5172],{"title":5120,"path":5121,"stem":5122,"children":5123,"page":59},"From Html To Project","\u002Freact-typescript\u002Ffrom-html-to-project","22.react-typescript\u002F01.from-html-to-project",[5124,5128,5132,5136,5140],{"title":5125,"path":5126,"stem":5127},"Від одного HTML-файлу до повноцінного проєкту","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fevolution","22.react-typescript\u002F01.from-html-to-project\u002F01.evolution",{"title":5129,"path":5130,"stem":5131},"Що таке React","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fwhat-is-react","22.react-typescript\u002F01.from-html-to-project\u002F02.what-is-react",{"title":5133,"path":5134,"stem":5135},"JSX та TSX — синтаксичний цукор, а не магія","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fjsx-tsx-syntax","22.react-typescript\u002F01.from-html-to-project\u002F03.jsx-tsx-syntax",{"title":5137,"path":5138,"stem":5139},"Компоненти — будівельні блоки інтерфейсу","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fcomponents","22.react-typescript\u002F01.from-html-to-project\u002F04.components",{"title":5141,"path":5142,"stem":5143},"JSX — розмітка всередині TypeScript","\u002Freact-typescript\u002Ffrom-html-to-project\u002Fjsx-expressions","22.react-typescript\u002F01.from-html-to-project\u002F05.jsx-expressions",{"title":5145,"path":5146,"stem":5147},"Хук useReducer: структуроване управління складним станом","\u002Freact-typescript\u002Fuse-reducer","22.react-typescript\u002F23.use-reducer",{"title":5149,"path":5150,"stem":5151},"Context API: передавання даних без «пропс-дрілінгу»","\u002Freact-typescript\u002Fcontext-api","22.react-typescript\u002F24.context-api",{"title":5153,"path":5154,"stem":5155},"Синхронізація з ефектами: хук useEffect та функції очищення","\u002Freact-typescript\u002Fuse-effect","22.react-typescript\u002F27.use-effect",{"title":5157,"path":5158,"stem":5159},"Можливо, вам не потрібен ефект: антипатерни та альтернативи","\u002Freact-typescript\u002Fyou-might-not-need-effect","22.react-typescript\u002F28.you-might-not-need-effect",{"title":5161,"path":5162,"stem":5163},"Життєвий цикл реактивних ефектів: мислення процесами синхронізації","\u002Freact-typescript\u002Flifecycle-of-reactive-effects","22.react-typescript\u002F29.lifecycle-of-reactive-effects",{"title":5165,"path":5166,"stem":5167},"Розділення подій та ефектів: реактивна проти нереактивної логіки","\u002Freact-typescript\u002Fseparating-events-from-effects","22.react-typescript\u002F30.separating-events-from-effects",{"title":5169,"path":5170,"stem":5171},"Видалення зайвих залежностей ефектів та оптимізація синхронізації","\u002Freact-typescript\u002Fremoving-effect-dependencies","22.react-typescript\u002F31.removing-effect-dependencies",{"title":5173,"path":5174,"stem":5175},"Кастомні хуки: повторне використання та композиція реактивної логіки","\u002Freact-typescript\u002Fcustom-hooks","22.react-typescript\u002F32.custom-hooks",{"title":5177,"path":5178,"stem":5179},"Тестування компонентів діаграм та пісочниць","\u002Ftest-components","98.test-components",{"id":5181,"title":4021,"body":5182,"description":29423,"extension":29424,"links":29425,"meta":29426,"navigation":6148,"path":4022,"seo":29427,"stem":4023,"__hash__":29428},"docs\u002F17.client-server-architecture\u002F09.rest-api-design-and-chi-routing.md",{"type":5183,"value":5184,"toc":29337},"minimark",[5185,5189,5365,5368,5373,5378,5386,5408,5419,5436,5440,5443,5479,5490,5494,5501,5518,5529,5539,5562,5573,5586,5593,5597,5604,5665,5672,5692,5712,5764,5766,5770,5774,5788,5799,5870,5877,5883,5887,5894,5913,5923,5929,5933,5940,5951,5968,5974,5976,5980,5984,5995,6000,6024,6029,6043,6049,6053,6060,6067,6072,6075,6102,6112,6328,6342,6346,6351,6378,6383,6406,6412,6414,6418,6421,6424,6462,6465,6622,6626,6635,6638,6644,6742,6752,6756,6759,6825,6842,6846,6853,6858,6911,6916,6923,6948,6968,6972,6993,6998,7105,7110,7163,7184,7188,7198,7230,7244,7248,7255,7328,7351,7355,7360,7395,7400,7434,7439,7456,7485,7487,7491,7495,7498,7668,7674,7691,7694,7698,7704,7730,7740,7815,7927,8149,8154,8189,8199,8201,8205,8209,8216,8331,8354,8358,8368,8476,8480,8485,8632,8644,8649,8714,8720,8725,8850,8855,8859,8934,8937,8949,8954,9090,9102,9106,9111,9259,9267,9272,9388,9396,9408,9412,9417,9444,9454,9459,9484,9495,9514,9516,9520,9524,9531,9554,9563,9567,9589,9592,11044,11048,11055,11098,11101,11193,11302,11306,11309,11549,11553,11558,11794,11799,12033,12038,12340,12344,12347,12710,12715,12719,12864,12868,12972,12976,13017,13021,13200,13204,13210,13688,13692,13695,14087,14091,14097,14597,14742,14746,14749,14865,14868,14872,16638,16682,16684,16688,16692,16698,16703,17115,17120,17225,17228,17248,17252,17255,17870,17873,17941,17943,17947,17951,17960,18361,18366,18369,18607,18612,18615,18838,18841,19447,19452,20101,20106,20910,20914,20919,21983,21992,21994,21998,22003,23461,23463,23467,23471,24070,24074,24591,24595,25810,25878,25880,25884,25961,26046,26048,26054,26056,26060,26064,26067,26128,26131,26169,26176,26180,26193,26219,26232,26236,26249,26261,26270,26317,26327,26331,26334,26373,26383,26387,26412,26427,26431,26444,26447,26453,26460,26471,26475,26478,26787,26792,26817,26821,26831,26839,26849,26861,26871,26876,27006,27011,27123,27129,27133,27178,27184,27186,27190,27194,27199,27243,27247,27466,27470,27475,27604,27610,27614,27624,27948,27958,27976,28134,28138,28202,28206,28330,28355,28359,28365,28431,28438,28471,28473,28477,28545,28555,28557,28562,28565,28573,28648,28654,28694,28699,28903,28925,28929,28934,28939,29279,29284,29333],[5186,5187,4021],"h1",{"id":5188},"проєктування-rest-api-та-маршрутизація-засобами-chi",[5190,5191,5192,5317],"card-group",{},[5193,5194,5197],"card",{"icon":5195,"title":5196},"i-lucide-graduation-cap","🎯 Навчальні цілі",[5198,5199,5200,5209,5216,5228,5235,5250,5273,5280,5292,5303,5310],"ul",{},[5201,5202,5203,5204,5208],"li",{},"Зрозуміти ",[5205,5206,5207],"strong",{},"історичну еволюцію"," від RPC-систем першого покоління до сучасних HTTP API та віддалених викликів процедур нового покоління (gRPC, GraphQL).",[5201,5210,5211,5212,5215],{},"Усвідомити, чому протокол HTTP став ",[5205,5213,5214],{},"універсальною мовою інтернету"," і де межа між HTTP як транспортом і HTTP як протоколом прикладного рівня.",[5201,5217,5218,5219,5222,5223,5227],{},"Розібратися з концепцією ",[5205,5220,5221],{},"REST"," (",[5224,5225,5226],"em",{},"Representational State Transfer",") як архітектурного стилю: що описав Рой Філдінг у своїй дисертації 2000 року, як це інтерпретується у 2008 році та у реальній практиці.",[5201,5229,5230,5231,5234],{},"Детально вивчити ",[5205,5232,5233],{},"складові HTTP-запитів та відповідей",": URL, заголовки, HTTP-методи, статус-коди, їхню семантику та застосування у дизайні API.",[5201,5236,5237,5238,5241,5242,5245,5246,5249],{},"Опанувати принципи ",[5205,5239,5240],{},"проєктування номенклатури URL",": ієрархії ресурсів, параметри шляху (",[5224,5243,5244],{},"path",") vs параметри запиту (",[5224,5247,5248],{},"query","), версіонування API, консистентність найменувань.",[5201,5251,5252,5253,5222,5256,5259,5260,5259,5263,5259,5266,5259,5269,5272],{},"Навчитися правильно використовувати ",[5205,5254,5255],{},"HTTP-методи",[5224,5257,5258],{},"GET",", ",[5224,5261,5262],{},"POST",[5224,5264,5265],{},"PUT",[5224,5267,5268],{},"DELETE",[5224,5270,5271],{},"PATCH",") відповідно до їхньої семантики: безпека, ідемпотентність, симетрія операцій.",[5201,5274,5275,5276,5279],{},"Зрозуміти практичну реалізацію ",[5205,5277,5278],{},"CRUD-операцій"," у HTTP API: створення ресурсів через POST\u002FPUT, читання через GET, оновлення через PUT\u002FPATCH, видалення через DELETE або архівування.",[5201,5281,5282,5283,5286,5287,5291],{},"Вивчити маршрутизатор ",[5205,5284,5285],{},"go-chi\u002Fchi",": структуру Radix Tree, параметри шляху (",[5288,5289,5290],"code",{},"chi.URLParam","), групування маршрутів, суб-роутери та middleware.",[5201,5293,5294,5295,5298,5299,5302],{},"Навчитися ",[5205,5296,5297],{},"серіалізації та десеріалізації JSON"," засобами пакета ",[5288,5300,5301],{},"encoding\u002Fjson",", формувати стандартизовані відповіді згідно RFC 7807 Problem Details.",[5201,5304,5305,5306,5309],{},"Побачити інтеграцію REST API з ",[5205,5307,5308],{},"гетерогенними клієнтами",": десктопними застосунками (JavaFX, C# Avalonia), мобільними (React Native), CLI-утилітами.",[5201,5311,5312,5313,5316],{},"Опанувати архітектурний патерн ",[5205,5314,5315],{},"Clean Architecture"," у контексті HTTP API: розділення на рівні Domain, Repository, UseCase та HTTP Delivery.",[5193,5318,5320],{"icon":255,"title":5319},"🛠️ Технологічний стек",[5198,5321,5322,5328,5337,5350,5359],{},[5201,5323,5324,5327],{},[5205,5325,5326],{},"Мова:"," Go 1.22+",[5201,5329,5330,5333,5334],{},[5205,5331,5332],{},"Маршрутизатор:"," ",[5288,5335,5336],{},"github.com\u002Fgo-chi\u002Fchi\u002Fv5",[5201,5338,5339,5333,5342,5259,5345,5259,5347],{},[5205,5340,5341],{},"Стандартні пакети:",[5288,5343,5344],{},"net\u002Fhttp",[5288,5346,5301],{},[5288,5348,5349],{},"context",[5201,5351,5352,5355,5356],{},[5205,5353,5354],{},"Інструменти тестування:"," Postman, cURL, HTTPie, ",[5288,5357,5358],{},"net\u002Fhttp\u002Fhttptest",[5201,5360,5361,5364],{},[5205,5362,5363],{},"Клієнтські платформи:"," JavaFX \u002F C# Avalonia (Desktop), React Native (Mobile), Go CLI",[5366,5367],"hr",{},[5369,5370,5372],"h2",{"id":5371},"історична-еволюція-від-rpc-до-http-api","Історична еволюція: від RPC до HTTP API",[5374,5375,5377],"h3",{"id":5376},"проблема-віддалених-обчислень-та-народження-rpc","Проблема віддалених обчислень та народження RPC",[5379,5380,5381,5382,5385],"p",{},"Виконання запитів користувача на віддаленому сервері є базовою задачею програмування ще з часів мейнфреймів (",[5224,5383,5384],{},"mainframes","). Ця потреба отримала новий імпульс розвитку з появою мережі ARPANET. Хоча перші високорівневі протоколи сітьової взаємодії працювали у термінах відправки повідомлень по мережі (наприклад, протокол DEL, запропонований у одному з перших RFC — RFC-5 від 1969 року), дослідники досить швидко прийшли до думки, що було б зручніше, якби звернення до віддаленого вузла мережі з точки зору сигнатури виклику нічим не відрізнялося від звернення до локальної пам'яті та локальних ресурсів.",[5379,5387,5388,5389,5392,5393,5396,5397,5400,5401,5222,5404,5407],{},"Цю концепцію суворо сформулював під назвою ",[5205,5390,5391],{},"Remote Procedure Call (RPC)"," у 1981 році співробітник знаменитої лабораторії Xerox PARC Брюс Нельсон (",[5224,5394,5395],{},"Bruce Nelson","), і він же був співавтором першої практичної імплементації запропонованої парадигми — ",[5205,5398,5399],{},"Sun RPC",", яка існує й сьогодні під назвою ",[5205,5402,5403],{},"ONC RPC",[5224,5405,5406],{},"Open Network Computing RPC",").",[5409,5410,5411,5414,5415,5418],"note",{},[5205,5412,5413],{},"Філософія RPC першого покоління:"," Головна ідея полягала у тому, щоб не розрізняти локальне та віддалене виконання коду. Вся «магія» схована всередині обгортки (",[5224,5416,5417],{},"wrapper","), яка генерує імплементацію роботи з віддаленим сервером, а з форматом передачі даних розробник взагалі не стикається. Виклик віддаленої функції виглядає точно так само, як виклик локальної.",[5379,5420,5421,5422,5222,5425,5428,5429,5222,5432,5435],{},"Перші широко розповсюджені RPC-протоколи — такі як Sun RPC, ",[5205,5423,5424],{},"Java RMI",[5224,5426,5427],{},"Remote Method Invocation","), ",[5205,5430,5431],{},"CORBA",[5224,5433,5434],{},"Common Object Request Broker Architecture",") — чітко слідували парадигмі «прозорого» віддаленого виклику. Технологія дозволила робити саме те, про що писав Нельсон: не розрізняти локальне та віддалене виконання коду.",[5374,5437,5439],{"id":5438},"криза-rpc-підходів-першого-покоління","Криза RPC-підходів першого покоління",[5379,5441,5442],{},"Зручність використування технології, однак, виявилася її ж Ахілловою п'ятою. RPC першого покоління зіткнулися з низкою фундаментальних проблем:",[5444,5445,5446,5452,5469],"ol",{},[5201,5447,5448,5451],{},[5205,5449,5450],{},"Висока складність протоколу:"," Вимога працювати з віддаленими викликами як із локальними призводить до високої складності протоколу через необхідність підтримувати різноманітні можливості високорівневих мов програмування (наприклад, передачу складних об'єктів із станом, ієрархіями наслідування, покажчиками).",[5201,5453,5454,5457,5458],{},[5205,5455,5456],{},"Платформенна залежність:"," RPC першого покоління диктують вибір мови та платформи для клієнта і сервера:",[5198,5459,5460,5463,5466],{},[5201,5461,5462],{},"Sun RPC не працював під Windows;",[5201,5464,5465],{},"Java RMI вимагав віртуальну машину Java;",[5201,5467,5468],{},"Деякі протоколи (наприклад, CORBA) декларували можливість розробки адаптерів для будь-якої мови, проте фактична імплементація виявилася вкрай складною.",[5201,5470,5471,5474,5475,5478],{},[5205,5472,5473],{},"Складність проксування та масштабування:"," Проксування запитів та шардування (",[5224,5476,5477],{},"sharding",") даних ускладнено необхідністю читати та розбирати тіло запиту, що може бути ресурсоємно. Можливість адресувати об'єкти у пам'яті віддаленого сервера так само, як локальні, накладає величезні обмеження на масштабування такої системи.",[5480,5481,5482,5485,5486,5489],"warning",{},[5205,5483,5484],{},"Фундаментальна суперечність:"," RPC-системи обіцяли абстрагувати мережу, але реальність така, що віддалений виклик ",[5205,5487,5488],{},"принципово відрізняється"," від локального: мережеві затримки, можливість втрати зв'язку, часткові збої, проблеми серіалізації складних об'єктів. Приховування цих відмінностей призводило до важких у налагодженні помилок та непередбачуваної поведінки систем.",[5374,5491,5493],{"id":5492},"http-як-універсальна-мова-інтернету","HTTP як універсальна мова інтернету",[5379,5495,5496,5497,5500],{},"Одночасно з ідеологічною кризою RPC-підходів відбувався інший процес — ",[5205,5498,5499],{},"стандартизація мережевих протоколів",". Ще на початку 1990-х спостерігалося величезне розмаїття форматів взаємодії, але поступово мережевий стек у двох точках практично повністю уніфікувався:",[5444,5502,5503,5509],{},[5201,5504,5505,5508],{},[5205,5506,5507],{},"Internet Protocol Suite (TCP\u002FIP):"," Базовий протокол IP та надбудова у вигляді TCP або UDP над ним. Сьогодні альтернативи TCP\u002FIP використовуються у вкрай обмеженому спектрі задач.",[5201,5510,5511,5514,5515,5407],{},[5205,5512,5513],{},"Система доменних імен (DNS):"," Зручна абстракція над IP-адресами, що дозволяє призначити вузлам мережі людино-читабельні синоніми (",[5224,5516,5517],{},"human-readable names",[5379,5519,5520,5521,5524,5525,5528],{},"Для передачі текстових (гіпертекстових) даних таким протоколом став ",[5205,5522,5523],{},"HTTP 0.9",", розроблений Тімом Бернерсом-Лі (",[5224,5526,5527],{},"Tim Berners-Lee",") та опублікований у 1991 році. Протокол був надзвичайно простим і описував спосіб отримати документ, відкривши TCP\u002FIP з'єднання з сервером та передавши рядок виду:",[5530,5531,5536],"pre",{"className":5532,"code":5534,"language":5535},[5533],"language-text","GET адрес_документа\n","text",[5288,5537,5534],{"__ignoreMap":5538},"",[5409,5540,5541,5544,5545,5259,5548,5259,5551,5554,5555,5222,5558,5561],{},[5205,5542,5543],{},"Філософія HTTP:"," На відміну від RPC, HTTP ніколи не намагався приховати мережеві особливості. Натомість він запропонував ",[5205,5546,5547],{},"явний",[5205,5549,5550],{},"текстовий",[5205,5552,5553],{},"стандартизований"," протокол, який легко налагоджувати, проксувати та кешувати. HTTP не обіцяв «магії», але забезпечив ",[5205,5556,5557],{},"інтероперабельність",[5224,5559,5560],{},"interoperability",") — здатність різних систем працювати разом без спеціальних налаштувань.",[5379,5563,5564,5565,5568,5569,5572],{},"Пізніше протокол був доповнений стандартом URL (",[5224,5566,5567],{},"Uniform Resource Locator","), що дозволяє деталізувати адресу документа, і далі протокол почав розвиватися стрімко: з'явилися нові методи (",[5224,5570,5571],{},"verbs",") окрім GET, статуси відповідей, заголовки, типи даних тощо.",[5379,5574,5575,5576,5579,5580,5222,5583,5407],{},"HTTP з'явився спочатку для передачі розміченого гіпертексту, що для програмних інтерфейсів підходить слабко. Однак HTML з часом еволюціонував у більш строгий та машино-читабельний ",[5205,5577,5578],{},"XML",", який швидко став одним із загальноприйнятих форматів опису викликів API. На початку 2000-х XML був швидко витіснений ще простішим та інтероперабельним ",[5205,5581,5582],{},"JSON",[5224,5584,5585],{},"JavaScript Object Notation",[5587,5588,5589,5592],"tip",{},[5205,5590,5591],{},"HTTP як третій рівень стеку:"," Оскільки HTTP був простим та зрозумілим протоколом, що дозволяв здійснювати довільні запити до віддалених серверів за їхніми доменними іменами, та швидко оброс величезною кількістю розширень над базовою функціональністю, він став другою точкою, до якої сходяться мережеві технології. Практично всі запити до API всередині TCP\u002FIP-мереж здійснюються по протоколу HTTP.",[5374,5594,5596],{"id":5595},"відродження-rpc-технології-другого-покоління","Відродження RPC: технології другого покоління",[5379,5598,5599,5600,5603],{},"У середині 1990-х років відбувається поступова відмова від RPC-фреймворків першого покоління на користь нового підходу, який пізніше Рой Філдінг у своїй дисертації 2000 року узагальнить під назвою ",[5205,5601,5602],{},"Representational State Transfer (REST)",". У новій парадигмі відношення між даними та операціями над ними перевертаються з ніг на голову:",[5198,5605,5606,5625,5632,5643,5654],{},[5201,5607,5608,5609,5612,5613,5616,5617,5620,5621,5624],{},"Клієнт ",[5205,5610,5611],{},"не викликає процедури на сервері"," з передачею параметрів — клієнт ",[5205,5614,5615],{},"вказує серверу абстрактний адрес"," (локатор) фрагмента даних (",[5224,5618,5619],{},"ресурсу"," \u002F ",[5224,5622,5623],{},"resource","), до якого він хоче застосувати операцію.",[5201,5626,5627,5628,5631],{},"Сам ",[5205,5629,5630],{},"список операцій обмежений"," та стандартизований, семантика їх чітко визначена у стандарті.",[5201,5633,5634,5635,5638,5639,5642],{},"Клієнт та сервер ",[5205,5636,5637],{},"незалежні"," та принципово не мають жодного розділеного стану (",[5224,5640,5641],{},"shared state","); усі необхідні для виконання операції параметри мають бути передані явно.",[5201,5644,5645,5646,5649,5650,5653],{},"Між клієнтом та сервером може знаходитися ",[5205,5647,5648],{},"множина проміжних вузлів"," мережі (проксі та шлюзи \u002F ",[5224,5651,5652],{},"proxies and gateways","), що не впливає на протокол.",[5201,5655,5656,5657,5660,5661,5664],{},"Сервер розмічає ",[5205,5658,5659],{},"параметри кешування"," переданих даних (представлення ресурсів \u002F ",[5224,5662,5663],{},"resource representations","), клієнт (та проміжні проксі) мають право кешувати дані відповідно до розмітки.",[5379,5666,5667,5668,5671],{},"Але неспокій дизайну API ніколи не вщухав. Починаючи з кінця 2010-х років ми спостерігаємо ",[5205,5669,5670],{},"розквіт RPC-технологій нового покоління"," — або, вірніше, комбінованих технологій, які одночасно:",[5198,5673,5674,5680,5686],{},[5201,5675,5676,5679],{},[5205,5677,5678],{},"Зручні"," у застосуванні в імперативних мовах програмування (постачаються з обгорткою, що дозволяє ефективно використовувати кодогенерацію).",[5201,5681,5682,5685],{},[5205,5683,5684],{},"Інтероперабельні"," (працюють поверх строго стандартизованих протоколів, незалежних від конкретної мови програмування).",[5201,5687,5688,5691],{},[5205,5689,5690],{},"Масштабовані"," (абстрагують поняття ресурсу та не надають прямого доступу до пам'яті сервера).",[5379,5693,5694,5695,5259,5698,5259,5701,5259,5704,5707,5708,5711],{},"Приклади таких технологій: ",[5205,5696,5697],{},"gRPC",[5205,5699,5700],{},"GraphQL",[5205,5702,5703],{},"Apache Thrift",[5205,5705,5706],{},"Apache Avro",". Цікаво, що майже всі вони (за винятком MQTT) працюють поверх протоколу HTTP. Таким чином, більшість сучасних RPC-протоколів ",[5205,5709,5710],{},"одночасно"," є HTTP API.",[5713,5714,5715],"accordion",{},[5716,5717,5720,5723,5749],"accordion-item",{"icon":5718,"label":5719},"i-lucide-help-circle","❓ Чому віддалений виклик не може бути «прозорим»?",[5379,5721,5722],{},"Тому що існують фундаментальні відмінності між локальним та віддаленим викликом:",[5444,5724,5725,5731,5737,5743],{},[5201,5726,5727,5730],{},[5205,5728,5729],{},"Мережеві затримки:"," Локальний виклик функції займає наносекунди, віддалений — мілісекунди або секунди.",[5201,5732,5733,5736],{},[5205,5734,5735],{},"Можливість відмови:"," Мережа може впасти у будь-який момент, TCP-з'єднання може розірватися, сервер може бути недоступним.",[5201,5738,5739,5742],{},[5205,5740,5741],{},"Часткові збої:"," Запит може бути доставлено, але відповідь загублено. Важко визначити, чи була операція виконана.",[5201,5744,5745,5748],{},[5205,5746,5747],{},"Серіалізація:"," Не всі об'єкти можна серіалізувати (наприклад, покажчики на функції, відкриті файлові дескриптори).",[5379,5750,5751,5752,5755,5756,5759,5760,5763],{},"Приховування цих відмінностей призводить до непередбачуваних помилок. Натомість сучасні підходи ",[5205,5753,5754],{},"явно показують",", що виклик віддалений: передають ",[5288,5757,5758],{},"context.Context"," для таймаутів, повертають ",[5288,5761,5762],{},"error"," для обробки мережевих збоїв, використовують асинхронні паттерни.",[5366,5765],{},[5369,5767,5769],{"id":5768},"архітектурний-стиль-rest-теорія-та-міфологія","Архітектурний стиль REST: теорія та міфологія",[5374,5771,5773],{"id":5772},"rest-за-філдінгом-2000-архітектурні-обмеження","REST за Філдінгом-2000: архітектурні обмеження",[5379,5775,5776,5777,5780,5781,5784,5785,5787],{},"У 2000 році Рой Філдінг (",[5224,5778,5779],{},"Roy Fielding","), один з авторів специфікацій HTTP та URI, захистив докторську дисертацію під назвою ",[5224,5782,5783],{},"«Architectural Styles and the Design of Network-based Software Architectures»"," («Архітектурні стилі та дизайн архітектури мережевого програмного забезпечення»). П'ята глава цієї дисертації називалася ",[5205,5786,5602],{},".",[5379,5789,5790,5791,5794,5795,5798],{},"Важливо зрозуміти: ця глава є ",[5205,5792,5793],{},"абстрактним оглядом"," розподіленої мережевої архітектури, взагалі не прив'язаної ні до HTTP, ні до URL. Вона не присвячена правилам дизайну API — у цій главі Філдінг методично ",[5205,5796,5797],{},"перелічує обмеження",", з якими стикається розробник розподіленого мережевого програмного забезпечення:",[5800,5801,5802,5806,5812,5816,5822,5826,5840,5844,5850,5854,5860,5864],"steps",{},[5374,5803,5805],{"id":5804},"обмеження-1-клієнт-серверна-архітектура","Обмеження 1: Клієнт-серверна архітектура",[5379,5807,5808,5811],{},[5205,5809,5810],{},"Client-Server:"," Клієнт та сервер не знають внутрішнього устрою один одного. Інтерфейс взаємодії є публічним контрактом, але імплементація прихована.",[5374,5813,5815],{"id":5814},"обмеження-2-відсутність-стану-на-сервері","Обмеження 2: Відсутність стану на сервері",[5379,5817,5818,5821],{},[5205,5819,5820],{},"Stateless:"," Сесія зберігається на клієнті. Сервер не зберігає контекст клієнта між запитами. Кожен запит містить усю необхідну інформацію для його виконання.",[5374,5823,5825],{"id":5824},"обмеження-3-кешування","Обмеження 3: Кешування",[5379,5827,5828,5831,5832,5835,5836,5839],{},[5205,5829,5830],{},"Cacheable:"," Дані повинні розмічатися як кешовані (",[5224,5833,5834],{},"cacheable",") або некешовані (",[5224,5837,5838],{},"non-cacheable","). Це дозволяє клієнтам та проміжним проксі зберігати копії даних для підвищення продуктивності.",[5374,5841,5843],{"id":5842},"обмеження-4-уніфікований-інтерфейс","Обмеження 4: Уніфікований інтерфейс",[5379,5845,5846,5849],{},[5205,5847,5848],{},"Uniform Interface:"," Інтерфейси взаємодії між компонентами повинні бути стандартизовані. Незалежно від того, який сервер стоїть за API, клієнт взаємодіє з ним однаковим чином.",[5374,5851,5853],{"id":5852},"обмеження-5-багатошаровість","Обмеження 5: Багатошаровість",[5379,5855,5856,5859],{},[5205,5857,5858],{},"Layered System:"," Мережеві системи є багатошаровими, тобто сервер може бути лише проксі до інших серверів. Клієнт не повинен знати, чи спілкується він безпосередньо з кінцевим сервером чи через проміжні вузли.",[5374,5861,5863],{"id":5862},"обмеження-6-код-за-запитом-опціонально","Обмеження 6: Код за запитом (опціонально)",[5379,5865,5866,5869],{},[5205,5867,5868],{},"Code-On-Demand (optional):"," Функціональність клієнта може бути розширена через постачання коду з сервера (наприклад, JavaScript у браузері).",[5379,5871,5872,5873,5876],{},"Саме цим REST і обмежується у дисертації Філдінга. Далі він конкретизує аспекти імплементації систем у зазначених обмеженнях, але всі вони так само є абстрактними. Наприклад: «Ключова інформаційна абстракція у REST — це ",[5205,5874,5875],{},"ресурс","; будь-яка інформація, якій можна дати найменування, може бути ресурсом».",[5409,5878,5879,5882],{},[5205,5880,5881],{},"Дисертація Філдінга — це не інструкція з написання API."," Це теоретичне дослідження архітектурних обмежень розподілених систем. Як наслідок, практично будь-яке сучасне мережеве програмне забезпечення так чи інакше відповідає принципам REST, оскільки ці обмеження є природними наслідками роботи у мережевому середовищі.",[5374,5884,5886],{"id":5885},"rest-за-філдінгом-2008-гіпермедіа-та-hateoas","REST за Філдінгом-2008: гіпермедіа та HATEOAS",[5379,5888,5889,5890,5893],{},"Ситуація ускладнилася у 2008 році, коли Філдінг випустив ",[5205,5891,5892],{},"роз'яснення",", що ж він насправді мав на увазі. У цій статті стверджується, що:",[5444,5895,5896,5906],{},[5201,5897,5898,5899,5222,5902,5905],{},"Розробка REST API повинна фокусуватися на описі ",[5205,5900,5901],{},"медіатипів",[5224,5903,5904],{},"media types","), що представляють ресурси; при цьому клієнт взагалі нічого про ці медіатипи знати не повинен заздалегідь.",[5201,5907,5908,5909,5912],{},"У REST API ",[5205,5910,5911],{},"не має бути фіксованих імен ресурсів"," та операцій над ними, клієнт повинен витягувати цю інформацію з відповідей сервера.",[5379,5914,5915,5916,5222,5919,5922],{},"REST за Філдінгом-2008 підпорядковується принципу ",[5205,5917,5918],{},"HATEOAS",[5224,5920,5921],{},"Hypermedia As The Engine Of Application State"," \u002F «Гіпермедіа як двигун стану застосунку»). Це означає, що клієнт, отримавши якимось чином посилання на точку входу у REST API, далі має бути у стані повністю вибудувати взаємодію з API, не володіючи взагалі жодним апріорним знанням про нього.",[5480,5924,5925,5928],{},[5205,5926,5927],{},"Жоден REST API у світі не відповідає REST за Філдінгом-2008."," Уявіть собі API, де клієнт не знає навіть URL-адреси для отримання списку замовлень — він має отримати цей URL з гіперпосилання у відповіді попереднього запиту. Це теоретично елегантно, але практично неможливо у реальних системах, де клієнт завжди має певні очікування щодо структури API.",[5374,5930,5932],{"id":5931},"rest-у-реальному-житті-json-over-http-api","REST у реальному житті: JSON-over-HTTP API",[5379,5934,5935,5936,5939],{},"Термін «REST API» або «RESTful API» у практичному використанні має ",[5205,5937,5938],{},"розмите значення",". За відсутністю чітких визначень тема REST API перетворилася на одне з найбільших джерел холіварів серед програмістів — притому холіварів безглуздих, оскільки популярне уявлення про REST не має майже жодного відношення до того REST, який описаний у дисертації Філдінга.",[5379,5941,5942,5943,5946,5947,5950],{},"У цій лекції ми будемо використовувати термін ",[5205,5944,5945],{},"HTTP API"," або ",[5205,5948,5949],{},"JSON-over-HTTP API"," для позначення API з такими характеристиками:",[5198,5952,5953,5956,5959,5962,5965],{},[5201,5954,5955],{},"Протоколом взаємодії є HTTP версій 1.1 та вище.",[5201,5957,5958],{},"Форматом даних є JSON (за винятком ендпоінтів, призначених для передачі файлів у інших форматах).",[5201,5960,5961],{},"В якості ідентифікаторів ресурсів використовується URL відповідно до стандарту.",[5201,5963,5964],{},"Семантика викликів HTTP-ендпоінтів відповідає специфікації.",[5201,5966,5967],{},"Жоден із веб-стандартів ніде не порушується навмисно.",[5587,5969,5970,5973],{},[5205,5971,5972],{},"Практичне визначення REST API:"," У реальному житті під «REST API» розуміють JSON-over-HTTP API, що використовує HTTP-методи відповідно до їхньої семантики (GET для читання, POST для створення, PUT для повної заміни, PATCH для часткового оновлення, DELETE для видалення), організовує URL як ієрархію ресурсів та повертає стандартні статус-коди HTTP.",[5366,5975],{},[5369,5977,5979],{"id":5978},"переваги-та-недоліки-http-api-порівняно-з-альтернативами","Переваги та недоліки HTTP API порівняно з альтернативами",[5374,5981,5983],{"id":5982},"формат-даних-json-vs-бінарні-протоколи","Формат даних: JSON vs бінарні протоколи",[5379,5985,5986,5987,5990,5991,5994],{},"Вибір технології для розробки клієнт-серверних API зводиться до вибору між ",[5205,5988,5989],{},"ресурсо-орієнтованим підходом"," (HTTP API) та одним із сучасних ",[5205,5992,5993],{},"RPC-протоколів"," (gRPC, GraphQL, Apache Thrift).",[5379,5996,5997],{},[5205,5998,5999],{},"Переваги JSON:",[5444,6001,6002,6012,6018],{},[5201,6003,6004,6007,6008,6011],{},[5205,6005,6006],{},"Людино-читабельність:"," JSON є текстовим форматом, який не вимагає додаткової розшифровки. На відміну від Protocol Buffers, де неможливо прочитати повідомлення без ",[5288,6009,6010],{},".proto","-файлу, JSON-документ майже завжди дозволяє зрозуміти, які дані в ньому описані.",[5201,6013,6014,6017],{},[5205,6015,6016],{},"Максимальна формальність:"," JSON не має конструкцій, які можуть бути по-різному витлумачені у різних архітектурах, та зручно проектується на нативні структури даних (індексні та асоціативні масиви) майже будь-якої мови програмування.",[5201,6019,6020,6023],{},[5205,6021,6022],{},"Простота налагодження:"," Запити та відповіді можна легко читати у логах, інспектувати у браузерних DevTools, копіювати та модифікувати у Postman чи cURL.",[5379,6025,6026],{},[5205,6027,6028],{},"Недоліки JSON:",[5444,6030,6031,6037],{},[5201,6032,6033,6036],{},[5205,6034,6035],{},"Надлишковість формату:"," У JSON необхідно щоразу передавати імена всіх полів, навіть якщо передається масив з великої кількості однакових об'єктів. Також є велика кількість технічних символів — лапок, дужок, ком.",[5201,6038,6039,6042],{},[5205,6040,6041],{},"Розмір даних:"," Без стиснення JSON-документи можуть бути значно більшими за бінарні формати (Protocol Buffers, FlatBuffers).",[5409,6044,6045,6048],{},[5205,6046,6047],{},"Стиснення нівелює різницю:"," Використання gzip або brotli практично нівелює різницю у розмірі JSON-документів порівняно з альтернативними бінарними форматами. Дослідження показують, що після стиснення JSON лише на 10-20% більший за Protobuf, що для більшості застосунків є цілком прийнятним компромісом за людино-читабельність.",[5374,6050,6052],{"id":6051},"машино-читабельність-метаданих","Машино-читабельність метаданих",[5379,6054,6055,6056,6059],{},"Принципова відмінність між використанням HTTP як протоколу прикладного рівня (HTTP API) та HTTP як транспорту (gRPC, GraphQL): у першому випадку ",[5205,6057,6058],{},"метадані запиту можна прочитати без читання тіла"," запиту або відповіді.",[5379,6061,6062,6063,6066],{},"Протокол HTTP дозволяє прочитати такі деталі, як метод та URL запиту, статус операції, заголовки запиту та відповіді, ",[5205,6064,6065],{},"не читаючи тіло запиту або відповіді цілком",". Для більшості протоколів вищого рівня (JSON-RPC, GraphQL) це не так: навіть якщо агент володіє підтримкою протоколу, йому необхідно прочитати та розібрати тіло відповіді.",[5379,6068,6069],{},[5205,6070,6071],{},"Переваги машино-читабельних метаданих:",[5379,6073,6074],{},"Сучасний стек взаємодії між клієнтом та сервером є багатошаровим. HTTP-запит проходить через:",[5444,6076,6077,6080,6083,6086,6096,6099],{},[5201,6078,6079],{},"Клієнтський фреймворк (Retrofit для Android, Axios для JavaScript).",[5201,6081,6082],{},"API операційної системи (сокети, TCP\u002FIP стек).",[5201,6084,6085],{},"Проміжні HTTP-проксі та балансувальники навантаження (nginx, Envoy).",[5201,6087,6088,6089,6092,6093,5407],{},"API-шлюзи (",[5224,6090,6091],{},"API Gateway",") та сервіс-меші (",[5224,6094,6095],{},"Service Mesh",[5201,6097,6098],{},"Веб-сервер на стороні бекенду (nginx, Apache).",[5201,6100,6101],{},"Серверний фреймворк (Go net\u002Fhttp, Chi, Gin).",[5379,6103,6104,6105,6108,6109,5787],{},"Головна перевага дотримання букви стандарту HTTP — ",[5205,6106,6107],{},"можливість покластися на те, що проміжні агенти вміють читати метадані"," запиту та виконувати дії з їхнім використанням — налаштовувати політику перезапитів та таймаути, логувати, кешувати, шардувати, проксувати — ",[5205,6110,6111],{},"без необхідності писати додатковий код",[6113,6114,6116],"plant-uml",{"alt":6115},"Багатошаровий стек HTTP-запиту",[5530,6117,6121],{"className":6118,"code":6119,"language":6120,"meta":5538,"style":5538},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\npackage \"Клієнт (Mobile App)\" #DBEAFE {\n    [HTTP Client Library]\n}\n\npackage \"Проміжна інфраструктура\" #F1F5F9 {\n    [CDN \u002F Proxy] #E2E8F0\n    [Load Balancer] #E2E8F0\n    [API Gateway] #E2E8F0\n}\n\npackage \"Бекенд (Go Service)\" #DCFCE7 {\n    [Web Server \u002F Router]\n    [Business Logic]\n}\n\n[HTTP Client Library] --> [CDN \u002F Proxy] : HTTP Request\n[CDN \u002F Proxy] --> [Load Balancer] : Forward\n[Load Balancer] --> [API Gateway] : Route\n[API Gateway] --> [Web Server \u002F Router] : Proxy\n[Web Server \u002F Router] --> [Business Logic] : Handle\n\nnote right of [CDN \u002F Proxy]\n  Кешування GET-запитів,\n  стиснення gzip\u002Fbrotli\nend note\n\nnote right of [API Gateway]\n  Логування, rate limiting,\n  автентифікація, CORS\nend note\n@enduml\n","plantuml",[5288,6122,6123,6131,6137,6143,6150,6156,6162,6168,6173,6179,6185,6191,6197,6202,6207,6213,6219,6225,6230,6235,6241,6247,6253,6259,6265,6270,6276,6282,6288,6294,6299,6305,6311,6317,6322],{"__ignoreMap":5538},[6124,6125,6128],"span",{"class":6126,"line":6127},"line",1,[6124,6129,6130],{},"@startuml\n",[6124,6132,6134],{"class":6126,"line":6133},2,[6124,6135,6136],{},"skinparam style plain\n",[6124,6138,6140],{"class":6126,"line":6139},3,[6124,6141,6142],{},"skinparam backgroundColor #FFFFFF\n",[6124,6144,6146],{"class":6126,"line":6145},4,[6124,6147,6149],{"emptyLinePlaceholder":6148},true,"\n",[6124,6151,6153],{"class":6126,"line":6152},5,[6124,6154,6155],{},"package \"Клієнт (Mobile App)\" #DBEAFE {\n",[6124,6157,6159],{"class":6126,"line":6158},6,[6124,6160,6161],{},"    [HTTP Client Library]\n",[6124,6163,6165],{"class":6126,"line":6164},7,[6124,6166,6167],{},"}\n",[6124,6169,6171],{"class":6126,"line":6170},8,[6124,6172,6149],{"emptyLinePlaceholder":6148},[6124,6174,6176],{"class":6126,"line":6175},9,[6124,6177,6178],{},"package \"Проміжна інфраструктура\" #F1F5F9 {\n",[6124,6180,6182],{"class":6126,"line":6181},10,[6124,6183,6184],{},"    [CDN \u002F Proxy] #E2E8F0\n",[6124,6186,6188],{"class":6126,"line":6187},11,[6124,6189,6190],{},"    [Load Balancer] #E2E8F0\n",[6124,6192,6194],{"class":6126,"line":6193},12,[6124,6195,6196],{},"    [API Gateway] #E2E8F0\n",[6124,6198,6200],{"class":6126,"line":6199},13,[6124,6201,6167],{},[6124,6203,6205],{"class":6126,"line":6204},14,[6124,6206,6149],{"emptyLinePlaceholder":6148},[6124,6208,6210],{"class":6126,"line":6209},15,[6124,6211,6212],{},"package \"Бекенд (Go Service)\" #DCFCE7 {\n",[6124,6214,6216],{"class":6126,"line":6215},16,[6124,6217,6218],{},"    [Web Server \u002F Router]\n",[6124,6220,6222],{"class":6126,"line":6221},17,[6124,6223,6224],{},"    [Business Logic]\n",[6124,6226,6228],{"class":6126,"line":6227},18,[6124,6229,6167],{},[6124,6231,6233],{"class":6126,"line":6232},19,[6124,6234,6149],{"emptyLinePlaceholder":6148},[6124,6236,6238],{"class":6126,"line":6237},20,[6124,6239,6240],{},"[HTTP Client Library] --> [CDN \u002F Proxy] : HTTP Request\n",[6124,6242,6244],{"class":6126,"line":6243},21,[6124,6245,6246],{},"[CDN \u002F Proxy] --> [Load Balancer] : Forward\n",[6124,6248,6250],{"class":6126,"line":6249},22,[6124,6251,6252],{},"[Load Balancer] --> [API Gateway] : Route\n",[6124,6254,6256],{"class":6126,"line":6255},23,[6124,6257,6258],{},"[API Gateway] --> [Web Server \u002F Router] : Proxy\n",[6124,6260,6262],{"class":6126,"line":6261},24,[6124,6263,6264],{},"[Web Server \u002F Router] --> [Business Logic] : Handle\n",[6124,6266,6268],{"class":6126,"line":6267},25,[6124,6269,6149],{"emptyLinePlaceholder":6148},[6124,6271,6273],{"class":6126,"line":6272},26,[6124,6274,6275],{},"note right of [CDN \u002F Proxy]\n",[6124,6277,6279],{"class":6126,"line":6278},27,[6124,6280,6281],{},"  Кешування GET-запитів,\n",[6124,6283,6285],{"class":6126,"line":6284},28,[6124,6286,6287],{},"  стиснення gzip\u002Fbrotli\n",[6124,6289,6291],{"class":6126,"line":6290},29,[6124,6292,6293],{},"end note\n",[6124,6295,6297],{"class":6126,"line":6296},30,[6124,6298,6149],{"emptyLinePlaceholder":6148},[6124,6300,6302],{"class":6126,"line":6301},31,[6124,6303,6304],{},"note right of [API Gateway]\n",[6124,6306,6308],{"class":6126,"line":6307},32,[6124,6309,6310],{},"  Логування, rate limiting,\n",[6124,6312,6314],{"class":6126,"line":6313},33,[6124,6315,6316],{},"  автентифікація, CORS\n",[6124,6318,6320],{"class":6126,"line":6319},34,[6124,6321,6293],{},[6124,6323,6325],{"class":6126,"line":6324},35,[6124,6326,6327],{},"@enduml\n",[5379,6329,6330,6333,6334,6337,6338,6341],{},[5205,6331,6332],{},"Недолік:"," Проміжні агенти можуть трактувати метадані ",[5205,6335,6336],{},"неправильно",". Якщо розробник API або проміжного ПЗ не знає специфікацію HTTP досконало, можуть виникнути помилки. Наприклад, деякі проксі за замовчуванням кешують ",[5288,6339,6340],{},"404 Not Found",", що може призвести до проблем, якщо ресурс з'являється пізніше.",[5374,6343,6345],{"id":6344},"вибір-технології-коли-http-api-коли-grpc","Вибір технології: коли HTTP API, коли gRPC?",[5379,6347,6348],{},[5205,6349,6350],{},"HTTP API (JSON-over-HTTP) підходить для:",[5198,6352,6353,6359,6365],{},[5201,6354,6355,6358],{},[5205,6356,6357],{},"Публічних API:"," Зрозумілий максимально широкому колу програмістів, дозволяє розробляти клієнтські застосунки практично на будь-якій платформі.",[5201,6360,6361,6364],{},[5205,6362,6363],{},"MVP та прототипів:"," Швидка розробка, величезна екосистема інструментів (Postman, Swagger UI, OpenAPI).",[5201,6366,6367,6370,6371,6374,6375,5787],{},[5205,6368,6369],{},"Вебклієнтів:"," Нативна підтримка у браузерах через ",[5288,6372,6373],{},"fetch()"," та ",[5288,6376,6377],{},"XMLHttpRequest",[5379,6379,6380],{},[5205,6381,6382],{},"gRPC підходить для:",[5198,6384,6385,6391,6400],{},[5201,6386,6387,6390],{},[5205,6388,6389],{},"Внутрішньої міжсервісної взаємодії:"," Висока продуктивність завдяки бінарній серіалізації Protocol Buffers та HTTP\u002F2.",[5201,6392,6393,6396,6397,5407],{},[5205,6394,6395],{},"Систем реального часу:"," Підтримка двонапрямлених потоків (",[5224,6398,6399],{},"bidirectional streaming",[5201,6401,6402,6405],{},[5205,6403,6404],{},"Строго типізованих контрактів:"," Contract-first підхід з кодогенерацією клієнтів для різних мов.",[5587,6407,6408,6411],{},[5205,6409,6410],{},"Гібридний підхід:"," У великих системах часто використовується комбінація: публічне API надається через JSON-over-HTTP для максимальної сумісності, а внутрішня комунікація мікросервісів відбувається через gRPC для підвищення продуктивності.",[5366,6413],{},[5369,6415,6417],{"id":6416},"складові-http-запитів-та-відповідей-детальний-розбір","Складові HTTP-запитів та відповідей: детальний розбір",[5374,6419,4121],{"id":6420},"анатомія-http-запиту",[5379,6422,6423],{},"HTTP-запит складається з наступних компонентів:",[5444,6425,6426,6435,6447,6453],{},[5201,6427,6428,5222,6431,6434],{},[5205,6429,6430],{},"Стартовий рядок",[5224,6432,6433],{},"request line","): метод, URL та версія протоколу.",[5201,6436,6437,5222,6440,6443,6444,5787],{},[5205,6438,6439],{},"Заголовки",[5224,6441,6442],{},"headers","): метаінформація у форматі ",[5288,6445,6446],{},"ключ: значення",[5201,6448,6449,6452],{},[5205,6450,6451],{},"Порожній рядок:"," Розділювач між заголовками та тілом.",[5201,6454,6455,5222,6458,6461],{},[5205,6456,6457],{},"Тіло запиту",[5224,6459,6460],{},"body","): Опціональне, містить дані (JSON, XML, форма, бінарні дані).",[5379,6463,6464],{},"Приклад повного HTTP-запиту:",[5530,6466,6470],{"className":6467,"code":6468,"language":6469,"meta":5538,"style":5538},"language-http shiki shiki-themes light-plus dark-plus dark-plus","POST \u002Fv1\u002Forders HTTP\u002F1.1\nHost: api.coffeeshop.dev\nContent-Type: application\u002Fjson\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\nContent-Length: 147\n\n{\n  \"coffee_machine_id\": 123,\n  \"recipe\": \"lungo\",\n  \"volume\": \"800ml\",\n  \"price\": {\n    \"amount\": \"10.23\",\n    \"currency\": \"UAH\"\n  }\n}\n","http",[5288,6471,6472,6492,6505,6515,6525,6535,6539,6544,6559,6571,6583,6591,6603,6613,6618],{"__ignoreMap":5538},[6124,6473,6474,6477,6481,6485,6488],{"class":6126,"line":6127},[6124,6475,5262],{"class":6476},"s8xlr",[6124,6478,6480],{"class":6479},"sHH4Y"," \u002Fv1\u002Forders ",[6124,6482,6484],{"class":6483},"su1O8","HTTP",[6124,6486,6487],{"class":6479},"\u002F",[6124,6489,6491],{"class":6490},"sJj4R","1.1\n",[6124,6493,6494,6498,6501],{"class":6126,"line":6133},[6124,6495,6497],{"class":6496},"sKtos","Host",[6124,6499,6500],{"class":6483},":",[6124,6502,6504],{"class":6503},"sbdoH"," api.coffeeshop.dev\n",[6124,6506,6507,6510,6512],{"class":6126,"line":6139},[6124,6508,6509],{"class":6496},"Content-Type",[6124,6511,6500],{"class":6483},[6124,6513,6514],{"class":6503}," application\u002Fjson\n",[6124,6516,6517,6520,6522],{"class":6126,"line":6145},[6124,6518,6519],{"class":6496},"Authorization",[6124,6521,6500],{"class":6483},[6124,6523,6524],{"class":6503}," Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n",[6124,6526,6527,6530,6532],{"class":6126,"line":6152},[6124,6528,6529],{"class":6496},"Content-Length",[6124,6531,6500],{"class":6483},[6124,6533,6534],{"class":6503}," 147\n",[6124,6536,6537],{"class":6126,"line":6158},[6124,6538,6149],{"emptyLinePlaceholder":6148},[6124,6540,6541],{"class":6126,"line":6164},[6124,6542,6543],{"class":6479},"{\n",[6124,6545,6546,6550,6553,6556],{"class":6126,"line":6170},[6124,6547,6549],{"class":6548},"sLwNe","  \"coffee_machine_id\"",[6124,6551,6552],{"class":6479},": ",[6124,6554,6555],{"class":6490},"123",[6124,6557,6558],{"class":6479},",\n",[6124,6560,6561,6564,6566,6569],{"class":6126,"line":6175},[6124,6562,6563],{"class":6548},"  \"recipe\"",[6124,6565,6552],{"class":6479},[6124,6567,6568],{"class":6503},"\"lungo\"",[6124,6570,6558],{"class":6479},[6124,6572,6573,6576,6578,6581],{"class":6126,"line":6181},[6124,6574,6575],{"class":6548},"  \"volume\"",[6124,6577,6552],{"class":6479},[6124,6579,6580],{"class":6503},"\"800ml\"",[6124,6582,6558],{"class":6479},[6124,6584,6585,6588],{"class":6126,"line":6187},[6124,6586,6587],{"class":6548},"  \"price\"",[6124,6589,6590],{"class":6479},": {\n",[6124,6592,6593,6596,6598,6601],{"class":6126,"line":6193},[6124,6594,6595],{"class":6548},"    \"amount\"",[6124,6597,6552],{"class":6479},[6124,6599,6600],{"class":6503},"\"10.23\"",[6124,6602,6558],{"class":6479},[6124,6604,6605,6608,6610],{"class":6126,"line":6199},[6124,6606,6607],{"class":6548},"    \"currency\"",[6124,6609,6552],{"class":6479},[6124,6611,6612],{"class":6503},"\"UAH\"\n",[6124,6614,6615],{"class":6126,"line":6204},[6124,6616,6617],{"class":6479},"  }\n",[6124,6619,6620],{"class":6126,"line":6209},[6124,6621,6167],{"class":6479},[5374,6623,6625],{"id":6624},"структура-url-схема-хост-шлях-параметри-запиту","Структура URL: схема, хост, шлях, параметри запиту",[5379,6627,6628,6629,5222,6632,5407],{},"URL (Uniform Resource Locator) є одиницею адресації у HTTP API. Формат URL регулюється окремим стандартом, що розробляється спільнотою ",[5205,6630,6631],{},"WHATWG",[5224,6633,6634],{},"Web Hypertext Application Technology Working Group",[5379,6636,6637],{},"URL складається з наступних компонентів:",[5530,6639,6642],{"className":6640,"code":6641,"language":5535},[5533],"https:\u002F\u002Fapi.coffeeshop.dev:443\u002Fv1\u002Forders\u002F123?include=items&format=json#section\n└───┘   └──────────────────┘ └─┘ └──────────┘ └────────────────────┘ └──────┘\nсхема        хост          порт     шлях         параметри запиту    фрагмент\n",[5288,6643,6641],{"__ignoreMap":5538},[5198,6645,6646,6663,6672,6689,6707,6728],{},[5201,6647,6648,5222,6651,6654,6655,6658,6659,6662],{},[5205,6649,6650],{},"Схема",[5224,6652,6653],{},"scheme","): Протокол звернення, у нашому випадку завжди ",[5288,6656,6657],{},"https:"," (або ",[5288,6660,6661],{},"http:"," для локальної розробки).",[5201,6664,6665,5222,6668,6671],{},[5205,6666,6667],{},"Хост",[5224,6669,6670],{},"host","): Доменне ім'я або IP-адреса сервера, може включати піддомени.",[5201,6673,6674,5222,6677,6680,6681,6684,6685,6688],{},[5205,6675,6676],{},"Порт",[5224,6678,6679],{},"port","): Опціонально, за замовчуванням ",[5288,6682,6683],{},"443"," для HTTPS та ",[5288,6686,6687],{},"80"," для HTTP.",[5201,6690,6691,5222,6694,6696,6697,5259,6700,6703,6704,6706],{},[5205,6692,6693],{},"Шлях",[5224,6695,5244],{},"): Частина URL між хостом (з портом) та символами ",[5288,6698,6699],{},"?",[5288,6701,6702],{},"#"," або кінцем рядка. Прийнято розбивати по символу ",[5288,6705,6487],{}," та працювати з кожною частиною як окремим токеном.",[5201,6708,6709,5222,6712,6714,6715,6717,6718,6720,6721,6724,6725,5787],{},[5205,6710,6711],{},"Параметри запиту",[5224,6713,5248],{},"): Частина URL після знака ",[5288,6716,6699],{}," до знака ",[5288,6719,6702],{}," або кінця рядка. Прийнято розкладати на пари ",[5288,6722,6723],{},"ключ=значення",", розділені символом ",[5288,6726,6727],{},"&",[5201,6729,6730,5222,6733,5620,6736,6714,6739,6741],{},[5205,6731,6732],{},"Фрагмент",[5224,6734,6735],{},"fragment",[5224,6737,6738],{},"anchor",[5288,6740,6702],{},". Традиційно розглядається як адресація всередині запитаного документа, тому багатьма агентами опускається при виконанні запиту.",[5409,6743,6744,6747,6748,6751],{},[5205,6745,6746],{},"Семантика частин URL:"," Стандарт HTTP та URL ",[5205,6749,6750],{},"не prescribe визначеної семантики"," значущим компонентам URL. Правила організації URL існують виключно для читабельності коду та зручності розробника. Проте дотримання усталених конвенцій критично важливе для того, щоб API був інтуїтивно зрозумілим іншим розробникам.",[5374,6753,6755],{"id":6754},"традиційна-семантика-url-у-http-api","Традиційна семантика URL у HTTP API",[5379,6757,6758],{},"У HTTP API історично склалися наступні конвенції:",[5444,6760,6761,6784],{},[5201,6762,6763,5222,6766,6769,6770,6773,6774,6780,6783],{},[5205,6764,6765],{},"Частини шляху",[5224,6767,6768],{},"path segments",") використовуються для організації ",[5205,6771,6772],{},"вкладених сутностей"," зі строгою ієрархією:",[5530,6775,6778],{"className":6776,"code":6777,"language":5535},[5533],"\u002Fpartners\u002F{partner_id}\u002Fcoffee-machines\u002F{machine_id}\n",[5288,6779,6777],{"__ignoreMap":5538},[6781,6782],"br",{},"Тут кофемашина належить строго одному партнеру, тому це відображено у вкладеній структурі URL.",[5201,6785,6786,5222,6788,6791,6792],{},[5205,6787,6711],{},[5224,6789,6790],{},"query parameters",") використовуються для:",[5198,6793,6794,6813],{},[5201,6795,6796,6799,6800,6806,6808,6809,6812],{},[5205,6797,6798],{},"Нестрогої ієрархії"," (відношення «багато до багатьох»):",[5530,6801,6804],{"className":6802,"code":6803,"language":5535},[5533],"\u002Frecipes?partner_id=\u003Cpartner_id>\n",[5288,6805,6803],{"__ignoreMap":5538},[6781,6807],{},"Рецепти можуть належати багатьом партнерам, тому ",[5288,6810,6811],{},"partner_id"," — це фільтр, а не частина ієрархії.",[5201,6814,6815,6818,6819],{},[5205,6816,6817],{},"Параметрів операції"," (фільтрація, сортування, пагінація):",[5530,6820,6823],{"className":6821,"code":6822,"language":5535},[5533],"\u002Forders?user_id=\u003Cuser_id>&status=pending&limit=50&offset=100\n",[5288,6824,6822],{"__ignoreMap":5538},[5480,6826,6827,6830,6831,6374,6834,6837,6838,6841],{},[5205,6828,6829],{},"Слеш у кінці URL:"," URL ",[5288,6832,6833],{},"\u002Forders\u002F123",[5288,6835,6836],{},"\u002Forders\u002F123\u002F"," з точки зору стандарту є ",[5205,6839,6840],{},"різними"," URL. Однак практично немає аргументів на користь того, щоб не вважати такі шляхи еквівалентними. Більшість маршрутизаторів автоматично нормалізують такі URL або налаштовуються на ігнорування фінального слеша.",[5374,6843,6845],{"id":6844},"http-заголовки-метаінформація-запиту","HTTP-заголовки: метаінформація запиту",[5379,6847,6848,6849,6852],{},"Заголовки — це ",[5205,6850,6851],{},"метаінформація",", прив'язана до запиту або відповіді. Вони можуть описувати властивості переданих даних, додаткові відомості про клієнта або сервера, або містити поля, не пов'язані безпосередньо зі змістом запиту\u002Fвідповіді.",[5379,6854,6855],{},[5205,6856,6857],{},"Ключові стандартні заголовки:",[5198,6859,6860,6869,6880,6885,6893,6899,6905],{},[5201,6861,6862,6864,6865,6868],{},[5288,6863,6497],{},": Обов'язковий заголовок, що вказує доменне ім'я сервера. Необхідний для віртуального хостингу (",[5224,6866,6867],{},"virtual hosting","), коли одна IP-адреса обслуговує багато доменів.",[5201,6870,6871,6873,6874,5259,6877,5407],{},[5288,6872,6509],{},": Вказує MIME-тип тіла запиту\u002Fвідповіді (наприклад, ",[5288,6875,6876],{},"application\u002Fjson",[5288,6878,6879],{},"multipart\u002Fform-data",[5201,6881,6882,6884],{},[5288,6883,6529],{},": Розмір тіла у байтах. Деякі проксі взагалі не пропускають запити без цього заголовка.",[5201,6886,6887,6889,6890,5407],{},[5288,6888,6519],{},": Містить облікові дані для автентифікації (наприклад, JWT-токен: ",[5288,6891,6892],{},"Bearer \u003Ctoken>",[5201,6894,6895,6898],{},[5288,6896,6897],{},"Accept",": Вказує, які типи даних клієнт готовий прийняти у відповіді.",[5201,6900,6901,6904],{},[5288,6902,6903],{},"User-Agent",": Ідентифікатор клієнтського застосунку (браузер, мобільний додаток).",[5201,6906,6907,6910],{},[5288,6908,6909],{},"Date",": Таймстемп створення запиту\u002Fвідповіді для синхронізації годинників.",[5379,6912,6913],{},[5205,6914,6915],{},"Користувацькі заголовки:",[5379,6917,6918,6919,6922],{},"Для передачі додаткових метаданих, специфічних для вашого API, рекомендується використовувати префікс у форматі ",[5288,6920,6921],{},"X-ApiName-FieldName",", щоб уникнути колізій із стандартними або майбутніми заголовками:",[5530,6924,6926],{"className":6467,"code":6925,"language":6469,"meta":5538,"style":5538},"X-CoffeeAPI-Request-ID: 7f3a8b2c-1e4d-4a9b-8c3f-2d1e4a7b9c3f\nX-CoffeeAPI-Client-Version: 2.5.1\n",[5288,6927,6928,6938],{"__ignoreMap":5538},[6124,6929,6930,6933,6935],{"class":6126,"line":6127},[6124,6931,6932],{"class":6496},"X-CoffeeAPI-Request-ID",[6124,6934,6500],{"class":6483},[6124,6936,6937],{"class":6503}," 7f3a8b2c-1e4d-4a9b-8c3f-2d1e4a7b9c3f\n",[6124,6939,6940,6943,6945],{"class":6126,"line":6133},[6124,6941,6942],{"class":6496},"X-CoffeeAPI-Client-Version",[6124,6944,6500],{"class":6483},[6124,6946,6947],{"class":6503}," 2.5.1\n",[5409,6949,6950,6953,6954,6957,6958,6960,6961,5259,6964,6967],{},[5205,6951,6952],{},"Префікс X- є застарілим, але популярним:"," Раніше рекомендувалося використовувати префікс ",[5288,6955,6956],{},"X-"," для нестандартних заголовків, але RFC 6648 від 2012 року оголосив цю практику застарілою. Проте відмови від префіксу ",[5288,6959,6956],{}," фактично не відбулося, і багато популярних нестандартних заголовків (наприклад, ",[5288,6962,6963],{},"X-Forwarded-For",[5288,6965,6966],{},"X-Request-ID",") все ще його містять.",[5374,6969,6971],{"id":6970},"http-методи-глаголи-семантика-та-побічні-ефекти","HTTP-методи (глаголи): семантика та побічні ефекти",[5379,6973,6974,6975,6978,6979,6982,6983,5259,6985,5259,6987,5259,6989,5259,6991,5787],{},"HTTP-метод визначає ",[5205,6976,6977],{},"семантику операції"," та її ",[5205,6980,6981],{},"побічні дії",". Стандарт RFC 9110 визначає вісім методів, із яких для розробки API найважливіші п'ять: ",[5288,6984,5258],{},[5288,6986,5262],{},[5288,6988,5265],{},[5288,6990,5268],{},[5288,6992,5271],{},[6994,6995,6997],"h4",{"id":6996},"таблиця-семантики-http-методів","Таблиця семантики HTTP-методів",[6999,7000,7001,7023],"table",{},[7002,7003,7004],"thead",{},[7005,7006,7007,7011,7014,7017,7020],"tr",{},[7008,7009,7010],"th",{},"Метод",[7008,7012,7013],{},"Семантика",[7008,7015,7016],{},"Безпечний",[7008,7018,7019],{},"Ідемпотентний",[7008,7021,7022],{},"Може мати тіло",[7024,7025,7026,7044,7060,7075,7090],"tbody",{},[7005,7027,7028,7033,7036,7039,7041],{},[7029,7030,7031],"td",{},[5288,7032,5258],{},[7029,7034,7035],{},"Повертає представлення ресурсу",[7029,7037,7038],{},"✅ Так",[7029,7040,7038],{},[7029,7042,7043],{},"❌ Ні (не рекомендується)",[7005,7045,7046,7050,7053,7056,7058],{},[7029,7047,7048],{},[5288,7049,5262],{},[7029,7051,7052],{},"Обробляє запит відповідно до внутрішньої семантики ресурсу",[7029,7054,7055],{},"❌ Ні",[7029,7057,7055],{},[7029,7059,7038],{},[7005,7061,7062,7066,7069,7071,7073],{},[7029,7063,7064],{},[5288,7065,5265],{},[7029,7067,7068],{},"Заміняє (повністю перезаписує) ресурс даними з тіла запиту",[7029,7070,7055],{},[7029,7072,7038],{},[7029,7074,7038],{},[7005,7076,7077,7081,7084,7086,7088],{},[7029,7078,7079],{},[5288,7080,5271],{},[7029,7082,7083],{},"Модифікує (частково перезаписує) ресурс даними з тіла запиту",[7029,7085,7055],{},[7029,7087,7055],{},[7029,7089,7038],{},[7005,7091,7092,7096,7099,7101,7103],{},[7029,7093,7094],{},[5288,7095,5268],{},[7029,7097,7098],{},"Видаляє ресурс",[7029,7100,7055],{},[7029,7102,7038],{},[7029,7104,7043],{},[5379,7106,7107],{},[5205,7108,7109],{},"Пояснення властивостей:",[5198,7111,7112,7125],{},[5201,7113,7114,5222,7117,7120,7121,7124],{},[5205,7115,7116],{},"Безпечний метод",[5224,7118,7119],{},"safe method","): Не модифікує ресурси на сервері. Виклик ",[5288,7122,7123],{},"GET \u002Forders\u002F123"," завжди має тільки читати дані, ніколи їх не змінювати.",[5201,7126,7127,5222,7130,7133,7134],{},[5205,7128,7129],{},"Ідемпотентний метод",[5224,7131,7132],{},"idempotent method","): Повторний виклик з тими самими параметрами залишає систему у тому самому стані, що й один виклик. Наприклад:",[5198,7135,7136,7145,7154],{},[5201,7137,7138,7141,7142,7144],{},[5288,7139,7140],{},"PUT \u002Forders\u002F123"," перезаписує замовлення ",[5288,7143,6555],{},". Повторний виклик з тим самим тілом не змінює результат.",[5201,7146,7147,7150,7151,7153],{},[5288,7148,7149],{},"DELETE \u002Forders\u002F123"," видаляє замовлення ",[5288,7152,6555],{},". Повторний виклик не змінює стан (замовлення вже видалено).",[5201,7155,7156,7159,7160,5787],{},[5288,7157,7158],{},"POST \u002Forders"," створює нове замовлення. Повторний виклик створить ще одне замовлення (дублікат), тому це ",[5205,7161,7162],{},"не ідемпотентно",[5587,7164,7165,7168,7169,5259,7171,7173,7174,7177,7178,7180,7181,7183],{},[5205,7166,7167],{},"URL є ключем ідемпотентності:"," Для модифікуючих ідемпотентних методів (",[5288,7170,5265],{},[5288,7172,5268],{},") ",[5205,7175,7176],{},"URL запиту є його ключем ідемпотентності",". Якщо ви викличете ",[5288,7179,7140],{}," двічі з однаковим тілом, ресурс ",[5288,7182,6833],{}," буде у тому самому стані після обох викликів.",[6994,7185,7187],{"id":7186},"симетричність-get-put-delete","Симетричність GET \u002F PUT \u002F DELETE",[5379,7189,7190,7191,5259,7193,5259,7195,7197],{},"Ідемпотентність та симетричність методів ",[5288,7192,5258],{},[5288,7194,5265],{},[5288,7196,5268],{}," означає, що:",[5444,7199,7200,7215],{},[5201,7201,7202,7203,7205,7206,7209,7210,7212,7213,5787],{},"Якщо ви викликали ",[5288,7204,7140],{}," з тілом ",[5288,7207,7208],{},"{\"status\": \"completed\"}",", то наступний ",[5288,7211,7123],{}," має повернути представлення ресурсу, що відповідає переданому у ",[5288,7214,5265],{},[5201,7216,7217,7218,7220,7221,7223,7224,5946,7226,7229],{},"Після виклику ",[5288,7219,7149],{},", наступний ",[5288,7222,7123],{}," має повернути статус ",[5288,7225,6340],{},[5288,7227,7228],{},"410 Gone"," (ресурс видалено).",[5379,7231,7232,7233,7236,7237,7239,7240,5946,7242,5787],{},"Це створює ",[5205,7234,7235],{},"консистентну модель",", де клієнт може покластися на те, що результат ",[5288,7238,5258],{}," відображає останню операцію ",[5288,7241,5265],{},[5288,7243,5268],{},[5374,7245,7247],{"id":7246},"статус-коди-http-машино-читабельні-результати-операцій","Статус-коди HTTP: машино-читабельні результати операцій",[5379,7249,7250,7251,7254],{},"Статус-код — це машино-читабельний опис результату HTTP-запиту у вигляді ",[5205,7252,7253],{},"трицифрового числа",". Усі статус-коди діляться на п'ять великих груп:",[5198,7256,7257,7266,7281,7296,7313],{},[5201,7258,7259,7262,7263,5407],{},[5205,7260,7261],{},"1xx"," — Інформаційні (рідко використовуються; приклад: ",[5288,7264,7265],{},"100 Continue",[5201,7267,7268,7271,7272,5259,7275,5259,7278,5407],{},[5205,7269,7270],{},"2xx"," — Успіх операції (",[5288,7273,7274],{},"200 OK",[5288,7276,7277],{},"201 Created",[5288,7279,7280],{},"204 No Content",[5201,7282,7283,7286,7287,5259,7290,5259,7293,5407],{},[5205,7284,7285],{},"3xx"," — Перенаправлення (",[5288,7288,7289],{},"301 Moved Permanently",[5288,7291,7292],{},"302 Found",[5288,7294,7295],{},"304 Not Modified",[5201,7297,7298,7301,7302,5259,7305,5259,7308,5259,7310,5407],{},[5205,7299,7300],{},"4xx"," — Клієнтські помилки (",[5288,7303,7304],{},"400 Bad Request",[5288,7306,7307],{},"401 Unauthorized",[5288,7309,6340],{},[5288,7311,7312],{},"422 Unprocessable Entity",[5201,7314,7315,7318,7319,5259,7322,5259,7325,5407],{},[5205,7316,7317],{},"5xx"," — Серверні помилки (",[5288,7320,7321],{},"500 Internal Server Error",[5288,7323,7324],{},"502 Bad Gateway",[5288,7326,7327],{},"503 Service Unavailable",[5409,7329,7330,7333,7334,7337,7338,7344,7345,7348,7349,5787],{},[5205,7331,7332],{},"Правило обробки невідомих кодів:"," Якщо клієнт отримує статус-код ",[5288,7335,7336],{},"xyz",", який йому невідомий, згідно зі специфікацією він ",[5205,7339,7340,7341],{},"має виконати ту дію, яку б виконав при отриманні коду ",[5288,7342,7343],{},"x00",". Наприклад, отримавши невідомий код ",[5288,7346,7347],{},"499",", клієнт має обробити його як ",[5288,7350,7304],{},[6994,7352,7354],{"id":7353},"найпопулярніші-статус-коди-для-rest-api","Найпопулярніші статус-коди для REST API",[5379,7356,7357],{},[5205,7358,7359],{},"Успішні операції (2xx):",[5198,7361,7362,7373,7385],{},[5201,7363,7364,7366,7367,5259,7369,5259,7371,5407],{},[5288,7365,7274],{},": Запит успішно оброблено, відповідь містить представлення ресурсу (використовується для ",[5288,7368,5258],{},[5288,7370,5265],{},[5288,7372,5271],{},[5201,7374,7375,7377,7378,7380,7381,7384],{},[5288,7376,7277],{},": Ресурс успішно створено (використовується для ",[5288,7379,5262],{},"). Рекомендується повертати заголовок ",[5288,7382,7383],{},"Location"," з URL нового ресурсу.",[5201,7386,7387,7389,7390,5946,7392,7394],{},[5288,7388,7280],{},": Запит успішно оброблено, але відповідь не містить тіла (використовується для ",[5288,7391,5268],{},[5288,7393,5265],{},", якщо немає чого повертати).",[5379,7396,7397],{},[5205,7398,7399],{},"Клієнтські помилки (4xx):",[5198,7401,7402,7407,7412,7418,7423,7429],{},[5201,7403,7404,7406],{},[5288,7405,7304],{},": Загальна помилка валідації запиту (некоректний JSON, відсутні обов'язкові поля).",[5201,7408,7409,7411],{},[5288,7410,7307],{},": Клієнт не автентифікований (відсутній або невалідний токен).",[5201,7413,7414,7417],{},[5288,7415,7416],{},"403 Forbidden",": Клієнт автентифікований, але не має прав на виконання операції.",[5201,7419,7420,7422],{},[5288,7421,6340],{},": Ресурс не знайдено.",[5201,7424,7425,7428],{},[5288,7426,7427],{},"409 Conflict",": Конфлікт стану (наприклад, спроба створити ресурс з ідентифікатором, який вже існує).",[5201,7430,7431,7433],{},[5288,7432,7312],{},": Запит синтаксично коректний, але семантично некоректний (наприклад, бізнес-правила не виконані).",[5379,7435,7436],{},[5205,7437,7438],{},"Серверні помилки (5xx):",[5198,7440,7441,7446,7451],{},[5201,7442,7443,7445],{},[5288,7444,7321],{},": Загальна серверна помилка.",[5201,7447,7448,7450],{},[5288,7449,7324],{},": Проксі-сервер отримав некоректну відповідь від upstream-сервера.",[5201,7452,7453,7455],{},[5288,7454,7327],{},": Сервіс тимчасово недоступний (наприклад, через перевантаження або технічне обслуговування).",[5480,7457,7458,7461,7462,7464,7465,7468,7469,5259,7472,5259,7475,5259,7478,7481,7482,7484],{},[5205,7459,7460],{},"Кешування статус-кодів:"," За замовчуванням усі ",[5288,7463,7300],{}," коди ",[5205,7466,7467],{},"не кешуються",", за винятком ",[5288,7470,7471],{},"404",[5288,7473,7474],{},"405",[5288,7476,7477],{},"410",[5288,7479,7480],{},"414",". Це може призвести до несподіваної поведінки. Наприклад, якщо ваш API повертає ",[5288,7483,7471],{}," для ресурсу, який може з'явитися пізніше, деякі клієнти або проксі можуть закешувати цю відповідь, і клієнт не дізнається про появу ресурсу, поки не спливе TTL кешу.",[5366,7486],{},[5369,7488,7490],{"id":7489},"принципи-організації-http-api-від-монолітного-ендпоінту-до-мікросервісів","Принципи організації HTTP API: від монолітного ендпоінту до мікросервісів",[5374,7492,7494],{"id":7493},"антипаттерн-монолітний-stateful-ендпоінт","Антипаттерн: монолітний Stateful-ендпоінт",[5379,7496,7497],{},"Розглянемо типову помилку у проєктуванні HTTP API. Уявімо процедуру старту застосунку: клієнт має отримати профіль поточного користувача та його активні замовлення. Інтуїтивно хочеться створити такий ендпоінт:",[5530,7499,7501],{"className":6467,"code":7500,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Fstate HTTP\u002F1.1\nAuthorization: Bearer \u003Ctoken>\n\n→ HTTP\u002F1.1 200 OK\n{\n  \"profile\": {\n    \"user_id\": \"user_123\",\n    \"name\": \"Андрій Петренко\",\n    \"email\": \"andrii@example.com\"\n  },\n  \"orders\": [\n    {\"id\": \"order_456\", \"status\": \"pending\", \"recipe\": \"espresso\"},\n    {\"id\": \"order_789\", \"status\": \"completed\", \"recipe\": \"cappuccino\"}\n  ]\n}\n",[5288,7502,7503,7516,7525,7529,7534,7538,7545,7557,7569,7579,7584,7592,7628,7659,7664],{"__ignoreMap":5538},[6124,7504,7505,7507,7510,7512,7514],{"class":6126,"line":6127},[6124,7506,5258],{"class":6476},[6124,7508,7509],{"class":6479}," \u002Fv1\u002Fstate ",[6124,7511,6484],{"class":6483},[6124,7513,6487],{"class":6479},[6124,7515,6491],{"class":6490},[6124,7517,7518,7520,7522],{"class":6126,"line":6133},[6124,7519,6519],{"class":6496},[6124,7521,6500],{"class":6483},[6124,7523,7524],{"class":6503}," Bearer \u003Ctoken>\n",[6124,7526,7527],{"class":6126,"line":6139},[6124,7528,6149],{"emptyLinePlaceholder":6148},[6124,7530,7531],{"class":6126,"line":6145},[6124,7532,7533],{"class":6479},"→ HTTP\u002F1.1 200 OK\n",[6124,7535,7536],{"class":6126,"line":6152},[6124,7537,6543],{"class":6479},[6124,7539,7540,7543],{"class":6126,"line":6158},[6124,7541,7542],{"class":6548},"  \"profile\"",[6124,7544,6590],{"class":6479},[6124,7546,7547,7550,7552,7555],{"class":6126,"line":6164},[6124,7548,7549],{"class":6548},"    \"user_id\"",[6124,7551,6552],{"class":6479},[6124,7553,7554],{"class":6503},"\"user_123\"",[6124,7556,6558],{"class":6479},[6124,7558,7559,7562,7564,7567],{"class":6126,"line":6170},[6124,7560,7561],{"class":6548},"    \"name\"",[6124,7563,6552],{"class":6479},[6124,7565,7566],{"class":6503},"\"Андрій Петренко\"",[6124,7568,6558],{"class":6479},[6124,7570,7571,7574,7576],{"class":6126,"line":6175},[6124,7572,7573],{"class":6548},"    \"email\"",[6124,7575,6552],{"class":6479},[6124,7577,7578],{"class":6503},"\"andrii@example.com\"\n",[6124,7580,7581],{"class":6126,"line":6181},[6124,7582,7583],{"class":6479},"  },\n",[6124,7585,7586,7589],{"class":6126,"line":6187},[6124,7587,7588],{"class":6548},"  \"orders\"",[6124,7590,7591],{"class":6479},": [\n",[6124,7593,7594,7597,7600,7602,7605,7607,7610,7612,7615,7617,7620,7622,7625],{"class":6126,"line":6193},[6124,7595,7596],{"class":6479},"    {",[6124,7598,7599],{"class":6548},"\"id\"",[6124,7601,6552],{"class":6479},[6124,7603,7604],{"class":6503},"\"order_456\"",[6124,7606,5259],{"class":6479},[6124,7608,7609],{"class":6548},"\"status\"",[6124,7611,6552],{"class":6479},[6124,7613,7614],{"class":6503},"\"pending\"",[6124,7616,5259],{"class":6479},[6124,7618,7619],{"class":6548},"\"recipe\"",[6124,7621,6552],{"class":6479},[6124,7623,7624],{"class":6503},"\"espresso\"",[6124,7626,7627],{"class":6479},"},\n",[6124,7629,7630,7632,7634,7636,7639,7641,7643,7645,7648,7650,7652,7654,7657],{"class":6126,"line":6199},[6124,7631,7596],{"class":6479},[6124,7633,7599],{"class":6548},[6124,7635,6552],{"class":6479},[6124,7637,7638],{"class":6503},"\"order_789\"",[6124,7640,5259],{"class":6479},[6124,7642,7609],{"class":6548},[6124,7644,6552],{"class":6479},[6124,7646,7647],{"class":6503},"\"completed\"",[6124,7649,5259],{"class":6479},[6124,7651,7619],{"class":6548},[6124,7653,6552],{"class":6479},[6124,7655,7656],{"class":6503},"\"cappuccino\"",[6124,7658,6167],{"class":6479},[6124,7660,7661],{"class":6126,"line":6204},[6124,7662,7663],{"class":6479},"  ]\n",[6124,7665,7666],{"class":6126,"line":6209},[6124,7667,6167],{"class":6479},[5379,7669,7670,7671,6500],{},"Цей підхід здається зручним, але ",[5205,7672,7673],{},"порушує кілька архітектурних принципів REST",[5444,7675,7676,7682,7688],{},[5201,7677,7678,7681],{},[5205,7679,7680],{},"Stateful-дизайн:"," Сервер має зберігати токени у пам'яті, щоб витягти з них ідентифікатор клієнта, до якого прив'язані дані. Це створює спільний стан між клієнтом і сервером.",[5201,7683,7684,7687],{},[5205,7685,7686],{},"Неможливість кешування:"," Профіль користувача змінюється рідко, а замовлення — часто. Але цей ендпоінт повертає обидва типи даних разом, тому кешувати відповідь немає сенсу.",[5201,7689,7690],{},"**Однош",[5379,7692,7693],{},"арова система:** Неможливо декомпозувати цей ендпоінт на мікросервіси, бо вся логіка зосереджена в одному місці.",[5374,7695,7697],{"id":7696},"рефакторинг-до-stateless-архітектури","Рефакторинг до Stateless-архітектури",[5379,7699,7700,7701,6500],{},"Давайте перепроєктуємо це API відповідно до принципів REST. Припустимо, ми вирішили декомпозувати монолітний бекенд на ",[5205,7702,7703],{},"чотири мікросервіси",[5198,7705,7706,7712,7718,7724],{},[5201,7707,7708,7711],{},[5205,7709,7710],{},"Сервіс A:"," Перевірка авторизаційних токенів (або використання JWT для stateless-автентифікації).",[5201,7713,7714,7717],{},[5205,7715,7716],{},"Сервіс B:"," Зберігання профілів користувачів.",[5201,7719,7720,7723],{},[5205,7721,7722],{},"Сервіс C:"," Зберігання замовлень користувачів.",[5201,7725,7726,7729],{},[5205,7727,7728],{},"Сервіс-шлюз D:"," Маршрутизує запити між мікросервісами.",[5379,7731,7732,7733,7736,7737,6500],{},"Замість одного монолітного запиту ",[5288,7734,7735],{},"GET \u002Fv1\u002Fstate"," створимо ",[5205,7738,7739],{},"два незалежні ресурси",[5530,7741,7743],{"className":6467,"code":7742,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Fprofiles\u002F{user_id} HTTP\u002F1.1\n\n→ HTTP\u002F1.1 200 OK\nCache-Control: max-age=3600\n{\n  \"user_id\": \"user_123\",\n  \"name\": \"Андрій Петренко\",\n  \"email\": \"andrii@example.com\"\n}\n",[5288,7744,7745,7758,7762,7766,7776,7780,7791,7802,7811],{"__ignoreMap":5538},[6124,7746,7747,7749,7752,7754,7756],{"class":6126,"line":6127},[6124,7748,5258],{"class":6476},[6124,7750,7751],{"class":6479}," \u002Fv1\u002Fprofiles\u002F{user_id} ",[6124,7753,6484],{"class":6483},[6124,7755,6487],{"class":6479},[6124,7757,6491],{"class":6490},[6124,7759,7760],{"class":6126,"line":6133},[6124,7761,6149],{"emptyLinePlaceholder":6148},[6124,7763,7764],{"class":6126,"line":6139},[6124,7765,7533],{"class":6479},[6124,7767,7768,7771,7773],{"class":6126,"line":6145},[6124,7769,7770],{"class":6496},"Cache-Control",[6124,7772,6500],{"class":6483},[6124,7774,7775],{"class":6503}," max-age=3600\n",[6124,7777,7778],{"class":6126,"line":6152},[6124,7779,6543],{"class":6479},[6124,7781,7782,7785,7787,7789],{"class":6126,"line":6158},[6124,7783,7784],{"class":6548},"  \"user_id\"",[6124,7786,6552],{"class":6479},[6124,7788,7554],{"class":6503},[6124,7790,6558],{"class":6479},[6124,7792,7793,7796,7798,7800],{"class":6126,"line":6164},[6124,7794,7795],{"class":6548},"  \"name\"",[6124,7797,6552],{"class":6479},[6124,7799,7566],{"class":6503},[6124,7801,6558],{"class":6479},[6124,7803,7804,7807,7809],{"class":6126,"line":6170},[6124,7805,7806],{"class":6548},"  \"email\"",[6124,7808,6552],{"class":6479},[6124,7810,7578],{"class":6503},[6124,7812,7813],{"class":6126,"line":6175},[6124,7814,6167],{"class":6479},[5530,7816,7818],{"className":6467,"code":7817,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Forders?user_id=user_123 HTTP\u002F1.1\n\n→ HTTP\u002F1.1 200 OK\nETag: \"v123abc\"\nCache-Control: no-cache\n[\n  {\"id\": \"order_456\", \"status\": \"pending\", \"recipe\": \"espresso\"},\n  {\"id\": \"order_789\", \"status\": \"completed\", \"recipe\": \"cappuccino\"}\n]\n",[5288,7819,7820,7833,7837,7841,7851,7860,7865,7894,7922],{"__ignoreMap":5538},[6124,7821,7822,7824,7827,7829,7831],{"class":6126,"line":6127},[6124,7823,5258],{"class":6476},[6124,7825,7826],{"class":6479}," \u002Fv1\u002Forders?user_id=user_123 ",[6124,7828,6484],{"class":6483},[6124,7830,6487],{"class":6479},[6124,7832,6491],{"class":6490},[6124,7834,7835],{"class":6126,"line":6133},[6124,7836,6149],{"emptyLinePlaceholder":6148},[6124,7838,7839],{"class":6126,"line":6139},[6124,7840,7533],{"class":6479},[6124,7842,7843,7846,7848],{"class":6126,"line":6145},[6124,7844,7845],{"class":6496},"ETag",[6124,7847,6500],{"class":6483},[6124,7849,7850],{"class":6503}," \"v123abc\"\n",[6124,7852,7853,7855,7857],{"class":6126,"line":6152},[6124,7854,7770],{"class":6496},[6124,7856,6500],{"class":6483},[6124,7858,7859],{"class":6503}," no-cache\n",[6124,7861,7862],{"class":6126,"line":6158},[6124,7863,7864],{"class":6479},"[\n",[6124,7866,7867,7870,7872,7874,7876,7878,7880,7882,7884,7886,7888,7890,7892],{"class":6126,"line":6164},[6124,7868,7869],{"class":6479},"  {",[6124,7871,7599],{"class":6548},[6124,7873,6552],{"class":6479},[6124,7875,7604],{"class":6503},[6124,7877,5259],{"class":6479},[6124,7879,7609],{"class":6548},[6124,7881,6552],{"class":6479},[6124,7883,7614],{"class":6503},[6124,7885,5259],{"class":6479},[6124,7887,7619],{"class":6548},[6124,7889,6552],{"class":6479},[6124,7891,7624],{"class":6503},[6124,7893,7627],{"class":6479},[6124,7895,7896,7898,7900,7902,7904,7906,7908,7910,7912,7914,7916,7918,7920],{"class":6126,"line":6170},[6124,7897,7869],{"class":6479},[6124,7899,7599],{"class":6548},[6124,7901,6552],{"class":6479},[6124,7903,7638],{"class":6503},[6124,7905,5259],{"class":6479},[6124,7907,7609],{"class":6548},[6124,7909,6552],{"class":6479},[6124,7911,7647],{"class":6503},[6124,7913,5259],{"class":6479},[6124,7915,7619],{"class":6548},[6124,7917,6552],{"class":6479},[6124,7919,7656],{"class":6503},[6124,7921,6167],{"class":6479},[6124,7923,7924],{"class":6126,"line":6175},[6124,7925,7926],{"class":6479},"]\n",[6113,7928,7930],{"alt":7929},"Рефакторинг монолітного API до мікросервісної архітектури",[5530,7931,7933],{"className":6118,"code":7932,"language":6120,"meta":5538,"style":5538},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\n\nactor \"Клієнт (Mobile)\" as Client #DBEAFE\n\npackage \"Шлюз D\" as Gateway #F1F5F9 {\n    component \"API Gateway\" as GW #E2E8F0\n    database \"Локальний кеш\" as Cache #FEF3C7\n}\n\npackage \"Сервіс B: Профілі\" as ServiceB #DCFCE7 {\n    component \"Profile Service\" as ProfileSvc\n    database \"Users DB\" as UsersDB\n}\n\npackage \"Сервіс C: Замовлення\" as ServiceC #DCFCE7 {\n    component \"Orders Service\" as OrdersSvc\n    database \"Orders DB\" as OrdersDB\n}\n\nClient -> GW : GET \u002Fv1\u002Fprofiles\u002Fuser_123\nGW -> Cache : Перевірка кешу\nCache --> GW : Cache miss\nGW -> ProfileSvc : GET \u002Fv1\u002Fprofiles\u002Fuser_123\nProfileSvc -> UsersDB : SELECT * FROM users\nUsersDB --> ProfileSvc : User data\nProfileSvc --> GW : 200 OK + Cache-Control: max-age=3600\nGW -> Cache : Зберегти у кеш\nGW --> Client : 200 OK (профіль)\n\nClient -> GW : GET \u002Fv1\u002Forders?user_id=user_123\nGW -> OrdersSvc : GET \u002Fv1\u002Forders?user_id=user_123\nOrdersSvc -> OrdersDB : SELECT * FROM orders\nOrdersDB --> OrdersSvc : Orders list\nOrdersSvc --> GW : 200 OK + ETag\nGW --> Client : 200 OK (замовлення)\n\nnote right of Cache #FEF3C7\n  Профілі кешуються на 1 годину,\n  замовлення — з умовним кешуванням\n  через ETag\nend note\n@enduml\n",[5288,7934,7935,7939,7943,7947,7951,7956,7960,7965,7970,7975,7979,7983,7988,7993,7998,8002,8006,8011,8016,8021,8025,8029,8034,8039,8044,8049,8054,8059,8064,8069,8074,8078,8083,8088,8093,8098,8104,8110,8115,8121,8127,8133,8139,8144],{"__ignoreMap":5538},[6124,7936,7937],{"class":6126,"line":6127},[6124,7938,6130],{},[6124,7940,7941],{"class":6126,"line":6133},[6124,7942,6136],{},[6124,7944,7945],{"class":6126,"line":6139},[6124,7946,6142],{},[6124,7948,7949],{"class":6126,"line":6145},[6124,7950,6149],{"emptyLinePlaceholder":6148},[6124,7952,7953],{"class":6126,"line":6152},[6124,7954,7955],{},"actor \"Клієнт (Mobile)\" as Client #DBEAFE\n",[6124,7957,7958],{"class":6126,"line":6158},[6124,7959,6149],{"emptyLinePlaceholder":6148},[6124,7961,7962],{"class":6126,"line":6164},[6124,7963,7964],{},"package \"Шлюз D\" as Gateway #F1F5F9 {\n",[6124,7966,7967],{"class":6126,"line":6170},[6124,7968,7969],{},"    component \"API Gateway\" as GW #E2E8F0\n",[6124,7971,7972],{"class":6126,"line":6175},[6124,7973,7974],{},"    database \"Локальний кеш\" as Cache #FEF3C7\n",[6124,7976,7977],{"class":6126,"line":6181},[6124,7978,6167],{},[6124,7980,7981],{"class":6126,"line":6187},[6124,7982,6149],{"emptyLinePlaceholder":6148},[6124,7984,7985],{"class":6126,"line":6193},[6124,7986,7987],{},"package \"Сервіс B: Профілі\" as ServiceB #DCFCE7 {\n",[6124,7989,7990],{"class":6126,"line":6199},[6124,7991,7992],{},"    component \"Profile Service\" as ProfileSvc\n",[6124,7994,7995],{"class":6126,"line":6204},[6124,7996,7997],{},"    database \"Users DB\" as UsersDB\n",[6124,7999,8000],{"class":6126,"line":6209},[6124,8001,6167],{},[6124,8003,8004],{"class":6126,"line":6215},[6124,8005,6149],{"emptyLinePlaceholder":6148},[6124,8007,8008],{"class":6126,"line":6221},[6124,8009,8010],{},"package \"Сервіс C: Замовлення\" as ServiceC #DCFCE7 {\n",[6124,8012,8013],{"class":6126,"line":6227},[6124,8014,8015],{},"    component \"Orders Service\" as OrdersSvc\n",[6124,8017,8018],{"class":6126,"line":6232},[6124,8019,8020],{},"    database \"Orders DB\" as OrdersDB\n",[6124,8022,8023],{"class":6126,"line":6237},[6124,8024,6167],{},[6124,8026,8027],{"class":6126,"line":6243},[6124,8028,6149],{"emptyLinePlaceholder":6148},[6124,8030,8031],{"class":6126,"line":6249},[6124,8032,8033],{},"Client -> GW : GET \u002Fv1\u002Fprofiles\u002Fuser_123\n",[6124,8035,8036],{"class":6126,"line":6255},[6124,8037,8038],{},"GW -> Cache : Перевірка кешу\n",[6124,8040,8041],{"class":6126,"line":6261},[6124,8042,8043],{},"Cache --> GW : Cache miss\n",[6124,8045,8046],{"class":6126,"line":6267},[6124,8047,8048],{},"GW -> ProfileSvc : GET \u002Fv1\u002Fprofiles\u002Fuser_123\n",[6124,8050,8051],{"class":6126,"line":6272},[6124,8052,8053],{},"ProfileSvc -> UsersDB : SELECT * FROM users\n",[6124,8055,8056],{"class":6126,"line":6278},[6124,8057,8058],{},"UsersDB --> ProfileSvc : User data\n",[6124,8060,8061],{"class":6126,"line":6284},[6124,8062,8063],{},"ProfileSvc --> GW : 200 OK + Cache-Control: max-age=3600\n",[6124,8065,8066],{"class":6126,"line":6290},[6124,8067,8068],{},"GW -> Cache : Зберегти у кеш\n",[6124,8070,8071],{"class":6126,"line":6296},[6124,8072,8073],{},"GW --> Client : 200 OK (профіль)\n",[6124,8075,8076],{"class":6126,"line":6301},[6124,8077,6149],{"emptyLinePlaceholder":6148},[6124,8079,8080],{"class":6126,"line":6307},[6124,8081,8082],{},"Client -> GW : GET \u002Fv1\u002Forders?user_id=user_123\n",[6124,8084,8085],{"class":6126,"line":6313},[6124,8086,8087],{},"GW -> OrdersSvc : GET \u002Fv1\u002Forders?user_id=user_123\n",[6124,8089,8090],{"class":6126,"line":6319},[6124,8091,8092],{},"OrdersSvc -> OrdersDB : SELECT * FROM orders\n",[6124,8094,8095],{"class":6126,"line":6324},[6124,8096,8097],{},"OrdersDB --> OrdersSvc : Orders list\n",[6124,8099,8101],{"class":6126,"line":8100},36,[6124,8102,8103],{},"OrdersSvc --> GW : 200 OK + ETag\n",[6124,8105,8107],{"class":6126,"line":8106},37,[6124,8108,8109],{},"GW --> Client : 200 OK (замовлення)\n",[6124,8111,8113],{"class":6126,"line":8112},38,[6124,8114,6149],{"emptyLinePlaceholder":6148},[6124,8116,8118],{"class":6126,"line":8117},39,[6124,8119,8120],{},"note right of Cache #FEF3C7\n",[6124,8122,8124],{"class":6126,"line":8123},40,[6124,8125,8126],{},"  Профілі кешуються на 1 годину,\n",[6124,8128,8130],{"class":6126,"line":8129},41,[6124,8131,8132],{},"  замовлення — з умовним кешуванням\n",[6124,8134,8136],{"class":6126,"line":8135},42,[6124,8137,8138],{},"  через ETag\n",[6124,8140,8142],{"class":6126,"line":8141},43,[6124,8143,6293],{},[6124,8145,8147],{"class":6126,"line":8146},44,[6124,8148,6327],{},[5379,8150,8151],{},[5205,8152,8153],{},"Переваги цього підходу:",[5444,8155,8156,8165,8177,8183],{},[5201,8157,8158,8160,8161,8164],{},[5205,8159,5820],{}," Кожен запит містить усю необхідну інформацію (",[5288,8162,8163],{},"user_id"," явно передано у URL або токені). Сервіси не зберігають стан клієнта між запитами.",[5201,8166,8167,8170,8171,8174,8175,5787],{},[5205,8168,8169],{},"Кешування:"," Профілі можна кешувати на годину (",[5288,8172,8173],{},"Cache-Control: max-age=3600","), а замовлення перевіряти через умовні запити з ",[5288,8176,7845],{},[5201,8178,8179,8182],{},[5205,8180,8181],{},"Масштабованість:"," Кожен мікросервіс можна масштабувати незалежно. Наприклад, якщо замовлень багато, можна запустити більше інстансів Сервісу C.",[5201,8184,8185,8188],{},[5205,8186,8187],{},"Уніфікований інтерфейс:"," Шлюз D може бути замінено на будь-який інший проксі або навіть на клієнтський код — всі сервіси спілкуються стандартним HTTP.",[5409,8190,8191,8194,8195,8198],{},[5205,8192,8193],{},"Stateless не означає відсутність стану взагалі:"," Мікросервіс B зберігає стан клієнта (профіль користувача), але він не зберігає ",[5205,8196,8197],{},"контекст сесії"," (токени, тимчасові дані). Stateless означає, що сервіс не залежить від даних, що зберігаються за межами його області відповідальності.",[5366,8200],{},[5369,8202,8204],{"id":8203},"проєктування-номенклатури-url-ієрархія-ресурсів-та-crud","Проєктування номенклатури URL: ієрархія ресурсів та CRUD",[5374,8206,8208],{"id":8207},"правила-організації-url-у-http-api","Правила організації URL у HTTP API",[5379,8210,8211,8212,8215],{},"Стандарти HTTP та URL ",[5205,8213,8214],{},"не визначають семантики"," частин URL (path, query). Проте історично склалися конвенції, яких варто дотримуватися для читабельності та інтуїтивності API:",[5444,8217,8218,8246,8275,8306],{},[5201,8219,8220,8223],{},[5205,8221,8222],{},"Використовуйте іменники, а не дієслова:",[5198,8224,8225,8234],{},[5201,8226,8227,8228,5259,8230,5259,8232],{},"✅ Правильно: ",[5288,8229,7123],{},[5288,8231,7158],{},[5288,8233,7149],{},[5201,8235,8236,8237,5259,8240,5259,8243],{},"❌ Неправильно: ",[5288,8238,8239],{},"GET \u002FgetOrder?id=123",[5288,8241,8242],{},"POST \u002FcreateOrder",[5288,8244,8245],{},"POST \u002FdeleteOrder",[5201,8247,8248,8251],{},[5205,8249,8250],{},"Використовуйте множину для колекцій:",[5198,8252,8253,8264],{},[5201,8254,8227,8255,5259,8258,5259,8261],{},[5288,8256,8257],{},"\u002Forders",[5288,8259,8260],{},"\u002Fusers",[5288,8262,8263],{},"\u002Fproducts",[5201,8265,8236,8266,5259,8269,5259,8272],{},[5288,8267,8268],{},"\u002Forder",[5288,8270,8271],{},"\u002Fuser",[5288,8273,8274],{},"\u002Fproduct",[5201,8276,8277,8280],{},[5205,8278,8279],{},"Дотримуйтесь єдиного стилю іменування:",[5198,8281,8282,8294],{},[5201,8283,8284,8287,8288,5259,8291],{},[5288,8285,8286],{},"kebab-case"," для шляху: ",[5288,8289,8290],{},"\u002Fcoffee-machines",[5288,8292,8293],{},"\u002Fuser-profiles",[5201,8295,8296,8299,8300,5259,8303],{},[5288,8297,8298],{},"snake_case"," для параметрів запиту та JSON-полів: ",[5288,8301,8302],{},"?user_id=123",[5288,8304,8305],{},"{\"order_id\": 456}",[5201,8307,8308,8311],{},[5205,8309,8310],{},"Версіонуйте API через шлях:",[5198,8312,8313,8321],{},[5201,8314,8227,8315,5259,8318],{},[5288,8316,8317],{},"\u002Fv1\u002Forders",[5288,8319,8320],{},"\u002Fv2\u002Forders",[5201,8322,8323,8324,8327,8328],{},"❌ Альтернативи (менш поширені): ",[5288,8325,8326],{},"?version=1",", заголовок ",[5288,8329,8330],{},"X-API-Version: 1",[5587,8332,8333,8343],{},[5379,8334,8335,8338,8339,8342],{},[5205,8336,8337],{},"Чому версія у path?"," Розміщення версії у шляху (",[5288,8340,8341],{},"\u002Fv1\u002F...",") є найпопулярнішим підходом, оскільки:",[5198,8344,8345,8348,8351],{},[5201,8346,8347],{},"Версія видна одразу у URL, що полегшує налагодження.",[5201,8349,8350],{},"Не потрібно налаштовувати спеціальні заголовки або параметри запиту.",[5201,8352,8353],{},"URL чітко показує, що це різні API, навіть якщо вони обслуговуються одним сервером.",[5374,8355,8357],{"id":8356},"crud-операції-від-теорії-до-практики","CRUD-операції: від теорії до практики",[5379,8359,8360,8361,5222,8364,8367],{},"Акронім ",[5205,8362,8363],{},"CRUD",[5224,8365,8366],{},"Create, Read, Update, Delete",") описує чотири базові операції над ресурсами. Концепція CRUD ідеально проектується на HTTP-методи:",[6999,8369,8370,8386],{},[7002,8371,8372],{},[7005,8373,8374,8377,8380,8383],{},[7008,8375,8376],{},"CRUD-операція",[7008,8378,8379],{},"HTTP-метод",[7008,8381,8382],{},"Приклад",[7008,8384,8385],{},"Опис",[7024,8387,8388,8406,8424,8442,8458],{},[7005,8389,8390,8395,8399,8403],{},[7029,8391,8392],{},[5205,8393,8394],{},"Create",[7029,8396,8397],{},[5288,8398,5262],{},[7029,8400,8401],{},[5288,8402,7158],{},[7029,8404,8405],{},"Створити нове замовлення",[7005,8407,8408,8413,8417,8421],{},[7029,8409,8410],{},[5205,8411,8412],{},"Read",[7029,8414,8415],{},[5288,8416,5258],{},[7029,8418,8419],{},[5288,8420,7123],{},[7029,8422,8423],{},"Прочитати замовлення з ID 123",[7005,8425,8426,8431,8435,8439],{},[7029,8427,8428],{},[5205,8429,8430],{},"Update",[7029,8432,8433],{},[5288,8434,5265],{},[7029,8436,8437],{},[5288,8438,7140],{},[7029,8440,8441],{},"Повністю замінити замовлення 123",[7005,8443,8444,8446,8450,8455],{},[7029,8445],{},[7029,8447,8448],{},[5288,8449,5271],{},[7029,8451,8452],{},[5288,8453,8454],{},"PATCH \u002Forders\u002F123",[7029,8456,8457],{},"Частково оновити замовлення 123",[7005,8459,8460,8465,8469,8473],{},[7029,8461,8462],{},[5205,8463,8464],{},"Delete",[7029,8466,8467],{},[5288,8468,5268],{},[7029,8470,8471],{},[5288,8472,7149],{},[7029,8474,8475],{},"Видалити замовлення 123",[6994,8477,8479],{"id":8478},"створення-ресурсів-create","Створення ресурсів (Create)",[5379,8481,8482],{},[5205,8483,8484],{},"Базовий підхід:",[5530,8486,8488],{"className":6467,"code":8487,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Forders HTTP\u002F1.1\nContent-Type: application\u002Fjson\n\n{\n  \"user_id\": \"user_123\",\n  \"recipe\": \"espresso\",\n  \"volume\": \"50ml\"\n}\n\n→ HTTP\u002F1.1 201 Created\nLocation: \u002Fv1\u002Forders\u002Forder_456\n{\n  \"id\": \"order_456\",\n  \"user_id\": \"user_123\",\n  \"recipe\": \"espresso\",\n  \"status\": \"pending\"\n}\n",[5288,8489,8490,8502,8510,8514,8518,8528,8538,8547,8551,8555,8569,8583,8587,8598,8608,8618,8628],{"__ignoreMap":5538},[6124,8491,8492,8494,8496,8498,8500],{"class":6126,"line":6127},[6124,8493,5262],{"class":6476},[6124,8495,6480],{"class":6479},[6124,8497,6484],{"class":6483},[6124,8499,6487],{"class":6479},[6124,8501,6491],{"class":6490},[6124,8503,8504,8506,8508],{"class":6126,"line":6133},[6124,8505,6509],{"class":6496},[6124,8507,6500],{"class":6483},[6124,8509,6514],{"class":6503},[6124,8511,8512],{"class":6126,"line":6139},[6124,8513,6149],{"emptyLinePlaceholder":6148},[6124,8515,8516],{"class":6126,"line":6145},[6124,8517,6543],{"class":6479},[6124,8519,8520,8522,8524,8526],{"class":6126,"line":6152},[6124,8521,7784],{"class":6548},[6124,8523,6552],{"class":6479},[6124,8525,7554],{"class":6503},[6124,8527,6558],{"class":6479},[6124,8529,8530,8532,8534,8536],{"class":6126,"line":6158},[6124,8531,6563],{"class":6548},[6124,8533,6552],{"class":6479},[6124,8535,7624],{"class":6503},[6124,8537,6558],{"class":6479},[6124,8539,8540,8542,8544],{"class":6126,"line":6164},[6124,8541,6575],{"class":6548},[6124,8543,6552],{"class":6479},[6124,8545,8546],{"class":6503},"\"50ml\"\n",[6124,8548,8549],{"class":6126,"line":6170},[6124,8550,6167],{"class":6479},[6124,8552,8553],{"class":6126,"line":6175},[6124,8554,6149],{"emptyLinePlaceholder":6148},[6124,8556,8557,8560,8563,8566],{"class":6126,"line":6181},[6124,8558,8559],{"class":6479},"→ HTTP\u002F",[6124,8561,8562],{"class":6490},"1.1",[6124,8564,8565],{"class":6490}," 201",[6124,8567,8568],{"class":6479}," Created\n",[6124,8570,8571,8574,8577,8580],{"class":6126,"line":6187},[6124,8572,8573],{"class":6479},"Location: \u002Fv",[6124,8575,8576],{"class":6490},"1",[6124,8578,8579],{"class":6479},"\u002Forders\u002Forder_",[6124,8581,8582],{"class":6490},"456\n",[6124,8584,8585],{"class":6126,"line":6193},[6124,8586,6543],{"class":6479},[6124,8588,8589,8592,8594,8596],{"class":6126,"line":6199},[6124,8590,8591],{"class":6548},"  \"id\"",[6124,8593,6552],{"class":6479},[6124,8595,7604],{"class":6503},[6124,8597,6558],{"class":6479},[6124,8599,8600,8602,8604,8606],{"class":6126,"line":6204},[6124,8601,7784],{"class":6548},[6124,8603,6552],{"class":6479},[6124,8605,7554],{"class":6503},[6124,8607,6558],{"class":6479},[6124,8609,8610,8612,8614,8616],{"class":6126,"line":6209},[6124,8611,6563],{"class":6548},[6124,8613,6552],{"class":6479},[6124,8615,7624],{"class":6503},[6124,8617,6558],{"class":6479},[6124,8619,8620,8623,8625],{"class":6126,"line":6215},[6124,8621,8622],{"class":6548},"  \"status\"",[6124,8624,6552],{"class":6479},[6124,8626,8627],{"class":6503},"\"pending\"\n",[6124,8629,8630],{"class":6126,"line":6221},[6124,8631,6167],{"class":6479},[5379,8633,8634,5333,8637,8639,8640,8643],{},[5205,8635,8636],{},"Проблема:",[5288,8638,5262],{}," за замовчуванням ",[5205,8641,8642],{},"не є ідемпотентним",". Якщо клієнт отримає таймаут і повторить запит, може бути створено два замовлення.",[5379,8645,8646],{},[5205,8647,8648],{},"Рішення 1: Токен ідемпотентності",[5530,8650,8652],{"className":6467,"code":8651,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Forders HTTP\u002F1.1\nIdempotency-Key: 7f3a8b2c-1e4d-4a9b-8c3f-2d1e4a7b9c3f\nContent-Type: application\u002Fjson\n\n{\n  \"user_id\": \"user_123\",\n  \"recipe\": \"espresso\"\n}\n",[5288,8653,8654,8666,8675,8683,8687,8691,8701,8710],{"__ignoreMap":5538},[6124,8655,8656,8658,8660,8662,8664],{"class":6126,"line":6127},[6124,8657,5262],{"class":6476},[6124,8659,6480],{"class":6479},[6124,8661,6484],{"class":6483},[6124,8663,6487],{"class":6479},[6124,8665,6491],{"class":6490},[6124,8667,8668,8671,8673],{"class":6126,"line":6133},[6124,8669,8670],{"class":6496},"Idempotency-Key",[6124,8672,6500],{"class":6483},[6124,8674,6937],{"class":6503},[6124,8676,8677,8679,8681],{"class":6126,"line":6139},[6124,8678,6509],{"class":6496},[6124,8680,6500],{"class":6483},[6124,8682,6514],{"class":6503},[6124,8684,8685],{"class":6126,"line":6145},[6124,8686,6149],{"emptyLinePlaceholder":6148},[6124,8688,8689],{"class":6126,"line":6152},[6124,8690,6543],{"class":6479},[6124,8692,8693,8695,8697,8699],{"class":6126,"line":6158},[6124,8694,7784],{"class":6548},[6124,8696,6552],{"class":6479},[6124,8698,7554],{"class":6503},[6124,8700,6558],{"class":6479},[6124,8702,8703,8705,8707],{"class":6126,"line":6164},[6124,8704,6563],{"class":6548},[6124,8706,6552],{"class":6479},[6124,8708,8709],{"class":6503},"\"espresso\"\n",[6124,8711,8712],{"class":6126,"line":6170},[6124,8713,6167],{"class":6479},[5379,8715,8716,8717,8719],{},"Сервер зберігає ",[5288,8718,8670],{}," та при повторному запиті з тим самим ключем повертає результат попередньої операції.",[5379,8721,8722],{},[5205,8723,8724],{},"Рішення 2: Схема чернетка-підтвердження",[5530,8726,8728],{"className":6467,"code":8727,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Fdrafts HTTP\u002F1.1\n{\"user_id\": \"user_123\", \"recipe\": \"espresso\"}\n\n→ 201 Created\nLocation: \u002Fv1\u002Fdrafts\u002Fdraft_789\n\nPUT \u002Fv1\u002Fdrafts\u002Fdraft_789\u002Fcommit HTTP\u002F1.1\n{\"confirm\": true}\n\n→ 200 OK\nLocation: \u002Fv1\u002Forders\u002Forder_456\n",[5288,8729,8730,8743,8765,8769,8779,8791,8795,8812,8826,8830,8840],{"__ignoreMap":5538},[6124,8731,8732,8734,8737,8739,8741],{"class":6126,"line":6127},[6124,8733,5262],{"class":6476},[6124,8735,8736],{"class":6479}," \u002Fv1\u002Fdrafts ",[6124,8738,6484],{"class":6483},[6124,8740,6487],{"class":6479},[6124,8742,6491],{"class":6490},[6124,8744,8745,8748,8751,8753,8755,8757,8759,8761,8763],{"class":6126,"line":6133},[6124,8746,8747],{"class":6479},"{",[6124,8749,8750],{"class":6548},"\"user_id\"",[6124,8752,6552],{"class":6479},[6124,8754,7554],{"class":6503},[6124,8756,5259],{"class":6479},[6124,8758,7619],{"class":6548},[6124,8760,6552],{"class":6479},[6124,8762,7624],{"class":6503},[6124,8764,6167],{"class":6479},[6124,8766,8767],{"class":6126,"line":6139},[6124,8768,6149],{"emptyLinePlaceholder":6148},[6124,8770,8771,8774,8777],{"class":6126,"line":6145},[6124,8772,8773],{"class":6479},"→ ",[6124,8775,8776],{"class":6490},"201",[6124,8778,8568],{"class":6479},[6124,8780,8781,8783,8785,8788],{"class":6126,"line":6152},[6124,8782,8573],{"class":6479},[6124,8784,8576],{"class":6490},[6124,8786,8787],{"class":6479},"\u002Fdrafts\u002Fdraft_",[6124,8789,8790],{"class":6490},"789\n",[6124,8792,8793],{"class":6126,"line":6158},[6124,8794,6149],{"emptyLinePlaceholder":6148},[6124,8796,8797,8800,8802,8804,8807,8810],{"class":6126,"line":6164},[6124,8798,8799],{"class":6479},"PUT \u002Fv",[6124,8801,8576],{"class":6490},[6124,8803,8787],{"class":6479},[6124,8805,8806],{"class":6490},"789",[6124,8808,8809],{"class":6479},"\u002Fcommit HTTP\u002F",[6124,8811,6491],{"class":6490},[6124,8813,8814,8816,8819,8821,8824],{"class":6126,"line":6170},[6124,8815,8747],{"class":6479},[6124,8817,8818],{"class":6548},"\"confirm\"",[6124,8820,6552],{"class":6479},[6124,8822,8823],{"class":6483},"true",[6124,8825,6167],{"class":6479},[6124,8827,8828],{"class":6126,"line":6175},[6124,8829,6149],{"emptyLinePlaceholder":6148},[6124,8831,8832,8834,8837],{"class":6126,"line":6181},[6124,8833,8773],{"class":6479},[6124,8835,8836],{"class":6490},"200",[6124,8838,8839],{"class":6479}," OK\n",[6124,8841,8842,8844,8846,8848],{"class":6126,"line":6187},[6124,8843,8573],{"class":6479},[6124,8845,8576],{"class":6490},[6124,8847,8579],{"class":6479},[6124,8849,8582],{"class":6490},[5379,8851,8852,8853,5407],{},"Цей підхід розділяє створення чернетки (легка операція) та підтвердження (важка операція, але ідемпотентна через ",[5288,8854,5265],{},[6994,8856,8858],{"id":8857},"читання-ресурсів-read","Читання ресурсів (Read)",[5530,8860,8862],{"className":6467,"code":8861,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\n\n→ HTTP\u002F1.1 200 OK\n{\n  \"id\": \"order_123\",\n  \"user_id\": \"user_456\",\n  \"recipe\": \"cappuccino\",\n  \"status\": \"completed\"\n}\n",[5288,8863,8864,8877,8881,8885,8889,8900,8911,8921,8930],{"__ignoreMap":5538},[6124,8865,8866,8868,8871,8873,8875],{"class":6126,"line":6127},[6124,8867,5258],{"class":6476},[6124,8869,8870],{"class":6479}," \u002Fv1\u002Forders\u002F123 ",[6124,8872,6484],{"class":6483},[6124,8874,6487],{"class":6479},[6124,8876,6491],{"class":6490},[6124,8878,8879],{"class":6126,"line":6133},[6124,8880,6149],{"emptyLinePlaceholder":6148},[6124,8882,8883],{"class":6126,"line":6139},[6124,8884,7533],{"class":6479},[6124,8886,8887],{"class":6126,"line":6145},[6124,8888,6543],{"class":6479},[6124,8890,8891,8893,8895,8898],{"class":6126,"line":6152},[6124,8892,8591],{"class":6548},[6124,8894,6552],{"class":6479},[6124,8896,8897],{"class":6503},"\"order_123\"",[6124,8899,6558],{"class":6479},[6124,8901,8902,8904,8906,8909],{"class":6126,"line":6158},[6124,8903,7784],{"class":6548},[6124,8905,6552],{"class":6479},[6124,8907,8908],{"class":6503},"\"user_456\"",[6124,8910,6558],{"class":6479},[6124,8912,8913,8915,8917,8919],{"class":6126,"line":6164},[6124,8914,6563],{"class":6548},[6124,8916,6552],{"class":6479},[6124,8918,7656],{"class":6503},[6124,8920,6558],{"class":6479},[6124,8922,8923,8925,8927],{"class":6126,"line":6170},[6124,8924,8622],{"class":6548},[6124,8926,6552],{"class":6479},[6124,8928,8929],{"class":6503},"\"completed\"\n",[6124,8931,8932],{"class":6126,"line":6175},[6124,8933,6167],{"class":6479},[5379,8935,8936],{},"Для списків з фільтрацією та пагінацією:",[5530,8938,8940],{"className":6467,"code":8939,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Forders?user_id=user_456&status=pending&limit=20&offset=0\n",[5288,8941,8942],{"__ignoreMap":5538},[6124,8943,8944,8946],{"class":6126,"line":6127},[6124,8945,5258],{"class":6476},[6124,8947,8948],{"class":6479}," \u002Fv1\u002Forders?user_id=user_456&status=pending&limit=20&offset=0\n",[5379,8950,8951,8952,6500],{},"Для складних пошукових запитів може знадобитися ",[5288,8953,5262],{},[5530,8955,8957],{"className":6467,"code":8956,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Forders\u002Fsearch HTTP\u002F1.1\n{\n  \"filters\": {\n    \"recipes\": [\"espresso\", \"cappuccino\"],\n    \"date_range\": {\"start\": \"2026-01-01\", \"end\": \"2026-12-31\"}\n  },\n  \"sort\": {\"field\": \"created_at\", \"order\": \"desc\"},\n  \"pagination\": {\"limit\": 50, \"offset\": 0}\n}\n",[5288,8958,8959,8972,8976,8983,9000,9028,9032,9059,9086],{"__ignoreMap":5538},[6124,8960,8961,8963,8966,8968,8970],{"class":6126,"line":6127},[6124,8962,5262],{"class":6476},[6124,8964,8965],{"class":6479}," \u002Fv1\u002Forders\u002Fsearch ",[6124,8967,6484],{"class":6483},[6124,8969,6487],{"class":6479},[6124,8971,6491],{"class":6490},[6124,8973,8974],{"class":6126,"line":6133},[6124,8975,6543],{"class":6479},[6124,8977,8978,8981],{"class":6126,"line":6139},[6124,8979,8980],{"class":6548},"  \"filters\"",[6124,8982,6590],{"class":6479},[6124,8984,8985,8988,8991,8993,8995,8997],{"class":6126,"line":6145},[6124,8986,8987],{"class":6548},"    \"recipes\"",[6124,8989,8990],{"class":6479},": [",[6124,8992,7624],{"class":6503},[6124,8994,5259],{"class":6479},[6124,8996,7656],{"class":6503},[6124,8998,8999],{"class":6479},"],\n",[6124,9001,9002,9005,9008,9011,9013,9016,9018,9021,9023,9026],{"class":6126,"line":6152},[6124,9003,9004],{"class":6548},"    \"date_range\"",[6124,9006,9007],{"class":6479},": {",[6124,9009,9010],{"class":6548},"\"start\"",[6124,9012,6552],{"class":6479},[6124,9014,9015],{"class":6503},"\"2026-01-01\"",[6124,9017,5259],{"class":6479},[6124,9019,9020],{"class":6548},"\"end\"",[6124,9022,6552],{"class":6479},[6124,9024,9025],{"class":6503},"\"2026-12-31\"",[6124,9027,6167],{"class":6479},[6124,9029,9030],{"class":6126,"line":6158},[6124,9031,7583],{"class":6479},[6124,9033,9034,9037,9039,9042,9044,9047,9049,9052,9054,9057],{"class":6126,"line":6164},[6124,9035,9036],{"class":6548},"  \"sort\"",[6124,9038,9007],{"class":6479},[6124,9040,9041],{"class":6548},"\"field\"",[6124,9043,6552],{"class":6479},[6124,9045,9046],{"class":6503},"\"created_at\"",[6124,9048,5259],{"class":6479},[6124,9050,9051],{"class":6548},"\"order\"",[6124,9053,6552],{"class":6479},[6124,9055,9056],{"class":6503},"\"desc\"",[6124,9058,7627],{"class":6479},[6124,9060,9061,9064,9066,9069,9071,9074,9076,9079,9081,9084],{"class":6126,"line":6170},[6124,9062,9063],{"class":6548},"  \"pagination\"",[6124,9065,9007],{"class":6479},[6124,9067,9068],{"class":6548},"\"limit\"",[6124,9070,6552],{"class":6479},[6124,9072,9073],{"class":6490},"50",[6124,9075,5259],{"class":6479},[6124,9077,9078],{"class":6548},"\"offset\"",[6124,9080,6552],{"class":6479},[6124,9082,9083],{"class":6490},"0",[6124,9085,6167],{"class":6479},[6124,9087,9088],{"class":6126,"line":6175},[6124,9089,6167],{"class":6479},[5480,9091,9092,9095,9096,9098,9099,9101],{},[5205,9093,9094],{},"Чому POST для пошуку?"," Складні фільтри важко передати через query-параметри (обмеження довжини URL, складність структур даних). Хоча ",[5288,9097,5258],{}," семантично кращий (операція безпечна), ",[5288,9100,5262],{}," дозволяє передати складну структуру у тілі запиту. Це компроміс між семантикою та практичністю.",[6994,9103,9105],{"id":9104},"оновлення-ресурсів-update","Оновлення ресурсів (Update)",[5379,9107,9108],{},[5205,9109,9110],{},"Повна заміна через PUT:",[5530,9112,9114],{"className":6467,"code":9113,"language":6469,"meta":5538,"style":5538},"PUT \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\nContent-Type: application\u002Fjson\n\n{\n  \"user_id\": \"user_456\",\n  \"recipe\": \"latte\",\n  \"volume\": \"300ml\",\n  \"status\": \"pending\"\n}\n\n→ HTTP\u002F1.1 200 OK\n{\n  \"id\": \"order_123\",\n  \"user_id\": \"user_456\",\n  \"recipe\": \"latte\",\n  \"volume\": \"300ml\",\n  \"status\": \"pending\"\n}\n",[5288,9115,9116,9128,9136,9140,9144,9154,9165,9176,9184,9188,9192,9203,9207,9217,9227,9237,9247,9255],{"__ignoreMap":5538},[6124,9117,9118,9120,9122,9124,9126],{"class":6126,"line":6127},[6124,9119,5265],{"class":6476},[6124,9121,8870],{"class":6479},[6124,9123,6484],{"class":6483},[6124,9125,6487],{"class":6479},[6124,9127,6491],{"class":6490},[6124,9129,9130,9132,9134],{"class":6126,"line":6133},[6124,9131,6509],{"class":6496},[6124,9133,6500],{"class":6483},[6124,9135,6514],{"class":6503},[6124,9137,9138],{"class":6126,"line":6139},[6124,9139,6149],{"emptyLinePlaceholder":6148},[6124,9141,9142],{"class":6126,"line":6145},[6124,9143,6543],{"class":6479},[6124,9145,9146,9148,9150,9152],{"class":6126,"line":6152},[6124,9147,7784],{"class":6548},[6124,9149,6552],{"class":6479},[6124,9151,8908],{"class":6503},[6124,9153,6558],{"class":6479},[6124,9155,9156,9158,9160,9163],{"class":6126,"line":6158},[6124,9157,6563],{"class":6548},[6124,9159,6552],{"class":6479},[6124,9161,9162],{"class":6503},"\"latte\"",[6124,9164,6558],{"class":6479},[6124,9166,9167,9169,9171,9174],{"class":6126,"line":6164},[6124,9168,6575],{"class":6548},[6124,9170,6552],{"class":6479},[6124,9172,9173],{"class":6503},"\"300ml\"",[6124,9175,6558],{"class":6479},[6124,9177,9178,9180,9182],{"class":6126,"line":6170},[6124,9179,8622],{"class":6548},[6124,9181,6552],{"class":6479},[6124,9183,8627],{"class":6503},[6124,9185,9186],{"class":6126,"line":6175},[6124,9187,6167],{"class":6479},[6124,9189,9190],{"class":6126,"line":6181},[6124,9191,6149],{"emptyLinePlaceholder":6148},[6124,9193,9194,9196,9198,9201],{"class":6126,"line":6187},[6124,9195,8559],{"class":6479},[6124,9197,8562],{"class":6490},[6124,9199,9200],{"class":6490}," 200",[6124,9202,8839],{"class":6479},[6124,9204,9205],{"class":6126,"line":6193},[6124,9206,6543],{"class":6479},[6124,9208,9209,9211,9213,9215],{"class":6126,"line":6199},[6124,9210,8591],{"class":6548},[6124,9212,6552],{"class":6479},[6124,9214,8897],{"class":6503},[6124,9216,6558],{"class":6479},[6124,9218,9219,9221,9223,9225],{"class":6126,"line":6204},[6124,9220,7784],{"class":6548},[6124,9222,6552],{"class":6479},[6124,9224,8908],{"class":6503},[6124,9226,6558],{"class":6479},[6124,9228,9229,9231,9233,9235],{"class":6126,"line":6209},[6124,9230,6563],{"class":6548},[6124,9232,6552],{"class":6479},[6124,9234,9162],{"class":6503},[6124,9236,6558],{"class":6479},[6124,9238,9239,9241,9243,9245],{"class":6126,"line":6215},[6124,9240,6575],{"class":6548},[6124,9242,6552],{"class":6479},[6124,9244,9173],{"class":6503},[6124,9246,6558],{"class":6479},[6124,9248,9249,9251,9253],{"class":6126,"line":6221},[6124,9250,8622],{"class":6548},[6124,9252,6552],{"class":6479},[6124,9254,8627],{"class":6503},[6124,9256,9257],{"class":6126,"line":6227},[6124,9258,6167],{"class":6479},[5379,9260,9261,5333,9263,9266],{},[5288,9262,5265],{},[5205,9264,9265],{},"повністю замінює"," ресурс. Усі поля, не передані у запиті, мають бути скинуті до значень за замовчуванням або видалені.",[5379,9268,9269],{},[5205,9270,9271],{},"Часткове оновлення через PATCH:",[5530,9273,9275],{"className":6467,"code":9274,"language":6469,"meta":5538,"style":5538},"PATCH \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\nContent-Type: application\u002Fjson\n\n{\n  \"status\": \"completed\"\n}\n\n→ HTTP\u002F1.1 200 OK\n{\n  \"id\": \"order_123\",\n  \"user_id\": \"user_456\",\n  \"recipe\": \"espresso\",\n  \"volume\": \"50ml\",\n  \"status\": \"completed\"\n}\n",[5288,9276,9277,9289,9297,9301,9305,9313,9317,9321,9331,9335,9345,9355,9365,9376,9384],{"__ignoreMap":5538},[6124,9278,9279,9281,9283,9285,9287],{"class":6126,"line":6127},[6124,9280,5271],{"class":6476},[6124,9282,8870],{"class":6479},[6124,9284,6484],{"class":6483},[6124,9286,6487],{"class":6479},[6124,9288,6491],{"class":6490},[6124,9290,9291,9293,9295],{"class":6126,"line":6133},[6124,9292,6509],{"class":6496},[6124,9294,6500],{"class":6483},[6124,9296,6514],{"class":6503},[6124,9298,9299],{"class":6126,"line":6139},[6124,9300,6149],{"emptyLinePlaceholder":6148},[6124,9302,9303],{"class":6126,"line":6145},[6124,9304,6543],{"class":6479},[6124,9306,9307,9309,9311],{"class":6126,"line":6152},[6124,9308,8622],{"class":6548},[6124,9310,6552],{"class":6479},[6124,9312,8929],{"class":6503},[6124,9314,9315],{"class":6126,"line":6158},[6124,9316,6167],{"class":6479},[6124,9318,9319],{"class":6126,"line":6164},[6124,9320,6149],{"emptyLinePlaceholder":6148},[6124,9322,9323,9325,9327,9329],{"class":6126,"line":6170},[6124,9324,8559],{"class":6479},[6124,9326,8562],{"class":6490},[6124,9328,9200],{"class":6490},[6124,9330,8839],{"class":6479},[6124,9332,9333],{"class":6126,"line":6175},[6124,9334,6543],{"class":6479},[6124,9336,9337,9339,9341,9343],{"class":6126,"line":6181},[6124,9338,8591],{"class":6548},[6124,9340,6552],{"class":6479},[6124,9342,8897],{"class":6503},[6124,9344,6558],{"class":6479},[6124,9346,9347,9349,9351,9353],{"class":6126,"line":6187},[6124,9348,7784],{"class":6548},[6124,9350,6552],{"class":6479},[6124,9352,8908],{"class":6503},[6124,9354,6558],{"class":6479},[6124,9356,9357,9359,9361,9363],{"class":6126,"line":6193},[6124,9358,6563],{"class":6548},[6124,9360,6552],{"class":6479},[6124,9362,7624],{"class":6503},[6124,9364,6558],{"class":6479},[6124,9366,9367,9369,9371,9374],{"class":6126,"line":6199},[6124,9368,6575],{"class":6548},[6124,9370,6552],{"class":6479},[6124,9372,9373],{"class":6503},"\"50ml\"",[6124,9375,6558],{"class":6479},[6124,9377,9378,9380,9382],{"class":6126,"line":6204},[6124,9379,8622],{"class":6548},[6124,9381,6552],{"class":6479},[6124,9383,8929],{"class":6503},[6124,9385,9386],{"class":6126,"line":6209},[6124,9387,6167],{"class":6479},[5379,9389,9390,5333,9392,9395],{},[5288,9391,5271],{},[5205,9393,9394],{},"частково модифікує"," ресурс. Оновлюються лише передані поля, інші залишаються без змін.",[5409,9397,9398,9401,9402,9404,9405,9407],{},[5205,9399,9400],{},"PATCH не є ідемпотентним:"," Формально ",[5288,9403,5271],{}," може виконувати операції, залежні від поточного стану (наприклад, інкремент лічильника). Тому повторний виклик може дати інший результат. На практиці більшість API трактують ",[5288,9406,5271],{}," як ідемпотентний, якщо операція є простою заміною полів.",[6994,9409,9411],{"id":9410},"видалення-ресурсів-delete","Видалення ресурсів (Delete)",[5379,9413,9414],{},[5205,9415,9416],{},"М'яке видалення (архівування):",[5530,9418,9420],{"className":6467,"code":9419,"language":6469,"meta":5538,"style":5538},"PUT \u002Fv1\u002Forders\u002F123\u002Farchive HTTP\u002F1.1\n\n→ HTTP\u002F1.1 204 No Content\n",[5288,9421,9422,9435,9439],{"__ignoreMap":5538},[6124,9423,9424,9426,9429,9431,9433],{"class":6126,"line":6127},[6124,9425,5265],{"class":6476},[6124,9427,9428],{"class":6479}," \u002Fv1\u002Forders\u002F123\u002Farchive ",[6124,9430,6484],{"class":6483},[6124,9432,6487],{"class":6479},[6124,9434,6491],{"class":6490},[6124,9436,9437],{"class":6126,"line":6133},[6124,9438,6149],{"emptyLinePlaceholder":6148},[6124,9440,9441],{"class":6126,"line":6139},[6124,9442,9443],{"class":6479},"→ HTTP\u002F1.1 204 No Content\n",[5379,9445,9446,9447,5946,9450,9453],{},"У сучасних системах дані рідко видаляються фізично, натомість вони ",[5205,9448,9449],{},"архівуються",[5205,9451,9452],{},"помічаються видаленими"," через зміну статусу.",[5379,9455,9456],{},[5205,9457,9458],{},"Жорстке видалення:",[5530,9460,9462],{"className":6467,"code":9461,"language":6469,"meta":5538,"style":5538},"DELETE \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\n\n→ HTTP\u002F1.1 204 No Content\n",[5288,9463,9464,9476,9480],{"__ignoreMap":5538},[6124,9465,9466,9468,9470,9472,9474],{"class":6126,"line":6127},[6124,9467,5268],{"class":6476},[6124,9469,8870],{"class":6479},[6124,9471,6484],{"class":6483},[6124,9473,6487],{"class":6479},[6124,9475,6491],{"class":6490},[6124,9477,9478],{"class":6126,"line":6133},[6124,9479,6149],{"emptyLinePlaceholder":6148},[6124,9481,9482],{"class":6126,"line":6139},[6124,9483,9443],{"class":6479},[5379,9485,9486,9487,9490,9491,5946,9493,5787],{},"Після цього ",[5288,9488,9489],{},"GET \u002Fv1\u002Forders\u002F123"," має повертати ",[5288,9492,6340],{},[5288,9494,7228],{},[9496,9497,9498,9501,9502,9505,9506,5946,9508,9510,9511,5787],"caution",{},[5205,9499,9500],{},"DELETE повинен бути ідемпотентним:"," Повторний виклик ",[5288,9503,9504],{},"DELETE \u002Fv1\u002Forders\u002F123"," не має викликати помилку, навіть якщо ресурс вже видалено. Правильна поведінка — повернути ",[5288,9507,7280],{},[5288,9509,6340],{},", але ",[5205,9512,9513],{},"не 500 Internal Server Error",[5366,9515],{},[5369,9517,9519],{"id":9518},"маршрутизатор-go-chichi-потужний-інструмент-для-rest-api","Маршрутизатор go-chi\u002Fchi: потужний інструмент для REST API",[5374,9521,9523],{"id":9522},"чому-chi-а-не-стандартний-servemux","Чому Chi, а не стандартний ServeMux?",[5379,9525,9526,9527,9530],{},"Стандартний роутер ",[5288,9528,9529],{},"http.ServeMux"," має обмежену функціональність:",[5198,9532,9533,9542,9548],{},[5201,9534,9535,9538,9539,5787],{},[5205,9536,9537],{},"Немає параметрів шляху:"," Неможливо створити маршрут виду ",[5288,9540,9541],{},"\u002Forders\u002F{id}",[5201,9543,9544,9547],{},[5205,9545,9546],{},"Немає middleware:"," Доводиться вручну обгортати обробники для логування, CORS, автентифікації.",[5201,9549,9550,9553],{},[5205,9551,9552],{},"Немає групування маршрутів:"," Складно організувати версіонування API або загальні префікси.",[5379,9555,9556,9559,9560,5787],{},[5205,9557,9558],{},"Chi"," — це легковаговий, але потужний маршрутизатор, який вирішує всі ці проблеми, залишаючись повністю сумісним зі стандартним інтерфейсом ",[5288,9561,9562],{},"http.Handler",[5374,9564,9566],{"id":9565},"встановлення-та-базове-використання","Встановлення та базове використання",[5530,9568,9572],{"className":9569,"code":9570,"language":9571,"meta":5538,"style":5538},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","go get -u github.com\u002Fgo-chi\u002Fchi\u002Fv5\n","bash",[5288,9573,9574],{"__ignoreMap":5538},[6124,9575,9576,9580,9583,9586],{"class":6126,"line":6127},[6124,9577,9579],{"class":9578},"s8Opu","go",[6124,9581,9582],{"class":6503}," get",[6124,9584,9585],{"class":6483}," -u",[6124,9587,9588],{"class":6503}," github.com\u002Fgo-chi\u002Fchi\u002Fv5\n",[5379,9590,9591],{},"Базовий приклад:",[5530,9593,9596],{"className":9594,"code":9595,"language":9579,"meta":5538,"style":5538},"language-go shiki shiki-themes light-plus dark-plus dark-plus","package main\n\nimport (\n    \"encoding\u002Fjson\"\n    \"net\u002Fhttp\"\n\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\u002Fmiddleware\"\n)\n\nfunc main() {\n    r := chi.NewRouter()\n\n    \u002F\u002F Middleware: логування запитів, відновлення після паніки\n    r.Use(middleware.Logger)\n    r.Use(middleware.Recoverer)\n\n    \u002F\u002F Маршрути\n    r.Get(\"\u002F\", homeHandler)\n    r.Get(\"\u002Fhealth\", healthCheckHandler)\n    r.Route(\"\u002Fv1\", func(r chi.Router) {\n        r.Get(\"\u002Forders\", listOrdersHandler)\n        r.Post(\"\u002Forders\", createOrderHandler)\n        r.Get(\"\u002Forders\u002F{orderID}\", getOrderHandler)\n        r.Put(\"\u002Forders\u002F{orderID}\", updateOrderHandler)\n        r.Delete(\"\u002Forders\u002F{orderID}\", deleteOrderHandler)\n    })\n\n    http.ListenAndServe(\":8080\", r)\n}\n\nfunc homeHandler(w http.ResponseWriter, r *http.Request) {\n    w.Write([]byte(\"Welcome to Coffee API\"))\n}\n\nfunc healthCheckHandler(w http.ResponseWriter, r *http.Request) {\n    json.NewEncoder(w).Encode(map[string]string{\"status\": \"healthy\"})\n}\n\nfunc listOrdersHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Витягуємо query-параметри\n    userID := r.URL.Query().Get(\"user_id\")\n    \u002F\u002F ... логіка отримання списку замовлень\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode([]map[string]interface{}{\n        {\"id\": \"order_1\", \"user_id\": userID, \"recipe\": \"espresso\"},\n    })\n}\n\nfunc getOrderHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Витягуємо параметр шляху\n    orderID := chi.URLParam(r, \"orderID\")\n    \n    \u002F\u002F ... логіка отримання замовлення за ID\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(map[string]interface{}{\n        \"id\":     orderID,\n        \"recipe\": \"cappuccino\",\n        \"status\": \"completed\",\n    })\n}\n\nfunc createOrderHandler(w http.ResponseWriter, r *http.Request) {\n    var req struct {\n        UserID string `json:\"user_id\"`\n        Recipe string `json:\"recipe\"`\n    }\n    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {\n        http.Error(w, \"Invalid JSON\", http.StatusBadRequest)\n        return\n    }\n    defer r.Body.Close()\n\n    \u002F\u002F ... логіка створення замовлення\n    w.WriteHeader(http.StatusCreated)\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(map[string]interface{}{\n        \"id\":      \"order_789\",\n        \"user_id\": req.UserID,\n        \"recipe\":  req.Recipe,\n        \"status\":  \"pending\",\n    })\n}\n\nfunc updateOrderHandler(w http.ResponseWriter, r *http.Request) {\n    orderID := chi.URLParam(r, \"orderID\")\n    \u002F\u002F ... логіка оновлення замовлення\n    w.WriteHeader(http.StatusOK)\n    json.NewEncoder(w).Encode(map[string]string{\"id\": orderID, \"status\": \"updated\"})\n}\n\nfunc deleteOrderHandler(w http.ResponseWriter, r *http.Request) {\n    orderID := chi.URLParam(r, \"orderID\")\n    \u002F\u002F ... логіка видалення замовлення\n    w.WriteHeader(http.StatusNoContent)\n}\n",[5288,9597,9598,9607,9611,9619,9624,9629,9633,9638,9643,9648,9652,9663,9683,9687,9693,9715,9734,9738,9743,9764,9784,9818,9839,9859,9879,9899,9918,9923,9927,9948,9952,9956,9992,10016,10020,10024,10055,10102,10106,10110,10141,10146,10176,10181,10207,10240,10272,10277,10282,10287,10319,10325,10351,10357,10363,10386,10417,10431,10443,10455,10460,10465,10470,10502,10517,10529,10540,10546,10599,10630,10636,10641,10661,10666,10672,10693,10716,10747,10759,10776,10793,10804,10809,10814,10819,10851,10874,10880,10900,10948,10953,10958,10990,11013,11019,11039],{"__ignoreMap":5538},[6124,9599,9600,9603],{"class":6126,"line":6127},[6124,9601,9602],{"class":6483},"package",[6124,9604,9606],{"class":9605},"sN1BT"," main\n",[6124,9608,9609],{"class":6126,"line":6133},[6124,9610,6149],{"emptyLinePlaceholder":6148},[6124,9612,9613,9616],{"class":6126,"line":6139},[6124,9614,9615],{"class":6476},"import",[6124,9617,9618],{"class":6479}," (\n",[6124,9620,9621],{"class":6126,"line":6145},[6124,9622,9623],{"class":6503},"    \"encoding\u002Fjson\"\n",[6124,9625,9626],{"class":6126,"line":6152},[6124,9627,9628],{"class":6503},"    \"net\u002Fhttp\"\n",[6124,9630,9631],{"class":6126,"line":6158},[6124,9632,6149],{"emptyLinePlaceholder":6148},[6124,9634,9635],{"class":6126,"line":6164},[6124,9636,9637],{"class":6503},"    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n",[6124,9639,9640],{"class":6126,"line":6170},[6124,9641,9642],{"class":6503},"    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\u002Fmiddleware\"\n",[6124,9644,9645],{"class":6126,"line":6175},[6124,9646,9647],{"class":6479},")\n",[6124,9649,9650],{"class":6126,"line":6181},[6124,9651,6149],{"emptyLinePlaceholder":6148},[6124,9653,9654,9657,9660],{"class":6126,"line":6187},[6124,9655,9656],{"class":6483},"func",[6124,9658,9659],{"class":9578}," main",[6124,9661,9662],{"class":6479},"() {\n",[6124,9664,9665,9669,9672,9675,9677,9680],{"class":6126,"line":6193},[6124,9666,9668],{"class":9667},"siwwj","    r",[6124,9670,9671],{"class":6479}," := ",[6124,9673,9674],{"class":9667},"chi",[6124,9676,5787],{"class":6479},[6124,9678,9679],{"class":9578},"NewRouter",[6124,9681,9682],{"class":6479},"()\n",[6124,9684,9685],{"class":6126,"line":6199},[6124,9686,6149],{"emptyLinePlaceholder":6148},[6124,9688,9689],{"class":6126,"line":6204},[6124,9690,9692],{"class":9691},"spJ8K","    \u002F\u002F Middleware: логування запитів, відновлення після паніки\n",[6124,9694,9695,9697,9699,9702,9705,9708,9710,9713],{"class":6126,"line":6209},[6124,9696,9668],{"class":9667},[6124,9698,5787],{"class":6479},[6124,9700,9701],{"class":9578},"Use",[6124,9703,9704],{"class":6479},"(",[6124,9706,9707],{"class":9667},"middleware",[6124,9709,5787],{"class":6479},[6124,9711,9712],{"class":9667},"Logger",[6124,9714,9647],{"class":6479},[6124,9716,9717,9719,9721,9723,9725,9727,9729,9732],{"class":6126,"line":6215},[6124,9718,9668],{"class":9667},[6124,9720,5787],{"class":6479},[6124,9722,9701],{"class":9578},[6124,9724,9704],{"class":6479},[6124,9726,9707],{"class":9667},[6124,9728,5787],{"class":6479},[6124,9730,9731],{"class":9667},"Recoverer",[6124,9733,9647],{"class":6479},[6124,9735,9736],{"class":6126,"line":6221},[6124,9737,6149],{"emptyLinePlaceholder":6148},[6124,9739,9740],{"class":6126,"line":6227},[6124,9741,9742],{"class":9691},"    \u002F\u002F Маршрути\n",[6124,9744,9745,9747,9749,9752,9754,9757,9759,9762],{"class":6126,"line":6232},[6124,9746,9668],{"class":9667},[6124,9748,5787],{"class":6479},[6124,9750,9751],{"class":9578},"Get",[6124,9753,9704],{"class":6479},[6124,9755,9756],{"class":6503},"\"\u002F\"",[6124,9758,5259],{"class":6479},[6124,9760,9761],{"class":9667},"homeHandler",[6124,9763,9647],{"class":6479},[6124,9765,9766,9768,9770,9772,9774,9777,9779,9782],{"class":6126,"line":6237},[6124,9767,9668],{"class":9667},[6124,9769,5787],{"class":6479},[6124,9771,9751],{"class":9578},[6124,9773,9704],{"class":6479},[6124,9775,9776],{"class":6503},"\"\u002Fhealth\"",[6124,9778,5259],{"class":6479},[6124,9780,9781],{"class":9667},"healthCheckHandler",[6124,9783,9647],{"class":6479},[6124,9785,9786,9788,9790,9793,9795,9798,9800,9802,9804,9807,9810,9812,9815],{"class":6126,"line":6243},[6124,9787,9668],{"class":9667},[6124,9789,5787],{"class":6479},[6124,9791,9792],{"class":9578},"Route",[6124,9794,9704],{"class":6479},[6124,9796,9797],{"class":6503},"\"\u002Fv1\"",[6124,9799,5259],{"class":6479},[6124,9801,9656],{"class":6483},[6124,9803,9704],{"class":6479},[6124,9805,9806],{"class":9667},"r",[6124,9808,9809],{"class":9605}," chi",[6124,9811,5787],{"class":6479},[6124,9813,9814],{"class":9605},"Router",[6124,9816,9817],{"class":6479},") {\n",[6124,9819,9820,9823,9825,9827,9829,9832,9834,9837],{"class":6126,"line":6249},[6124,9821,9822],{"class":9667},"        r",[6124,9824,5787],{"class":6479},[6124,9826,9751],{"class":9578},[6124,9828,9704],{"class":6479},[6124,9830,9831],{"class":6503},"\"\u002Forders\"",[6124,9833,5259],{"class":6479},[6124,9835,9836],{"class":9667},"listOrdersHandler",[6124,9838,9647],{"class":6479},[6124,9840,9841,9843,9845,9848,9850,9852,9854,9857],{"class":6126,"line":6255},[6124,9842,9822],{"class":9667},[6124,9844,5787],{"class":6479},[6124,9846,9847],{"class":9578},"Post",[6124,9849,9704],{"class":6479},[6124,9851,9831],{"class":6503},[6124,9853,5259],{"class":6479},[6124,9855,9856],{"class":9667},"createOrderHandler",[6124,9858,9647],{"class":6479},[6124,9860,9861,9863,9865,9867,9869,9872,9874,9877],{"class":6126,"line":6261},[6124,9862,9822],{"class":9667},[6124,9864,5787],{"class":6479},[6124,9866,9751],{"class":9578},[6124,9868,9704],{"class":6479},[6124,9870,9871],{"class":6503},"\"\u002Forders\u002F{orderID}\"",[6124,9873,5259],{"class":6479},[6124,9875,9876],{"class":9667},"getOrderHandler",[6124,9878,9647],{"class":6479},[6124,9880,9881,9883,9885,9888,9890,9892,9894,9897],{"class":6126,"line":6267},[6124,9882,9822],{"class":9667},[6124,9884,5787],{"class":6479},[6124,9886,9887],{"class":9578},"Put",[6124,9889,9704],{"class":6479},[6124,9891,9871],{"class":6503},[6124,9893,5259],{"class":6479},[6124,9895,9896],{"class":9667},"updateOrderHandler",[6124,9898,9647],{"class":6479},[6124,9900,9901,9903,9905,9907,9909,9911,9913,9916],{"class":6126,"line":6272},[6124,9902,9822],{"class":9667},[6124,9904,5787],{"class":6479},[6124,9906,8464],{"class":9578},[6124,9908,9704],{"class":6479},[6124,9910,9871],{"class":6503},[6124,9912,5259],{"class":6479},[6124,9914,9915],{"class":9667},"deleteOrderHandler",[6124,9917,9647],{"class":6479},[6124,9919,9920],{"class":6126,"line":6278},[6124,9921,9922],{"class":6479},"    })\n",[6124,9924,9925],{"class":6126,"line":6284},[6124,9926,6149],{"emptyLinePlaceholder":6148},[6124,9928,9929,9932,9934,9937,9939,9942,9944,9946],{"class":6126,"line":6290},[6124,9930,9931],{"class":9667},"    http",[6124,9933,5787],{"class":6479},[6124,9935,9936],{"class":9578},"ListenAndServe",[6124,9938,9704],{"class":6479},[6124,9940,9941],{"class":6503},"\":8080\"",[6124,9943,5259],{"class":6479},[6124,9945,9806],{"class":9667},[6124,9947,9647],{"class":6479},[6124,9949,9950],{"class":6126,"line":6296},[6124,9951,6167],{"class":6479},[6124,9953,9954],{"class":6126,"line":6301},[6124,9955,6149],{"emptyLinePlaceholder":6148},[6124,9957,9958,9960,9963,9965,9968,9971,9973,9976,9978,9980,9983,9985,9987,9990],{"class":6126,"line":6307},[6124,9959,9656],{"class":6483},[6124,9961,9962],{"class":9578}," homeHandler",[6124,9964,9704],{"class":6479},[6124,9966,9967],{"class":9667},"w",[6124,9969,9970],{"class":9605}," http",[6124,9972,5787],{"class":6479},[6124,9974,9975],{"class":9605},"ResponseWriter",[6124,9977,5259],{"class":6479},[6124,9979,9806],{"class":9667},[6124,9981,9982],{"class":6479}," *",[6124,9984,6469],{"class":9605},[6124,9986,5787],{"class":6479},[6124,9988,9989],{"class":9605},"Request",[6124,9991,9817],{"class":6479},[6124,9993,9994,9997,9999,10002,10005,10008,10010,10013],{"class":6126,"line":6313},[6124,9995,9996],{"class":9667},"    w",[6124,9998,5787],{"class":6479},[6124,10000,10001],{"class":9578},"Write",[6124,10003,10004],{"class":6479},"([]",[6124,10006,10007],{"class":9605},"byte",[6124,10009,9704],{"class":6479},[6124,10011,10012],{"class":6503},"\"Welcome to Coffee API\"",[6124,10014,10015],{"class":6479},"))\n",[6124,10017,10018],{"class":6126,"line":6319},[6124,10019,6167],{"class":6479},[6124,10021,10022],{"class":6126,"line":6324},[6124,10023,6149],{"emptyLinePlaceholder":6148},[6124,10025,10026,10028,10031,10033,10035,10037,10039,10041,10043,10045,10047,10049,10051,10053],{"class":6126,"line":8100},[6124,10027,9656],{"class":6483},[6124,10029,10030],{"class":9578}," healthCheckHandler",[6124,10032,9704],{"class":6479},[6124,10034,9967],{"class":9667},[6124,10036,9970],{"class":9605},[6124,10038,5787],{"class":6479},[6124,10040,9975],{"class":9605},[6124,10042,5259],{"class":6479},[6124,10044,9806],{"class":9667},[6124,10046,9982],{"class":6479},[6124,10048,6469],{"class":9605},[6124,10050,5787],{"class":6479},[6124,10052,9989],{"class":9605},[6124,10054,9817],{"class":6479},[6124,10056,10057,10060,10062,10065,10067,10069,10071,10074,10076,10079,10082,10085,10088,10090,10092,10094,10096,10099],{"class":6126,"line":8106},[6124,10058,10059],{"class":9667},"    json",[6124,10061,5787],{"class":6479},[6124,10063,10064],{"class":9578},"NewEncoder",[6124,10066,9704],{"class":6479},[6124,10068,9967],{"class":9667},[6124,10070,5407],{"class":6479},[6124,10072,10073],{"class":9578},"Encode",[6124,10075,9704],{"class":6479},[6124,10077,10078],{"class":6483},"map",[6124,10080,10081],{"class":6479},"[",[6124,10083,10084],{"class":9605},"string",[6124,10086,10087],{"class":6479},"]",[6124,10089,10084],{"class":9605},[6124,10091,8747],{"class":6479},[6124,10093,7609],{"class":6503},[6124,10095,6552],{"class":6479},[6124,10097,10098],{"class":6503},"\"healthy\"",[6124,10100,10101],{"class":6479},"})\n",[6124,10103,10104],{"class":6126,"line":8112},[6124,10105,6167],{"class":6479},[6124,10107,10108],{"class":6126,"line":8117},[6124,10109,6149],{"emptyLinePlaceholder":6148},[6124,10111,10112,10114,10117,10119,10121,10123,10125,10127,10129,10131,10133,10135,10137,10139],{"class":6126,"line":8123},[6124,10113,9656],{"class":6483},[6124,10115,10116],{"class":9578}," listOrdersHandler",[6124,10118,9704],{"class":6479},[6124,10120,9967],{"class":9667},[6124,10122,9970],{"class":9605},[6124,10124,5787],{"class":6479},[6124,10126,9975],{"class":9605},[6124,10128,5259],{"class":6479},[6124,10130,9806],{"class":9667},[6124,10132,9982],{"class":6479},[6124,10134,6469],{"class":9605},[6124,10136,5787],{"class":6479},[6124,10138,9989],{"class":9605},[6124,10140,9817],{"class":6479},[6124,10142,10143],{"class":6126,"line":8129},[6124,10144,10145],{"class":9691},"    \u002F\u002F Витягуємо query-параметри\n",[6124,10147,10148,10151,10153,10155,10157,10160,10162,10165,10168,10170,10172,10174],{"class":6126,"line":8135},[6124,10149,10150],{"class":9667},"    userID",[6124,10152,9671],{"class":6479},[6124,10154,9806],{"class":9667},[6124,10156,5787],{"class":6479},[6124,10158,10159],{"class":9667},"URL",[6124,10161,5787],{"class":6479},[6124,10163,10164],{"class":9578},"Query",[6124,10166,10167],{"class":6479},"().",[6124,10169,9751],{"class":9578},[6124,10171,9704],{"class":6479},[6124,10173,8750],{"class":6503},[6124,10175,9647],{"class":6479},[6124,10177,10178],{"class":6126,"line":8141},[6124,10179,10180],{"class":9691},"    \u002F\u002F ... логіка отримання списку замовлень\n",[6124,10182,10183,10185,10187,10190,10192,10195,10197,10200,10202,10205],{"class":6126,"line":8146},[6124,10184,9996],{"class":9667},[6124,10186,5787],{"class":6479},[6124,10188,10189],{"class":9578},"Header",[6124,10191,10167],{"class":6479},[6124,10193,10194],{"class":9578},"Set",[6124,10196,9704],{"class":6479},[6124,10198,10199],{"class":6503},"\"Content-Type\"",[6124,10201,5259],{"class":6479},[6124,10203,10204],{"class":6503},"\"application\u002Fjson\"",[6124,10206,9647],{"class":6479},[6124,10208,10210,10212,10214,10216,10218,10220,10222,10224,10226,10228,10230,10232,10234,10237],{"class":6126,"line":10209},45,[6124,10211,10059],{"class":9667},[6124,10213,5787],{"class":6479},[6124,10215,10064],{"class":9578},[6124,10217,9704],{"class":6479},[6124,10219,9967],{"class":9667},[6124,10221,5407],{"class":6479},[6124,10223,10073],{"class":9578},[6124,10225,10004],{"class":6479},[6124,10227,10078],{"class":6483},[6124,10229,10081],{"class":6479},[6124,10231,10084],{"class":9605},[6124,10233,10087],{"class":6479},[6124,10235,10236],{"class":6483},"interface",[6124,10238,10239],{"class":6479},"{}{\n",[6124,10241,10243,10246,10248,10250,10253,10255,10257,10259,10262,10264,10266,10268,10270],{"class":6126,"line":10242},46,[6124,10244,10245],{"class":6479},"        {",[6124,10247,7599],{"class":6503},[6124,10249,6552],{"class":6479},[6124,10251,10252],{"class":6503},"\"order_1\"",[6124,10254,5259],{"class":6479},[6124,10256,8750],{"class":6503},[6124,10258,6552],{"class":6479},[6124,10260,10261],{"class":9667},"userID",[6124,10263,5259],{"class":6479},[6124,10265,7619],{"class":6503},[6124,10267,6552],{"class":6479},[6124,10269,7624],{"class":6503},[6124,10271,7627],{"class":6479},[6124,10273,10275],{"class":6126,"line":10274},47,[6124,10276,9922],{"class":6479},[6124,10278,10280],{"class":6126,"line":10279},48,[6124,10281,6167],{"class":6479},[6124,10283,10285],{"class":6126,"line":10284},49,[6124,10286,6149],{"emptyLinePlaceholder":6148},[6124,10288,10290,10292,10295,10297,10299,10301,10303,10305,10307,10309,10311,10313,10315,10317],{"class":6126,"line":10289},50,[6124,10291,9656],{"class":6483},[6124,10293,10294],{"class":9578}," getOrderHandler",[6124,10296,9704],{"class":6479},[6124,10298,9967],{"class":9667},[6124,10300,9970],{"class":9605},[6124,10302,5787],{"class":6479},[6124,10304,9975],{"class":9605},[6124,10306,5259],{"class":6479},[6124,10308,9806],{"class":9667},[6124,10310,9982],{"class":6479},[6124,10312,6469],{"class":9605},[6124,10314,5787],{"class":6479},[6124,10316,9989],{"class":9605},[6124,10318,9817],{"class":6479},[6124,10320,10322],{"class":6126,"line":10321},51,[6124,10323,10324],{"class":9691},"    \u002F\u002F Витягуємо параметр шляху\n",[6124,10326,10328,10331,10333,10335,10337,10340,10342,10344,10346,10349],{"class":6126,"line":10327},52,[6124,10329,10330],{"class":9667},"    orderID",[6124,10332,9671],{"class":6479},[6124,10334,9674],{"class":9667},[6124,10336,5787],{"class":6479},[6124,10338,10339],{"class":9578},"URLParam",[6124,10341,9704],{"class":6479},[6124,10343,9806],{"class":9667},[6124,10345,5259],{"class":6479},[6124,10347,10348],{"class":6503},"\"orderID\"",[6124,10350,9647],{"class":6479},[6124,10352,10354],{"class":6126,"line":10353},53,[6124,10355,10356],{"class":6479},"    \n",[6124,10358,10360],{"class":6126,"line":10359},54,[6124,10361,10362],{"class":9691},"    \u002F\u002F ... логіка отримання замовлення за ID\n",[6124,10364,10366,10368,10370,10372,10374,10376,10378,10380,10382,10384],{"class":6126,"line":10365},55,[6124,10367,9996],{"class":9667},[6124,10369,5787],{"class":6479},[6124,10371,10189],{"class":9578},[6124,10373,10167],{"class":6479},[6124,10375,10194],{"class":9578},[6124,10377,9704],{"class":6479},[6124,10379,10199],{"class":6503},[6124,10381,5259],{"class":6479},[6124,10383,10204],{"class":6503},[6124,10385,9647],{"class":6479},[6124,10387,10389,10391,10393,10395,10397,10399,10401,10403,10405,10407,10409,10411,10413,10415],{"class":6126,"line":10388},56,[6124,10390,10059],{"class":9667},[6124,10392,5787],{"class":6479},[6124,10394,10064],{"class":9578},[6124,10396,9704],{"class":6479},[6124,10398,9967],{"class":9667},[6124,10400,5407],{"class":6479},[6124,10402,10073],{"class":9578},[6124,10404,9704],{"class":6479},[6124,10406,10078],{"class":6483},[6124,10408,10081],{"class":6479},[6124,10410,10084],{"class":9605},[6124,10412,10087],{"class":6479},[6124,10414,10236],{"class":6483},[6124,10416,10239],{"class":6479},[6124,10418,10420,10423,10426,10429],{"class":6126,"line":10419},57,[6124,10421,10422],{"class":6503},"        \"id\"",[6124,10424,10425],{"class":6479},":     ",[6124,10427,10428],{"class":9667},"orderID",[6124,10430,6558],{"class":6479},[6124,10432,10434,10437,10439,10441],{"class":6126,"line":10433},58,[6124,10435,10436],{"class":6503},"        \"recipe\"",[6124,10438,6552],{"class":6479},[6124,10440,7656],{"class":6503},[6124,10442,6558],{"class":6479},[6124,10444,10446,10449,10451,10453],{"class":6126,"line":10445},59,[6124,10447,10448],{"class":6503},"        \"status\"",[6124,10450,6552],{"class":6479},[6124,10452,7647],{"class":6503},[6124,10454,6558],{"class":6479},[6124,10456,10458],{"class":6126,"line":10457},60,[6124,10459,9922],{"class":6479},[6124,10461,10463],{"class":6126,"line":10462},61,[6124,10464,6167],{"class":6479},[6124,10466,10468],{"class":6126,"line":10467},62,[6124,10469,6149],{"emptyLinePlaceholder":6148},[6124,10471,10473,10475,10478,10480,10482,10484,10486,10488,10490,10492,10494,10496,10498,10500],{"class":6126,"line":10472},63,[6124,10474,9656],{"class":6483},[6124,10476,10477],{"class":9578}," createOrderHandler",[6124,10479,9704],{"class":6479},[6124,10481,9967],{"class":9667},[6124,10483,9970],{"class":9605},[6124,10485,5787],{"class":6479},[6124,10487,9975],{"class":9605},[6124,10489,5259],{"class":6479},[6124,10491,9806],{"class":9667},[6124,10493,9982],{"class":6479},[6124,10495,6469],{"class":9605},[6124,10497,5787],{"class":6479},[6124,10499,9989],{"class":9605},[6124,10501,9817],{"class":6479},[6124,10503,10505,10508,10511,10514],{"class":6126,"line":10504},64,[6124,10506,10507],{"class":6483},"    var",[6124,10509,10510],{"class":9667}," req",[6124,10512,10513],{"class":6483}," struct",[6124,10515,10516],{"class":6479}," {\n",[6124,10518,10520,10523,10526],{"class":6126,"line":10519},65,[6124,10521,10522],{"class":9667},"        UserID",[6124,10524,10525],{"class":9605}," string",[6124,10527,10528],{"class":6503}," `json:\"user_id\"`\n",[6124,10530,10532,10535,10537],{"class":6126,"line":10531},66,[6124,10533,10534],{"class":9667},"        Recipe",[6124,10536,10525],{"class":9605},[6124,10538,10539],{"class":6503}," `json:\"recipe\"`\n",[6124,10541,10543],{"class":6126,"line":10542},67,[6124,10544,10545],{"class":6479},"    }\n",[6124,10547,10549,10552,10555,10557,10560,10562,10565,10567,10569,10571,10574,10576,10579,10582,10585,10588,10591,10594,10597],{"class":6126,"line":10548},68,[6124,10550,10551],{"class":6476},"    if",[6124,10553,10554],{"class":9667}," err",[6124,10556,9671],{"class":6479},[6124,10558,10559],{"class":9667},"json",[6124,10561,5787],{"class":6479},[6124,10563,10564],{"class":9578},"NewDecoder",[6124,10566,9704],{"class":6479},[6124,10568,9806],{"class":9667},[6124,10570,5787],{"class":6479},[6124,10572,10573],{"class":9667},"Body",[6124,10575,5407],{"class":6479},[6124,10577,10578],{"class":9578},"Decode",[6124,10580,10581],{"class":6479},"(&",[6124,10583,10584],{"class":9667},"req",[6124,10586,10587],{"class":6479},"); ",[6124,10589,10590],{"class":9667},"err",[6124,10592,10593],{"class":6479}," != ",[6124,10595,10596],{"class":6483},"nil",[6124,10598,10516],{"class":6479},[6124,10600,10602,10605,10607,10610,10612,10614,10616,10619,10621,10623,10625,10628],{"class":6126,"line":10601},69,[6124,10603,10604],{"class":9667},"        http",[6124,10606,5787],{"class":6479},[6124,10608,10609],{"class":9578},"Error",[6124,10611,9704],{"class":6479},[6124,10613,9967],{"class":9667},[6124,10615,5259],{"class":6479},[6124,10617,10618],{"class":6503},"\"Invalid JSON\"",[6124,10620,5259],{"class":6479},[6124,10622,6469],{"class":9667},[6124,10624,5787],{"class":6479},[6124,10626,10627],{"class":9667},"StatusBadRequest",[6124,10629,9647],{"class":6479},[6124,10631,10633],{"class":6126,"line":10632},70,[6124,10634,10635],{"class":6476},"        return\n",[6124,10637,10639],{"class":6126,"line":10638},71,[6124,10640,10545],{"class":6479},[6124,10642,10644,10647,10650,10652,10654,10656,10659],{"class":6126,"line":10643},72,[6124,10645,10646],{"class":6476},"    defer",[6124,10648,10649],{"class":9667}," r",[6124,10651,5787],{"class":6479},[6124,10653,10573],{"class":9667},[6124,10655,5787],{"class":6479},[6124,10657,10658],{"class":9578},"Close",[6124,10660,9682],{"class":6479},[6124,10662,10664],{"class":6126,"line":10663},73,[6124,10665,6149],{"emptyLinePlaceholder":6148},[6124,10667,10669],{"class":6126,"line":10668},74,[6124,10670,10671],{"class":9691},"    \u002F\u002F ... логіка створення замовлення\n",[6124,10673,10675,10677,10679,10682,10684,10686,10688,10691],{"class":6126,"line":10674},75,[6124,10676,9996],{"class":9667},[6124,10678,5787],{"class":6479},[6124,10680,10681],{"class":9578},"WriteHeader",[6124,10683,9704],{"class":6479},[6124,10685,6469],{"class":9667},[6124,10687,5787],{"class":6479},[6124,10689,10690],{"class":9667},"StatusCreated",[6124,10692,9647],{"class":6479},[6124,10694,10696,10698,10700,10702,10704,10706,10708,10710,10712,10714],{"class":6126,"line":10695},76,[6124,10697,9996],{"class":9667},[6124,10699,5787],{"class":6479},[6124,10701,10189],{"class":9578},[6124,10703,10167],{"class":6479},[6124,10705,10194],{"class":9578},[6124,10707,9704],{"class":6479},[6124,10709,10199],{"class":6503},[6124,10711,5259],{"class":6479},[6124,10713,10204],{"class":6503},[6124,10715,9647],{"class":6479},[6124,10717,10719,10721,10723,10725,10727,10729,10731,10733,10735,10737,10739,10741,10743,10745],{"class":6126,"line":10718},77,[6124,10720,10059],{"class":9667},[6124,10722,5787],{"class":6479},[6124,10724,10064],{"class":9578},[6124,10726,9704],{"class":6479},[6124,10728,9967],{"class":9667},[6124,10730,5407],{"class":6479},[6124,10732,10073],{"class":9578},[6124,10734,9704],{"class":6479},[6124,10736,10078],{"class":6483},[6124,10738,10081],{"class":6479},[6124,10740,10084],{"class":9605},[6124,10742,10087],{"class":6479},[6124,10744,10236],{"class":6483},[6124,10746,10239],{"class":6479},[6124,10748,10750,10752,10755,10757],{"class":6126,"line":10749},78,[6124,10751,10422],{"class":6503},[6124,10753,10754],{"class":6479},":      ",[6124,10756,7638],{"class":6503},[6124,10758,6558],{"class":6479},[6124,10760,10762,10765,10767,10769,10771,10774],{"class":6126,"line":10761},79,[6124,10763,10764],{"class":6503},"        \"user_id\"",[6124,10766,6552],{"class":6479},[6124,10768,10584],{"class":9667},[6124,10770,5787],{"class":6479},[6124,10772,10773],{"class":9667},"UserID",[6124,10775,6558],{"class":6479},[6124,10777,10779,10781,10784,10786,10788,10791],{"class":6126,"line":10778},80,[6124,10780,10436],{"class":6503},[6124,10782,10783],{"class":6479},":  ",[6124,10785,10584],{"class":9667},[6124,10787,5787],{"class":6479},[6124,10789,10790],{"class":9667},"Recipe",[6124,10792,6558],{"class":6479},[6124,10794,10796,10798,10800,10802],{"class":6126,"line":10795},81,[6124,10797,10448],{"class":6503},[6124,10799,10783],{"class":6479},[6124,10801,7614],{"class":6503},[6124,10803,6558],{"class":6479},[6124,10805,10807],{"class":6126,"line":10806},82,[6124,10808,9922],{"class":6479},[6124,10810,10812],{"class":6126,"line":10811},83,[6124,10813,6167],{"class":6479},[6124,10815,10817],{"class":6126,"line":10816},84,[6124,10818,6149],{"emptyLinePlaceholder":6148},[6124,10820,10822,10824,10827,10829,10831,10833,10835,10837,10839,10841,10843,10845,10847,10849],{"class":6126,"line":10821},85,[6124,10823,9656],{"class":6483},[6124,10825,10826],{"class":9578}," updateOrderHandler",[6124,10828,9704],{"class":6479},[6124,10830,9967],{"class":9667},[6124,10832,9970],{"class":9605},[6124,10834,5787],{"class":6479},[6124,10836,9975],{"class":9605},[6124,10838,5259],{"class":6479},[6124,10840,9806],{"class":9667},[6124,10842,9982],{"class":6479},[6124,10844,6469],{"class":9605},[6124,10846,5787],{"class":6479},[6124,10848,9989],{"class":9605},[6124,10850,9817],{"class":6479},[6124,10852,10854,10856,10858,10860,10862,10864,10866,10868,10870,10872],{"class":6126,"line":10853},86,[6124,10855,10330],{"class":9667},[6124,10857,9671],{"class":6479},[6124,10859,9674],{"class":9667},[6124,10861,5787],{"class":6479},[6124,10863,10339],{"class":9578},[6124,10865,9704],{"class":6479},[6124,10867,9806],{"class":9667},[6124,10869,5259],{"class":6479},[6124,10871,10348],{"class":6503},[6124,10873,9647],{"class":6479},[6124,10875,10877],{"class":6126,"line":10876},87,[6124,10878,10879],{"class":9691},"    \u002F\u002F ... логіка оновлення замовлення\n",[6124,10881,10883,10885,10887,10889,10891,10893,10895,10898],{"class":6126,"line":10882},88,[6124,10884,9996],{"class":9667},[6124,10886,5787],{"class":6479},[6124,10888,10681],{"class":9578},[6124,10890,9704],{"class":6479},[6124,10892,6469],{"class":9667},[6124,10894,5787],{"class":6479},[6124,10896,10897],{"class":9667},"StatusOK",[6124,10899,9647],{"class":6479},[6124,10901,10903,10905,10907,10909,10911,10913,10915,10917,10919,10921,10923,10925,10927,10929,10931,10933,10935,10937,10939,10941,10943,10946],{"class":6126,"line":10902},89,[6124,10904,10059],{"class":9667},[6124,10906,5787],{"class":6479},[6124,10908,10064],{"class":9578},[6124,10910,9704],{"class":6479},[6124,10912,9967],{"class":9667},[6124,10914,5407],{"class":6479},[6124,10916,10073],{"class":9578},[6124,10918,9704],{"class":6479},[6124,10920,10078],{"class":6483},[6124,10922,10081],{"class":6479},[6124,10924,10084],{"class":9605},[6124,10926,10087],{"class":6479},[6124,10928,10084],{"class":9605},[6124,10930,8747],{"class":6479},[6124,10932,7599],{"class":6503},[6124,10934,6552],{"class":6479},[6124,10936,10428],{"class":9667},[6124,10938,5259],{"class":6479},[6124,10940,7609],{"class":6503},[6124,10942,6552],{"class":6479},[6124,10944,10945],{"class":6503},"\"updated\"",[6124,10947,10101],{"class":6479},[6124,10949,10951],{"class":6126,"line":10950},90,[6124,10952,6167],{"class":6479},[6124,10954,10956],{"class":6126,"line":10955},91,[6124,10957,6149],{"emptyLinePlaceholder":6148},[6124,10959,10961,10963,10966,10968,10970,10972,10974,10976,10978,10980,10982,10984,10986,10988],{"class":6126,"line":10960},92,[6124,10962,9656],{"class":6483},[6124,10964,10965],{"class":9578}," deleteOrderHandler",[6124,10967,9704],{"class":6479},[6124,10969,9967],{"class":9667},[6124,10971,9970],{"class":9605},[6124,10973,5787],{"class":6479},[6124,10975,9975],{"class":9605},[6124,10977,5259],{"class":6479},[6124,10979,9806],{"class":9667},[6124,10981,9982],{"class":6479},[6124,10983,6469],{"class":9605},[6124,10985,5787],{"class":6479},[6124,10987,9989],{"class":9605},[6124,10989,9817],{"class":6479},[6124,10991,10993,10995,10997,10999,11001,11003,11005,11007,11009,11011],{"class":6126,"line":10992},93,[6124,10994,10330],{"class":9667},[6124,10996,9671],{"class":6479},[6124,10998,9674],{"class":9667},[6124,11000,5787],{"class":6479},[6124,11002,10339],{"class":9578},[6124,11004,9704],{"class":6479},[6124,11006,9806],{"class":9667},[6124,11008,5259],{"class":6479},[6124,11010,10348],{"class":6503},[6124,11012,9647],{"class":6479},[6124,11014,11016],{"class":6126,"line":11015},94,[6124,11017,11018],{"class":9691},"    \u002F\u002F ... логіка видалення замовлення\n",[6124,11020,11022,11024,11026,11028,11030,11032,11034,11037],{"class":6126,"line":11021},95,[6124,11023,9996],{"class":9667},[6124,11025,5787],{"class":6479},[6124,11027,10681],{"class":9578},[6124,11029,9704],{"class":6479},[6124,11031,6469],{"class":9667},[6124,11033,5787],{"class":6479},[6124,11035,11036],{"class":9667},"StatusNoContent",[6124,11038,9647],{"class":6479},[6124,11040,11042],{"class":6126,"line":11041},96,[6124,11043,6167],{"class":6479},[5374,11045,11047],{"id":11046},"параметри-шляху-chiurlparam","Параметри шляху: chi.URLParam",[5379,11049,11050,11051,11054],{},"Chi використовує ",[5205,11052,11053],{},"дерево пошуку Radix Tree"," для ефективного зіставлення URL із маршрутами. Параметри шляху визначаються через фігурні дужки:",[5530,11056,11058],{"className":9594,"code":11057,"language":9579,"meta":5538,"style":5538},"r.Get(\"\u002Forders\u002F{orderID}\", getOrderHandler)\nr.Get(\"\u002Fusers\u002F{userID}\u002Forders\u002F{orderID}\", getUserOrderHandler)\n",[5288,11059,11060,11078],{"__ignoreMap":5538},[6124,11061,11062,11064,11066,11068,11070,11072,11074,11076],{"class":6126,"line":6127},[6124,11063,9806],{"class":9667},[6124,11065,5787],{"class":6479},[6124,11067,9751],{"class":9578},[6124,11069,9704],{"class":6479},[6124,11071,9871],{"class":6503},[6124,11073,5259],{"class":6479},[6124,11075,9876],{"class":9667},[6124,11077,9647],{"class":6479},[6124,11079,11080,11082,11084,11086,11088,11091,11093,11096],{"class":6126,"line":6133},[6124,11081,9806],{"class":9667},[6124,11083,5787],{"class":6479},[6124,11085,9751],{"class":9578},[6124,11087,9704],{"class":6479},[6124,11089,11090],{"class":6503},"\"\u002Fusers\u002F{userID}\u002Forders\u002F{orderID}\"",[6124,11092,5259],{"class":6479},[6124,11094,11095],{"class":9667},"getUserOrderHandler",[6124,11097,9647],{"class":6479},[5379,11099,11100],{},"Витягування параметрів:",[5530,11102,11104],{"className":9594,"code":11103,"language":9579,"meta":5538,"style":5538},"func getOrderHandler(w http.ResponseWriter, r *http.Request) {\n    orderID := chi.URLParam(r, \"orderID\")\n    fmt.Fprintf(w, \"Order ID: %s\", orderID)\n}\n",[5288,11105,11106,11136,11158,11189],{"__ignoreMap":5538},[6124,11107,11108,11110,11112,11114,11116,11118,11120,11122,11124,11126,11128,11130,11132,11134],{"class":6126,"line":6127},[6124,11109,9656],{"class":6483},[6124,11111,10294],{"class":9578},[6124,11113,9704],{"class":6479},[6124,11115,9967],{"class":9667},[6124,11117,9970],{"class":9605},[6124,11119,5787],{"class":6479},[6124,11121,9975],{"class":9605},[6124,11123,5259],{"class":6479},[6124,11125,9806],{"class":9667},[6124,11127,9982],{"class":6479},[6124,11129,6469],{"class":9605},[6124,11131,5787],{"class":6479},[6124,11133,9989],{"class":9605},[6124,11135,9817],{"class":6479},[6124,11137,11138,11140,11142,11144,11146,11148,11150,11152,11154,11156],{"class":6126,"line":6133},[6124,11139,10330],{"class":9667},[6124,11141,9671],{"class":6479},[6124,11143,9674],{"class":9667},[6124,11145,5787],{"class":6479},[6124,11147,10339],{"class":9578},[6124,11149,9704],{"class":6479},[6124,11151,9806],{"class":9667},[6124,11153,5259],{"class":6479},[6124,11155,10348],{"class":6503},[6124,11157,9647],{"class":6479},[6124,11159,11160,11163,11165,11168,11170,11172,11174,11177,11180,11183,11185,11187],{"class":6126,"line":6139},[6124,11161,11162],{"class":9667},"    fmt",[6124,11164,5787],{"class":6479},[6124,11166,11167],{"class":9578},"Fprintf",[6124,11169,9704],{"class":6479},[6124,11171,9967],{"class":9667},[6124,11173,5259],{"class":6479},[6124,11175,11176],{"class":6503},"\"Order ID: ",[6124,11178,11179],{"class":9667},"%s",[6124,11181,11182],{"class":6503},"\"",[6124,11184,5259],{"class":6479},[6124,11186,10428],{"class":9667},[6124,11188,9647],{"class":6479},[6124,11190,11191],{"class":6126,"line":6145},[6124,11192,6167],{"class":6479},[5587,11194,11195,11201],{},[5379,11196,11197,11200],{},[5205,11198,11199],{},"Валідація параметрів шляху:"," Chi не виконує автоматичну валідацію типів параметрів. Якщо ви очікуєте числовий ID, перевіряйте його вручну:",[5530,11202,11204],{"className":9594,"code":11203,"language":9579,"meta":5538,"style":5538},"orderID := chi.URLParam(r, \"orderID\")\nid, err := strconv.Atoi(orderID)\nif err != nil {\n    http.Error(w, \"Invalid order ID\", http.StatusBadRequest)\n    return\n}\n",[5288,11205,11206,11228,11253,11266,11293,11298],{"__ignoreMap":5538},[6124,11207,11208,11210,11212,11214,11216,11218,11220,11222,11224,11226],{"class":6126,"line":6127},[6124,11209,10428],{"class":9667},[6124,11211,9671],{"class":6479},[6124,11213,9674],{"class":9667},[6124,11215,5787],{"class":6479},[6124,11217,10339],{"class":9578},[6124,11219,9704],{"class":6479},[6124,11221,9806],{"class":9667},[6124,11223,5259],{"class":6479},[6124,11225,10348],{"class":6503},[6124,11227,9647],{"class":6479},[6124,11229,11230,11233,11235,11237,11239,11242,11244,11247,11249,11251],{"class":6126,"line":6133},[6124,11231,11232],{"class":9667},"id",[6124,11234,5259],{"class":6479},[6124,11236,10590],{"class":9667},[6124,11238,9671],{"class":6479},[6124,11240,11241],{"class":9667},"strconv",[6124,11243,5787],{"class":6479},[6124,11245,11246],{"class":9578},"Atoi",[6124,11248,9704],{"class":6479},[6124,11250,10428],{"class":9667},[6124,11252,9647],{"class":6479},[6124,11254,11255,11258,11260,11262,11264],{"class":6126,"line":6139},[6124,11256,11257],{"class":6476},"if",[6124,11259,10554],{"class":9667},[6124,11261,10593],{"class":6479},[6124,11263,10596],{"class":6483},[6124,11265,10516],{"class":6479},[6124,11267,11268,11270,11272,11274,11276,11278,11280,11283,11285,11287,11289,11291],{"class":6126,"line":6145},[6124,11269,9931],{"class":9667},[6124,11271,5787],{"class":6479},[6124,11273,10609],{"class":9578},[6124,11275,9704],{"class":6479},[6124,11277,9967],{"class":9667},[6124,11279,5259],{"class":6479},[6124,11281,11282],{"class":6503},"\"Invalid order ID\"",[6124,11284,5259],{"class":6479},[6124,11286,6469],{"class":9667},[6124,11288,5787],{"class":6479},[6124,11290,10627],{"class":9667},[6124,11292,9647],{"class":6479},[6124,11294,11295],{"class":6126,"line":6152},[6124,11296,11297],{"class":6476},"    return\n",[6124,11299,11300],{"class":6126,"line":6158},[6124,11301,6167],{"class":6479},[5374,11303,11305],{"id":11304},"групування-маршрутів-та-суб-роутери","Групування маршрутів та суб-роутери",[5379,11307,11308],{},"Групування дозволяє застосовувати спільні middleware або префікси до набору маршрутів:",[5530,11310,11312],{"className":9594,"code":11311,"language":9579,"meta":5538,"style":5538},"r.Route(\"\u002Fv1\", func(r chi.Router) {\n    \u002F\u002F Middleware тільки для \u002Fv1\u002F*\n    r.Use(corsMiddleware)\n    r.Use(authMiddleware)\n\n    r.Get(\"\u002Fhealth\", healthHandler)\n\n    r.Route(\"\u002Forders\", func(r chi.Router) {\n        r.Get(\"\u002F\", listOrdersHandler)       \u002F\u002F GET \u002Fv1\u002Forders\n        r.Post(\"\u002F\", createOrderHandler)     \u002F\u002F POST \u002Fv1\u002Forders\n        r.Get(\"\u002F{id}\", getOrderHandler)     \u002F\u002F GET \u002Fv1\u002Forders\u002F{id}\n        r.Put(\"\u002F{id}\", updateOrderHandler)  \u002F\u002F PUT \u002Fv1\u002Forders\u002F{id}\n        r.Delete(\"\u002F{id}\", deleteOrderHandler) \u002F\u002F DELETE \u002Fv1\u002Forders\u002F{id}\n    })\n})\n",[5288,11313,11314,11342,11347,11362,11377,11381,11400,11404,11432,11454,11476,11498,11520,11541,11545],{"__ignoreMap":5538},[6124,11315,11316,11318,11320,11322,11324,11326,11328,11330,11332,11334,11336,11338,11340],{"class":6126,"line":6127},[6124,11317,9806],{"class":9667},[6124,11319,5787],{"class":6479},[6124,11321,9792],{"class":9578},[6124,11323,9704],{"class":6479},[6124,11325,9797],{"class":6503},[6124,11327,5259],{"class":6479},[6124,11329,9656],{"class":6483},[6124,11331,9704],{"class":6479},[6124,11333,9806],{"class":9667},[6124,11335,9809],{"class":9605},[6124,11337,5787],{"class":6479},[6124,11339,9814],{"class":9605},[6124,11341,9817],{"class":6479},[6124,11343,11344],{"class":6126,"line":6133},[6124,11345,11346],{"class":9691},"    \u002F\u002F Middleware тільки для \u002Fv1\u002F*\n",[6124,11348,11349,11351,11353,11355,11357,11360],{"class":6126,"line":6139},[6124,11350,9668],{"class":9667},[6124,11352,5787],{"class":6479},[6124,11354,9701],{"class":9578},[6124,11356,9704],{"class":6479},[6124,11358,11359],{"class":9667},"corsMiddleware",[6124,11361,9647],{"class":6479},[6124,11363,11364,11366,11368,11370,11372,11375],{"class":6126,"line":6145},[6124,11365,9668],{"class":9667},[6124,11367,5787],{"class":6479},[6124,11369,9701],{"class":9578},[6124,11371,9704],{"class":6479},[6124,11373,11374],{"class":9667},"authMiddleware",[6124,11376,9647],{"class":6479},[6124,11378,11379],{"class":6126,"line":6152},[6124,11380,6149],{"emptyLinePlaceholder":6148},[6124,11382,11383,11385,11387,11389,11391,11393,11395,11398],{"class":6126,"line":6158},[6124,11384,9668],{"class":9667},[6124,11386,5787],{"class":6479},[6124,11388,9751],{"class":9578},[6124,11390,9704],{"class":6479},[6124,11392,9776],{"class":6503},[6124,11394,5259],{"class":6479},[6124,11396,11397],{"class":9667},"healthHandler",[6124,11399,9647],{"class":6479},[6124,11401,11402],{"class":6126,"line":6164},[6124,11403,6149],{"emptyLinePlaceholder":6148},[6124,11405,11406,11408,11410,11412,11414,11416,11418,11420,11422,11424,11426,11428,11430],{"class":6126,"line":6170},[6124,11407,9668],{"class":9667},[6124,11409,5787],{"class":6479},[6124,11411,9792],{"class":9578},[6124,11413,9704],{"class":6479},[6124,11415,9831],{"class":6503},[6124,11417,5259],{"class":6479},[6124,11419,9656],{"class":6483},[6124,11421,9704],{"class":6479},[6124,11423,9806],{"class":9667},[6124,11425,9809],{"class":9605},[6124,11427,5787],{"class":6479},[6124,11429,9814],{"class":9605},[6124,11431,9817],{"class":6479},[6124,11433,11434,11436,11438,11440,11442,11444,11446,11448,11451],{"class":6126,"line":6175},[6124,11435,9822],{"class":9667},[6124,11437,5787],{"class":6479},[6124,11439,9751],{"class":9578},[6124,11441,9704],{"class":6479},[6124,11443,9756],{"class":6503},[6124,11445,5259],{"class":6479},[6124,11447,9836],{"class":9667},[6124,11449,11450],{"class":6479},")       ",[6124,11452,11453],{"class":9691},"\u002F\u002F GET \u002Fv1\u002Forders\n",[6124,11455,11456,11458,11460,11462,11464,11466,11468,11470,11473],{"class":6126,"line":6181},[6124,11457,9822],{"class":9667},[6124,11459,5787],{"class":6479},[6124,11461,9847],{"class":9578},[6124,11463,9704],{"class":6479},[6124,11465,9756],{"class":6503},[6124,11467,5259],{"class":6479},[6124,11469,9856],{"class":9667},[6124,11471,11472],{"class":6479},")     ",[6124,11474,11475],{"class":9691},"\u002F\u002F POST \u002Fv1\u002Forders\n",[6124,11477,11478,11480,11482,11484,11486,11489,11491,11493,11495],{"class":6126,"line":6187},[6124,11479,9822],{"class":9667},[6124,11481,5787],{"class":6479},[6124,11483,9751],{"class":9578},[6124,11485,9704],{"class":6479},[6124,11487,11488],{"class":6503},"\"\u002F{id}\"",[6124,11490,5259],{"class":6479},[6124,11492,9876],{"class":9667},[6124,11494,11472],{"class":6479},[6124,11496,11497],{"class":9691},"\u002F\u002F GET \u002Fv1\u002Forders\u002F{id}\n",[6124,11499,11500,11502,11504,11506,11508,11510,11512,11514,11517],{"class":6126,"line":6193},[6124,11501,9822],{"class":9667},[6124,11503,5787],{"class":6479},[6124,11505,9887],{"class":9578},[6124,11507,9704],{"class":6479},[6124,11509,11488],{"class":6503},[6124,11511,5259],{"class":6479},[6124,11513,9896],{"class":9667},[6124,11515,11516],{"class":6479},")  ",[6124,11518,11519],{"class":9691},"\u002F\u002F PUT \u002Fv1\u002Forders\u002F{id}\n",[6124,11521,11522,11524,11526,11528,11530,11532,11534,11536,11538],{"class":6126,"line":6199},[6124,11523,9822],{"class":9667},[6124,11525,5787],{"class":6479},[6124,11527,8464],{"class":9578},[6124,11529,9704],{"class":6479},[6124,11531,11488],{"class":6503},[6124,11533,5259],{"class":6479},[6124,11535,9915],{"class":9667},[6124,11537,7173],{"class":6479},[6124,11539,11540],{"class":9691},"\u002F\u002F DELETE \u002Fv1\u002Forders\u002F{id}\n",[6124,11542,11543],{"class":6126,"line":6204},[6124,11544,9922],{"class":6479},[6124,11546,11547],{"class":6126,"line":6209},[6124,11548,10101],{"class":6479},[5374,11550,11552],{"id":11551},"створення-користувацьких-middleware","Створення користувацьких Middleware",[5379,11554,11555,11556,6500],{},"Middleware у Chi — це функція, що обгортає ",[5288,11557,9562],{},[5530,11559,11561],{"className":9594,"code":11560,"language":9579,"meta":5538,"style":5538},"func loggingMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        start := time.Now()\n        \n        \u002F\u002F Викликаємо наступний обробник у ланцюжку\n        next.ServeHTTP(w, r)\n        \n        \u002F\u002F Логуємо після виконання запиту\n        duration := time.Since(start)\n        log.Printf(\"%s %s %v\", r.Method, r.URL.Path, duration)\n    })\n}\n\n\u002F\u002F Застосування middleware\nr.Use(loggingMiddleware)\n",[5288,11562,11563,11592,11632,11649,11654,11659,11679,11683,11688,11709,11762,11766,11770,11774,11779],{"__ignoreMap":5538},[6124,11564,11565,11567,11570,11572,11575,11577,11579,11582,11584,11586,11588,11590],{"class":6126,"line":6127},[6124,11566,9656],{"class":6483},[6124,11568,11569],{"class":9578}," loggingMiddleware",[6124,11571,9704],{"class":6479},[6124,11573,11574],{"class":9667},"next",[6124,11576,9970],{"class":9605},[6124,11578,5787],{"class":6479},[6124,11580,11581],{"class":9605},"Handler",[6124,11583,7173],{"class":6479},[6124,11585,6469],{"class":9605},[6124,11587,5787],{"class":6479},[6124,11589,11581],{"class":9605},[6124,11591,10516],{"class":6479},[6124,11593,11594,11597,11599,11601,11604,11606,11608,11610,11612,11614,11616,11618,11620,11622,11624,11626,11628,11630],{"class":6126,"line":6133},[6124,11595,11596],{"class":6476},"    return",[6124,11598,9970],{"class":9667},[6124,11600,5787],{"class":6479},[6124,11602,11603],{"class":9578},"HandlerFunc",[6124,11605,9704],{"class":6479},[6124,11607,9656],{"class":6483},[6124,11609,9704],{"class":6479},[6124,11611,9967],{"class":9667},[6124,11613,9970],{"class":9605},[6124,11615,5787],{"class":6479},[6124,11617,9975],{"class":9605},[6124,11619,5259],{"class":6479},[6124,11621,9806],{"class":9667},[6124,11623,9982],{"class":6479},[6124,11625,6469],{"class":9605},[6124,11627,5787],{"class":6479},[6124,11629,9989],{"class":9605},[6124,11631,9817],{"class":6479},[6124,11633,11634,11637,11639,11642,11644,11647],{"class":6126,"line":6139},[6124,11635,11636],{"class":9667},"        start",[6124,11638,9671],{"class":6479},[6124,11640,11641],{"class":9667},"time",[6124,11643,5787],{"class":6479},[6124,11645,11646],{"class":9578},"Now",[6124,11648,9682],{"class":6479},[6124,11650,11651],{"class":6126,"line":6145},[6124,11652,11653],{"class":6479},"        \n",[6124,11655,11656],{"class":6126,"line":6152},[6124,11657,11658],{"class":9691},"        \u002F\u002F Викликаємо наступний обробник у ланцюжку\n",[6124,11660,11661,11664,11666,11669,11671,11673,11675,11677],{"class":6126,"line":6158},[6124,11662,11663],{"class":9667},"        next",[6124,11665,5787],{"class":6479},[6124,11667,11668],{"class":9578},"ServeHTTP",[6124,11670,9704],{"class":6479},[6124,11672,9967],{"class":9667},[6124,11674,5259],{"class":6479},[6124,11676,9806],{"class":9667},[6124,11678,9647],{"class":6479},[6124,11680,11681],{"class":6126,"line":6164},[6124,11682,11653],{"class":6479},[6124,11684,11685],{"class":6126,"line":6170},[6124,11686,11687],{"class":9691},"        \u002F\u002F Логуємо після виконання запиту\n",[6124,11689,11690,11693,11695,11697,11699,11702,11704,11707],{"class":6126,"line":6175},[6124,11691,11692],{"class":9667},"        duration",[6124,11694,9671],{"class":6479},[6124,11696,11641],{"class":9667},[6124,11698,5787],{"class":6479},[6124,11700,11701],{"class":9578},"Since",[6124,11703,9704],{"class":6479},[6124,11705,11706],{"class":9667},"start",[6124,11708,9647],{"class":6479},[6124,11710,11711,11714,11716,11719,11721,11723,11725,11728,11731,11733,11735,11737,11739,11742,11744,11746,11748,11750,11752,11755,11757,11760],{"class":6126,"line":6181},[6124,11712,11713],{"class":9667},"        log",[6124,11715,5787],{"class":6479},[6124,11717,11718],{"class":9578},"Printf",[6124,11720,9704],{"class":6479},[6124,11722,11182],{"class":6503},[6124,11724,11179],{"class":9667},[6124,11726,11727],{"class":9667}," %s",[6124,11729,11730],{"class":9667}," %v",[6124,11732,11182],{"class":6503},[6124,11734,5259],{"class":6479},[6124,11736,9806],{"class":9667},[6124,11738,5787],{"class":6479},[6124,11740,11741],{"class":9667},"Method",[6124,11743,5259],{"class":6479},[6124,11745,9806],{"class":9667},[6124,11747,5787],{"class":6479},[6124,11749,10159],{"class":9667},[6124,11751,5787],{"class":6479},[6124,11753,11754],{"class":9667},"Path",[6124,11756,5259],{"class":6479},[6124,11758,11759],{"class":9667},"duration",[6124,11761,9647],{"class":6479},[6124,11763,11764],{"class":6126,"line":6187},[6124,11765,9922],{"class":6479},[6124,11767,11768],{"class":6126,"line":6193},[6124,11769,6167],{"class":6479},[6124,11771,11772],{"class":6126,"line":6199},[6124,11773,6149],{"emptyLinePlaceholder":6148},[6124,11775,11776],{"class":6126,"line":6204},[6124,11777,11778],{"class":9691},"\u002F\u002F Застосування middleware\n",[6124,11780,11781,11783,11785,11787,11789,11792],{"class":6126,"line":6209},[6124,11782,9806],{"class":9667},[6124,11784,5787],{"class":6479},[6124,11786,9701],{"class":9578},[6124,11788,9704],{"class":6479},[6124,11790,11791],{"class":9667},"loggingMiddleware",[6124,11793,9647],{"class":6479},[5379,11795,11796],{},[5205,11797,11798],{},"Middleware для CORS:",[5530,11800,11802],{"className":9594,"code":11801,"language":9579,"meta":5538,"style":5538},"func corsMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        w.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\n        w.Header().Set(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\")\n        w.Header().Set(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\")\n\n        \u002F\u002F Обробка preflight-запитів\n        if r.Method == http.MethodOptions {\n            w.WriteHeader(http.StatusOK)\n            return\n        }\n\n        next.ServeHTTP(w, r)\n    })\n}\n",[5288,11803,11804,11831,11869,11894,11918,11942,11946,11951,11974,11993,11998,12003,12007,12025,12029],{"__ignoreMap":5538},[6124,11805,11806,11808,11811,11813,11815,11817,11819,11821,11823,11825,11827,11829],{"class":6126,"line":6127},[6124,11807,9656],{"class":6483},[6124,11809,11810],{"class":9578}," corsMiddleware",[6124,11812,9704],{"class":6479},[6124,11814,11574],{"class":9667},[6124,11816,9970],{"class":9605},[6124,11818,5787],{"class":6479},[6124,11820,11581],{"class":9605},[6124,11822,7173],{"class":6479},[6124,11824,6469],{"class":9605},[6124,11826,5787],{"class":6479},[6124,11828,11581],{"class":9605},[6124,11830,10516],{"class":6479},[6124,11832,11833,11835,11837,11839,11841,11843,11845,11847,11849,11851,11853,11855,11857,11859,11861,11863,11865,11867],{"class":6126,"line":6133},[6124,11834,11596],{"class":6476},[6124,11836,9970],{"class":9667},[6124,11838,5787],{"class":6479},[6124,11840,11603],{"class":9578},[6124,11842,9704],{"class":6479},[6124,11844,9656],{"class":6483},[6124,11846,9704],{"class":6479},[6124,11848,9967],{"class":9667},[6124,11850,9970],{"class":9605},[6124,11852,5787],{"class":6479},[6124,11854,9975],{"class":9605},[6124,11856,5259],{"class":6479},[6124,11858,9806],{"class":9667},[6124,11860,9982],{"class":6479},[6124,11862,6469],{"class":9605},[6124,11864,5787],{"class":6479},[6124,11866,9989],{"class":9605},[6124,11868,9817],{"class":6479},[6124,11870,11871,11874,11876,11878,11880,11882,11884,11887,11889,11892],{"class":6126,"line":6139},[6124,11872,11873],{"class":9667},"        w",[6124,11875,5787],{"class":6479},[6124,11877,10189],{"class":9578},[6124,11879,10167],{"class":6479},[6124,11881,10194],{"class":9578},[6124,11883,9704],{"class":6479},[6124,11885,11886],{"class":6503},"\"Access-Control-Allow-Origin\"",[6124,11888,5259],{"class":6479},[6124,11890,11891],{"class":6503},"\"*\"",[6124,11893,9647],{"class":6479},[6124,11895,11896,11898,11900,11902,11904,11906,11908,11911,11913,11916],{"class":6126,"line":6145},[6124,11897,11873],{"class":9667},[6124,11899,5787],{"class":6479},[6124,11901,10189],{"class":9578},[6124,11903,10167],{"class":6479},[6124,11905,10194],{"class":9578},[6124,11907,9704],{"class":6479},[6124,11909,11910],{"class":6503},"\"Access-Control-Allow-Methods\"",[6124,11912,5259],{"class":6479},[6124,11914,11915],{"class":6503},"\"GET, POST, PUT, DELETE, OPTIONS\"",[6124,11917,9647],{"class":6479},[6124,11919,11920,11922,11924,11926,11928,11930,11932,11935,11937,11940],{"class":6126,"line":6152},[6124,11921,11873],{"class":9667},[6124,11923,5787],{"class":6479},[6124,11925,10189],{"class":9578},[6124,11927,10167],{"class":6479},[6124,11929,10194],{"class":9578},[6124,11931,9704],{"class":6479},[6124,11933,11934],{"class":6503},"\"Access-Control-Allow-Headers\"",[6124,11936,5259],{"class":6479},[6124,11938,11939],{"class":6503},"\"Content-Type, Authorization\"",[6124,11941,9647],{"class":6479},[6124,11943,11944],{"class":6126,"line":6158},[6124,11945,6149],{"emptyLinePlaceholder":6148},[6124,11947,11948],{"class":6126,"line":6164},[6124,11949,11950],{"class":9691},"        \u002F\u002F Обробка preflight-запитів\n",[6124,11952,11953,11956,11958,11960,11962,11965,11967,11969,11972],{"class":6126,"line":6170},[6124,11954,11955],{"class":6476},"        if",[6124,11957,10649],{"class":9667},[6124,11959,5787],{"class":6479},[6124,11961,11741],{"class":9667},[6124,11963,11964],{"class":6479}," == ",[6124,11966,6469],{"class":9667},[6124,11968,5787],{"class":6479},[6124,11970,11971],{"class":9667},"MethodOptions",[6124,11973,10516],{"class":6479},[6124,11975,11976,11979,11981,11983,11985,11987,11989,11991],{"class":6126,"line":6175},[6124,11977,11978],{"class":9667},"            w",[6124,11980,5787],{"class":6479},[6124,11982,10681],{"class":9578},[6124,11984,9704],{"class":6479},[6124,11986,6469],{"class":9667},[6124,11988,5787],{"class":6479},[6124,11990,10897],{"class":9667},[6124,11992,9647],{"class":6479},[6124,11994,11995],{"class":6126,"line":6181},[6124,11996,11997],{"class":6476},"            return\n",[6124,11999,12000],{"class":6126,"line":6187},[6124,12001,12002],{"class":6479},"        }\n",[6124,12004,12005],{"class":6126,"line":6193},[6124,12006,6149],{"emptyLinePlaceholder":6148},[6124,12008,12009,12011,12013,12015,12017,12019,12021,12023],{"class":6126,"line":6199},[6124,12010,11663],{"class":9667},[6124,12012,5787],{"class":6479},[6124,12014,11668],{"class":9578},[6124,12016,9704],{"class":6479},[6124,12018,9967],{"class":9667},[6124,12020,5259],{"class":6479},[6124,12022,9806],{"class":9667},[6124,12024,9647],{"class":6479},[6124,12026,12027],{"class":6126,"line":6204},[6124,12028,9922],{"class":6479},[6124,12030,12031],{"class":6126,"line":6209},[6124,12032,6167],{"class":6479},[5379,12034,12035],{},[5205,12036,12037],{},"Middleware для автентифікації:",[5530,12039,12041],{"className":9594,"code":12040,"language":9579,"meta":5538,"style":5538},"func authMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        token := r.Header.Get(\"Authorization\")\n        if token == \"\" {\n            http.Error(w, \"Unauthorized\", http.StatusUnauthorized)\n            return\n        }\n\n        \u002F\u002F Перевірка токена (наприклад, JWT)\n        userID, err := validateToken(token)\n        if err != nil {\n            http.Error(w, \"Invalid token\", http.StatusUnauthorized)\n            return\n        }\n\n        \u002F\u002F Додаємо userID до контексту\n        ctx := context.WithValue(r.Context(), \"userID\", userID)\n        next.ServeHTTP(w, r.WithContext(ctx))\n    })\n}\n",[5288,12042,12043,12070,12108,12132,12146,12175,12179,12183,12187,12192,12213,12225,12252,12256,12260,12264,12269,12304,12332,12336],{"__ignoreMap":5538},[6124,12044,12045,12047,12050,12052,12054,12056,12058,12060,12062,12064,12066,12068],{"class":6126,"line":6127},[6124,12046,9656],{"class":6483},[6124,12048,12049],{"class":9578}," authMiddleware",[6124,12051,9704],{"class":6479},[6124,12053,11574],{"class":9667},[6124,12055,9970],{"class":9605},[6124,12057,5787],{"class":6479},[6124,12059,11581],{"class":9605},[6124,12061,7173],{"class":6479},[6124,12063,6469],{"class":9605},[6124,12065,5787],{"class":6479},[6124,12067,11581],{"class":9605},[6124,12069,10516],{"class":6479},[6124,12071,12072,12074,12076,12078,12080,12082,12084,12086,12088,12090,12092,12094,12096,12098,12100,12102,12104,12106],{"class":6126,"line":6133},[6124,12073,11596],{"class":6476},[6124,12075,9970],{"class":9667},[6124,12077,5787],{"class":6479},[6124,12079,11603],{"class":9578},[6124,12081,9704],{"class":6479},[6124,12083,9656],{"class":6483},[6124,12085,9704],{"class":6479},[6124,12087,9967],{"class":9667},[6124,12089,9970],{"class":9605},[6124,12091,5787],{"class":6479},[6124,12093,9975],{"class":9605},[6124,12095,5259],{"class":6479},[6124,12097,9806],{"class":9667},[6124,12099,9982],{"class":6479},[6124,12101,6469],{"class":9605},[6124,12103,5787],{"class":6479},[6124,12105,9989],{"class":9605},[6124,12107,9817],{"class":6479},[6124,12109,12110,12113,12115,12117,12119,12121,12123,12125,12127,12130],{"class":6126,"line":6139},[6124,12111,12112],{"class":9667},"        token",[6124,12114,9671],{"class":6479},[6124,12116,9806],{"class":9667},[6124,12118,5787],{"class":6479},[6124,12120,10189],{"class":9667},[6124,12122,5787],{"class":6479},[6124,12124,9751],{"class":9578},[6124,12126,9704],{"class":6479},[6124,12128,12129],{"class":6503},"\"Authorization\"",[6124,12131,9647],{"class":6479},[6124,12133,12134,12136,12139,12141,12144],{"class":6126,"line":6145},[6124,12135,11955],{"class":6476},[6124,12137,12138],{"class":9667}," token",[6124,12140,11964],{"class":6479},[6124,12142,12143],{"class":6503},"\"\"",[6124,12145,10516],{"class":6479},[6124,12147,12148,12151,12153,12155,12157,12159,12161,12164,12166,12168,12170,12173],{"class":6126,"line":6152},[6124,12149,12150],{"class":9667},"            http",[6124,12152,5787],{"class":6479},[6124,12154,10609],{"class":9578},[6124,12156,9704],{"class":6479},[6124,12158,9967],{"class":9667},[6124,12160,5259],{"class":6479},[6124,12162,12163],{"class":6503},"\"Unauthorized\"",[6124,12165,5259],{"class":6479},[6124,12167,6469],{"class":9667},[6124,12169,5787],{"class":6479},[6124,12171,12172],{"class":9667},"StatusUnauthorized",[6124,12174,9647],{"class":6479},[6124,12176,12177],{"class":6126,"line":6158},[6124,12178,11997],{"class":6476},[6124,12180,12181],{"class":6126,"line":6164},[6124,12182,12002],{"class":6479},[6124,12184,12185],{"class":6126,"line":6170},[6124,12186,6149],{"emptyLinePlaceholder":6148},[6124,12188,12189],{"class":6126,"line":6175},[6124,12190,12191],{"class":9691},"        \u002F\u002F Перевірка токена (наприклад, JWT)\n",[6124,12193,12194,12197,12199,12201,12203,12206,12208,12211],{"class":6126,"line":6181},[6124,12195,12196],{"class":9667},"        userID",[6124,12198,5259],{"class":6479},[6124,12200,10590],{"class":9667},[6124,12202,9671],{"class":6479},[6124,12204,12205],{"class":9578},"validateToken",[6124,12207,9704],{"class":6479},[6124,12209,12210],{"class":9667},"token",[6124,12212,9647],{"class":6479},[6124,12214,12215,12217,12219,12221,12223],{"class":6126,"line":6187},[6124,12216,11955],{"class":6476},[6124,12218,10554],{"class":9667},[6124,12220,10593],{"class":6479},[6124,12222,10596],{"class":6483},[6124,12224,10516],{"class":6479},[6124,12226,12227,12229,12231,12233,12235,12237,12239,12242,12244,12246,12248,12250],{"class":6126,"line":6193},[6124,12228,12150],{"class":9667},[6124,12230,5787],{"class":6479},[6124,12232,10609],{"class":9578},[6124,12234,9704],{"class":6479},[6124,12236,9967],{"class":9667},[6124,12238,5259],{"class":6479},[6124,12240,12241],{"class":6503},"\"Invalid token\"",[6124,12243,5259],{"class":6479},[6124,12245,6469],{"class":9667},[6124,12247,5787],{"class":6479},[6124,12249,12172],{"class":9667},[6124,12251,9647],{"class":6479},[6124,12253,12254],{"class":6126,"line":6199},[6124,12255,11997],{"class":6476},[6124,12257,12258],{"class":6126,"line":6204},[6124,12259,12002],{"class":6479},[6124,12261,12262],{"class":6126,"line":6209},[6124,12263,6149],{"emptyLinePlaceholder":6148},[6124,12265,12266],{"class":6126,"line":6215},[6124,12267,12268],{"class":9691},"        \u002F\u002F Додаємо userID до контексту\n",[6124,12270,12271,12274,12276,12278,12280,12283,12285,12287,12289,12292,12295,12298,12300,12302],{"class":6126,"line":6221},[6124,12272,12273],{"class":9667},"        ctx",[6124,12275,9671],{"class":6479},[6124,12277,5349],{"class":9667},[6124,12279,5787],{"class":6479},[6124,12281,12282],{"class":9578},"WithValue",[6124,12284,9704],{"class":6479},[6124,12286,9806],{"class":9667},[6124,12288,5787],{"class":6479},[6124,12290,12291],{"class":9578},"Context",[6124,12293,12294],{"class":6479},"(), ",[6124,12296,12297],{"class":6503},"\"userID\"",[6124,12299,5259],{"class":6479},[6124,12301,10261],{"class":9667},[6124,12303,9647],{"class":6479},[6124,12305,12306,12308,12310,12312,12314,12316,12318,12320,12322,12325,12327,12330],{"class":6126,"line":6227},[6124,12307,11663],{"class":9667},[6124,12309,5787],{"class":6479},[6124,12311,11668],{"class":9578},[6124,12313,9704],{"class":6479},[6124,12315,9967],{"class":9667},[6124,12317,5259],{"class":6479},[6124,12319,9806],{"class":9667},[6124,12321,5787],{"class":6479},[6124,12323,12324],{"class":9578},"WithContext",[6124,12326,9704],{"class":6479},[6124,12328,12329],{"class":9667},"ctx",[6124,12331,10015],{"class":6479},[6124,12333,12334],{"class":6126,"line":6232},[6124,12335,9922],{"class":6479},[6124,12337,12338],{"class":6126,"line":6237},[6124,12339,6167],{"class":6479},[5374,12341,12343],{"id":12342},"вбудовані-middleware-пакета-chimiddleware","Вбудовані middleware пакета chi\u002Fmiddleware",[5379,12345,12346],{},"Chi постачається з багатим набором готових middleware:",[5530,12348,12350],{"className":9594,"code":12349,"language":9579,"meta":5538,"style":5538},"import \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\u002Fmiddleware\"\n\nfunc main() {\n    r := chi.NewRouter()\n\n    \u002F\u002F 1. Logger - логування кожного запиту\n    r.Use(middleware.Logger)\n\n    \u002F\u002F 2. Recoverer - відновлення після паніки\n    r.Use(middleware.Recoverer)\n\n    \u002F\u002F 3. RequestID - додає унікальний ID до кожного запиту\n    r.Use(middleware.RequestID)\n\n    \u002F\u002F 4. RealIP - витягує реальний IP клієнта (за проксі)\n    r.Use(middleware.RealIP)\n\n    \u002F\u002F 5. Timeout - встановлює таймаут для обробки запиту\n    r.Use(middleware.Timeout(60 * time.Second))\n\n    \u002F\u002F 6. Throttle - обмеження кількості одночасних запитів\n    r.Use(middleware.Throttle(100))\n\n    \u002F\u002F 7. Compress - стиснення відповідей (gzip, deflate)\n    r.Use(middleware.Compress(5))\n\n    \u002F\u002F 8. StripSlashes - нормалізація слешів у кінці URL\n    r.Use(middleware.StripSlashes)\n\n    \u002F\u002F 9. Heartbeat - ендпоінт для health checks\n    r.Use(middleware.Heartbeat(\"\u002Fping\"))\n\n    \u002F\u002F 10. AllowContentType - дозволяє лише певні Content-Type\n    r.Use(middleware.AllowContentType(\"application\u002Fjson\"))\n\n    \u002F\u002F ... ваші маршрути\n}\n",[5288,12351,12352,12359,12363,12371,12385,12389,12394,12412,12416,12421,12439,12443,12448,12467,12471,12476,12495,12499,12504,12538,12542,12547,12571,12575,12580,12604,12608,12613,12632,12636,12641,12665,12669,12674,12697,12701,12706],{"__ignoreMap":5538},[6124,12353,12354,12356],{"class":6126,"line":6127},[6124,12355,9615],{"class":6476},[6124,12357,12358],{"class":6503}," \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\u002Fmiddleware\"\n",[6124,12360,12361],{"class":6126,"line":6133},[6124,12362,6149],{"emptyLinePlaceholder":6148},[6124,12364,12365,12367,12369],{"class":6126,"line":6139},[6124,12366,9656],{"class":6483},[6124,12368,9659],{"class":9578},[6124,12370,9662],{"class":6479},[6124,12372,12373,12375,12377,12379,12381,12383],{"class":6126,"line":6145},[6124,12374,9668],{"class":9667},[6124,12376,9671],{"class":6479},[6124,12378,9674],{"class":9667},[6124,12380,5787],{"class":6479},[6124,12382,9679],{"class":9578},[6124,12384,9682],{"class":6479},[6124,12386,12387],{"class":6126,"line":6152},[6124,12388,6149],{"emptyLinePlaceholder":6148},[6124,12390,12391],{"class":6126,"line":6158},[6124,12392,12393],{"class":9691},"    \u002F\u002F 1. Logger - логування кожного запиту\n",[6124,12395,12396,12398,12400,12402,12404,12406,12408,12410],{"class":6126,"line":6164},[6124,12397,9668],{"class":9667},[6124,12399,5787],{"class":6479},[6124,12401,9701],{"class":9578},[6124,12403,9704],{"class":6479},[6124,12405,9707],{"class":9667},[6124,12407,5787],{"class":6479},[6124,12409,9712],{"class":9667},[6124,12411,9647],{"class":6479},[6124,12413,12414],{"class":6126,"line":6170},[6124,12415,6149],{"emptyLinePlaceholder":6148},[6124,12417,12418],{"class":6126,"line":6175},[6124,12419,12420],{"class":9691},"    \u002F\u002F 2. Recoverer - відновлення після паніки\n",[6124,12422,12423,12425,12427,12429,12431,12433,12435,12437],{"class":6126,"line":6181},[6124,12424,9668],{"class":9667},[6124,12426,5787],{"class":6479},[6124,12428,9701],{"class":9578},[6124,12430,9704],{"class":6479},[6124,12432,9707],{"class":9667},[6124,12434,5787],{"class":6479},[6124,12436,9731],{"class":9667},[6124,12438,9647],{"class":6479},[6124,12440,12441],{"class":6126,"line":6187},[6124,12442,6149],{"emptyLinePlaceholder":6148},[6124,12444,12445],{"class":6126,"line":6193},[6124,12446,12447],{"class":9691},"    \u002F\u002F 3. RequestID - додає унікальний ID до кожного запиту\n",[6124,12449,12450,12452,12454,12456,12458,12460,12462,12465],{"class":6126,"line":6199},[6124,12451,9668],{"class":9667},[6124,12453,5787],{"class":6479},[6124,12455,9701],{"class":9578},[6124,12457,9704],{"class":6479},[6124,12459,9707],{"class":9667},[6124,12461,5787],{"class":6479},[6124,12463,12464],{"class":9667},"RequestID",[6124,12466,9647],{"class":6479},[6124,12468,12469],{"class":6126,"line":6204},[6124,12470,6149],{"emptyLinePlaceholder":6148},[6124,12472,12473],{"class":6126,"line":6209},[6124,12474,12475],{"class":9691},"    \u002F\u002F 4. RealIP - витягує реальний IP клієнта (за проксі)\n",[6124,12477,12478,12480,12482,12484,12486,12488,12490,12493],{"class":6126,"line":6215},[6124,12479,9668],{"class":9667},[6124,12481,5787],{"class":6479},[6124,12483,9701],{"class":9578},[6124,12485,9704],{"class":6479},[6124,12487,9707],{"class":9667},[6124,12489,5787],{"class":6479},[6124,12491,12492],{"class":9667},"RealIP",[6124,12494,9647],{"class":6479},[6124,12496,12497],{"class":6126,"line":6221},[6124,12498,6149],{"emptyLinePlaceholder":6148},[6124,12500,12501],{"class":6126,"line":6227},[6124,12502,12503],{"class":9691},"    \u002F\u002F 5. Timeout - встановлює таймаут для обробки запиту\n",[6124,12505,12506,12508,12510,12512,12514,12516,12518,12521,12523,12526,12529,12531,12533,12536],{"class":6126,"line":6232},[6124,12507,9668],{"class":9667},[6124,12509,5787],{"class":6479},[6124,12511,9701],{"class":9578},[6124,12513,9704],{"class":6479},[6124,12515,9707],{"class":9667},[6124,12517,5787],{"class":6479},[6124,12519,12520],{"class":9578},"Timeout",[6124,12522,9704],{"class":6479},[6124,12524,12525],{"class":6490},"60",[6124,12527,12528],{"class":6479}," * ",[6124,12530,11641],{"class":9667},[6124,12532,5787],{"class":6479},[6124,12534,12535],{"class":9667},"Second",[6124,12537,10015],{"class":6479},[6124,12539,12540],{"class":6126,"line":6237},[6124,12541,6149],{"emptyLinePlaceholder":6148},[6124,12543,12544],{"class":6126,"line":6243},[6124,12545,12546],{"class":9691},"    \u002F\u002F 6. Throttle - обмеження кількості одночасних запитів\n",[6124,12548,12549,12551,12553,12555,12557,12559,12561,12564,12566,12569],{"class":6126,"line":6249},[6124,12550,9668],{"class":9667},[6124,12552,5787],{"class":6479},[6124,12554,9701],{"class":9578},[6124,12556,9704],{"class":6479},[6124,12558,9707],{"class":9667},[6124,12560,5787],{"class":6479},[6124,12562,12563],{"class":9578},"Throttle",[6124,12565,9704],{"class":6479},[6124,12567,12568],{"class":6490},"100",[6124,12570,10015],{"class":6479},[6124,12572,12573],{"class":6126,"line":6255},[6124,12574,6149],{"emptyLinePlaceholder":6148},[6124,12576,12577],{"class":6126,"line":6261},[6124,12578,12579],{"class":9691},"    \u002F\u002F 7. Compress - стиснення відповідей (gzip, deflate)\n",[6124,12581,12582,12584,12586,12588,12590,12592,12594,12597,12599,12602],{"class":6126,"line":6267},[6124,12583,9668],{"class":9667},[6124,12585,5787],{"class":6479},[6124,12587,9701],{"class":9578},[6124,12589,9704],{"class":6479},[6124,12591,9707],{"class":9667},[6124,12593,5787],{"class":6479},[6124,12595,12596],{"class":9578},"Compress",[6124,12598,9704],{"class":6479},[6124,12600,12601],{"class":6490},"5",[6124,12603,10015],{"class":6479},[6124,12605,12606],{"class":6126,"line":6272},[6124,12607,6149],{"emptyLinePlaceholder":6148},[6124,12609,12610],{"class":6126,"line":6278},[6124,12611,12612],{"class":9691},"    \u002F\u002F 8. StripSlashes - нормалізація слешів у кінці URL\n",[6124,12614,12615,12617,12619,12621,12623,12625,12627,12630],{"class":6126,"line":6284},[6124,12616,9668],{"class":9667},[6124,12618,5787],{"class":6479},[6124,12620,9701],{"class":9578},[6124,12622,9704],{"class":6479},[6124,12624,9707],{"class":9667},[6124,12626,5787],{"class":6479},[6124,12628,12629],{"class":9667},"StripSlashes",[6124,12631,9647],{"class":6479},[6124,12633,12634],{"class":6126,"line":6290},[6124,12635,6149],{"emptyLinePlaceholder":6148},[6124,12637,12638],{"class":6126,"line":6296},[6124,12639,12640],{"class":9691},"    \u002F\u002F 9. Heartbeat - ендпоінт для health checks\n",[6124,12642,12643,12645,12647,12649,12651,12653,12655,12658,12660,12663],{"class":6126,"line":6301},[6124,12644,9668],{"class":9667},[6124,12646,5787],{"class":6479},[6124,12648,9701],{"class":9578},[6124,12650,9704],{"class":6479},[6124,12652,9707],{"class":9667},[6124,12654,5787],{"class":6479},[6124,12656,12657],{"class":9578},"Heartbeat",[6124,12659,9704],{"class":6479},[6124,12661,12662],{"class":6503},"\"\u002Fping\"",[6124,12664,10015],{"class":6479},[6124,12666,12667],{"class":6126,"line":6307},[6124,12668,6149],{"emptyLinePlaceholder":6148},[6124,12670,12671],{"class":6126,"line":6313},[6124,12672,12673],{"class":9691},"    \u002F\u002F 10. AllowContentType - дозволяє лише певні Content-Type\n",[6124,12675,12676,12678,12680,12682,12684,12686,12688,12691,12693,12695],{"class":6126,"line":6319},[6124,12677,9668],{"class":9667},[6124,12679,5787],{"class":6479},[6124,12681,9701],{"class":9578},[6124,12683,9704],{"class":6479},[6124,12685,9707],{"class":9667},[6124,12687,5787],{"class":6479},[6124,12689,12690],{"class":9578},"AllowContentType",[6124,12692,9704],{"class":6479},[6124,12694,10204],{"class":6503},[6124,12696,10015],{"class":6479},[6124,12698,12699],{"class":6126,"line":6324},[6124,12700,6149],{"emptyLinePlaceholder":6148},[6124,12702,12703],{"class":6126,"line":8100},[6124,12704,12705],{"class":9691},"    \u002F\u002F ... ваші маршрути\n",[6124,12707,12708],{"class":6126,"line":8106},[6124,12709,6167],{"class":6479},[5379,12711,12712],{},[5205,12713,12714],{},"Пояснення ключових middleware:",[6994,12716,12718],{"id":12717},"_1-requestid-унікальний-ідентифікатор-запиту","1. RequestID - унікальний ідентифікатор запиту",[5530,12720,12722],{"className":9594,"code":12721,"language":9579,"meta":5538,"style":5538},"r.Use(middleware.RequestID)\n\nfunc someHandler(w http.ResponseWriter, r *http.Request) {\n    requestID := middleware.GetReqID(r.Context())\n    log.Printf(\"[%s] Processing request\", requestID)\n    \n    \u002F\u002F Додаємо Request ID до відповіді для трейсингу\n    w.Header().Set(\"X-Request-ID\", requestID)\n}\n",[5288,12723,12724,12742,12746,12777,12802,12828,12832,12837,12860],{"__ignoreMap":5538},[6124,12725,12726,12728,12730,12732,12734,12736,12738,12740],{"class":6126,"line":6127},[6124,12727,9806],{"class":9667},[6124,12729,5787],{"class":6479},[6124,12731,9701],{"class":9578},[6124,12733,9704],{"class":6479},[6124,12735,9707],{"class":9667},[6124,12737,5787],{"class":6479},[6124,12739,12464],{"class":9667},[6124,12741,9647],{"class":6479},[6124,12743,12744],{"class":6126,"line":6133},[6124,12745,6149],{"emptyLinePlaceholder":6148},[6124,12747,12748,12750,12753,12755,12757,12759,12761,12763,12765,12767,12769,12771,12773,12775],{"class":6126,"line":6139},[6124,12749,9656],{"class":6483},[6124,12751,12752],{"class":9578}," someHandler",[6124,12754,9704],{"class":6479},[6124,12756,9967],{"class":9667},[6124,12758,9970],{"class":9605},[6124,12760,5787],{"class":6479},[6124,12762,9975],{"class":9605},[6124,12764,5259],{"class":6479},[6124,12766,9806],{"class":9667},[6124,12768,9982],{"class":6479},[6124,12770,6469],{"class":9605},[6124,12772,5787],{"class":6479},[6124,12774,9989],{"class":9605},[6124,12776,9817],{"class":6479},[6124,12778,12779,12782,12784,12786,12788,12791,12793,12795,12797,12799],{"class":6126,"line":6145},[6124,12780,12781],{"class":9667},"    requestID",[6124,12783,9671],{"class":6479},[6124,12785,9707],{"class":9667},[6124,12787,5787],{"class":6479},[6124,12789,12790],{"class":9578},"GetReqID",[6124,12792,9704],{"class":6479},[6124,12794,9806],{"class":9667},[6124,12796,5787],{"class":6479},[6124,12798,12291],{"class":9578},[6124,12800,12801],{"class":6479},"())\n",[6124,12803,12804,12807,12809,12811,12813,12816,12818,12821,12823,12826],{"class":6126,"line":6152},[6124,12805,12806],{"class":9667},"    log",[6124,12808,5787],{"class":6479},[6124,12810,11718],{"class":9578},[6124,12812,9704],{"class":6479},[6124,12814,12815],{"class":6503},"\"[",[6124,12817,11179],{"class":9667},[6124,12819,12820],{"class":6503},"] Processing request\"",[6124,12822,5259],{"class":6479},[6124,12824,12825],{"class":9667},"requestID",[6124,12827,9647],{"class":6479},[6124,12829,12830],{"class":6126,"line":6158},[6124,12831,10356],{"class":6479},[6124,12833,12834],{"class":6126,"line":6164},[6124,12835,12836],{"class":9691},"    \u002F\u002F Додаємо Request ID до відповіді для трейсингу\n",[6124,12838,12839,12841,12843,12845,12847,12849,12851,12854,12856,12858],{"class":6126,"line":6170},[6124,12840,9996],{"class":9667},[6124,12842,5787],{"class":6479},[6124,12844,10189],{"class":9578},[6124,12846,10167],{"class":6479},[6124,12848,10194],{"class":9578},[6124,12850,9704],{"class":6479},[6124,12852,12853],{"class":6503},"\"X-Request-ID\"",[6124,12855,5259],{"class":6479},[6124,12857,12825],{"class":9667},[6124,12859,9647],{"class":6479},[6124,12861,12862],{"class":6126,"line":6175},[6124,12863,6167],{"class":6479},[6994,12865,12867],{"id":12866},"_2-realip-отримання-справжньої-ip-адреси-клієнта","2. RealIP - отримання справжньої IP-адреси клієнта",[5530,12869,12871],{"className":9594,"code":12870,"language":9579,"meta":5538,"style":5538},"r.Use(middleware.RealIP)\n\nfunc someHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Витягує IP з заголовків X-Forwarded-For, X-Real-IP\n    clientIP := r.RemoteAddr\n    log.Printf(\"Request from IP: %s\", clientIP)\n}\n",[5288,12872,12873,12891,12895,12925,12930,12944,12968],{"__ignoreMap":5538},[6124,12874,12875,12877,12879,12881,12883,12885,12887,12889],{"class":6126,"line":6127},[6124,12876,9806],{"class":9667},[6124,12878,5787],{"class":6479},[6124,12880,9701],{"class":9578},[6124,12882,9704],{"class":6479},[6124,12884,9707],{"class":9667},[6124,12886,5787],{"class":6479},[6124,12888,12492],{"class":9667},[6124,12890,9647],{"class":6479},[6124,12892,12893],{"class":6126,"line":6133},[6124,12894,6149],{"emptyLinePlaceholder":6148},[6124,12896,12897,12899,12901,12903,12905,12907,12909,12911,12913,12915,12917,12919,12921,12923],{"class":6126,"line":6139},[6124,12898,9656],{"class":6483},[6124,12900,12752],{"class":9578},[6124,12902,9704],{"class":6479},[6124,12904,9967],{"class":9667},[6124,12906,9970],{"class":9605},[6124,12908,5787],{"class":6479},[6124,12910,9975],{"class":9605},[6124,12912,5259],{"class":6479},[6124,12914,9806],{"class":9667},[6124,12916,9982],{"class":6479},[6124,12918,6469],{"class":9605},[6124,12920,5787],{"class":6479},[6124,12922,9989],{"class":9605},[6124,12924,9817],{"class":6479},[6124,12926,12927],{"class":6126,"line":6145},[6124,12928,12929],{"class":9691},"    \u002F\u002F Витягує IP з заголовків X-Forwarded-For, X-Real-IP\n",[6124,12931,12932,12935,12937,12939,12941],{"class":6126,"line":6152},[6124,12933,12934],{"class":9667},"    clientIP",[6124,12936,9671],{"class":6479},[6124,12938,9806],{"class":9667},[6124,12940,5787],{"class":6479},[6124,12942,12943],{"class":9667},"RemoteAddr\n",[6124,12945,12946,12948,12950,12952,12954,12957,12959,12961,12963,12966],{"class":6126,"line":6158},[6124,12947,12806],{"class":9667},[6124,12949,5787],{"class":6479},[6124,12951,11718],{"class":9578},[6124,12953,9704],{"class":6479},[6124,12955,12956],{"class":6503},"\"Request from IP: ",[6124,12958,11179],{"class":9667},[6124,12960,11182],{"class":6503},[6124,12962,5259],{"class":6479},[6124,12964,12965],{"class":9667},"clientIP",[6124,12967,9647],{"class":6479},[6124,12969,12970],{"class":6126,"line":6164},[6124,12971,6167],{"class":6479},[6994,12973,12975],{"id":12974},"_3-throttle-обмеження-одночасних-запитів","3. Throttle - обмеження одночасних запитів",[5530,12977,12979],{"className":9594,"code":12978,"language":9579,"meta":5538,"style":5538},"\u002F\u002F Дозволяємо не більше 100 одночасних запитів\nr.Use(middleware.Throttle(100))\n\n\u002F\u002F Якщо ліміт перевищено, Chi повертає 429 Too Many Requests\n",[5288,12980,12981,12986,13008,13012],{"__ignoreMap":5538},[6124,12982,12983],{"class":6126,"line":6127},[6124,12984,12985],{"class":9691},"\u002F\u002F Дозволяємо не більше 100 одночасних запитів\n",[6124,12987,12988,12990,12992,12994,12996,12998,13000,13002,13004,13006],{"class":6126,"line":6133},[6124,12989,9806],{"class":9667},[6124,12991,5787],{"class":6479},[6124,12993,9701],{"class":9578},[6124,12995,9704],{"class":6479},[6124,12997,9707],{"class":9667},[6124,12999,5787],{"class":6479},[6124,13001,12563],{"class":9578},[6124,13003,9704],{"class":6479},[6124,13005,12568],{"class":6490},[6124,13007,10015],{"class":6479},[6124,13009,13010],{"class":6126,"line":6139},[6124,13011,6149],{"emptyLinePlaceholder":6148},[6124,13013,13014],{"class":6126,"line":6145},[6124,13015,13016],{"class":9691},"\u002F\u002F Якщо ліміт перевищено, Chi повертає 429 Too Many Requests\n",[6994,13018,13020],{"id":13019},"_4-timeout-таймаут-обробки-запиту","4. Timeout - таймаут обробки запиту",[5530,13022,13024],{"className":9594,"code":13023,"language":9579,"meta":5538,"style":5538},"\u002F\u002F Якщо обробник не встигне відповісти за 30 секунд, \n\u002F\u002F Chi поверне 504 Gateway Timeout\nr.Use(middleware.Timeout(30 * time.Second))\n\nfunc slowHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Можна перевірити, чи не скасовано контекст\n    select {\n    case \u003C-time.After(5 * time.Second):\n        w.Write([]byte(\"Done\"))\n    case \u003C-r.Context().Done():\n        \u002F\u002F Таймаут або клієнт розірвав з'єднання\n        return\n    }\n}\n",[5288,13025,13026,13031,13036,13067,13071,13102,13107,13114,13144,13163,13183,13188,13192,13196],{"__ignoreMap":5538},[6124,13027,13028],{"class":6126,"line":6127},[6124,13029,13030],{"class":9691},"\u002F\u002F Якщо обробник не встигне відповісти за 30 секунд, \n",[6124,13032,13033],{"class":6126,"line":6133},[6124,13034,13035],{"class":9691},"\u002F\u002F Chi поверне 504 Gateway Timeout\n",[6124,13037,13038,13040,13042,13044,13046,13048,13050,13052,13054,13057,13059,13061,13063,13065],{"class":6126,"line":6139},[6124,13039,9806],{"class":9667},[6124,13041,5787],{"class":6479},[6124,13043,9701],{"class":9578},[6124,13045,9704],{"class":6479},[6124,13047,9707],{"class":9667},[6124,13049,5787],{"class":6479},[6124,13051,12520],{"class":9578},[6124,13053,9704],{"class":6479},[6124,13055,13056],{"class":6490},"30",[6124,13058,12528],{"class":6479},[6124,13060,11641],{"class":9667},[6124,13062,5787],{"class":6479},[6124,13064,12535],{"class":9667},[6124,13066,10015],{"class":6479},[6124,13068,13069],{"class":6126,"line":6145},[6124,13070,6149],{"emptyLinePlaceholder":6148},[6124,13072,13073,13075,13078,13080,13082,13084,13086,13088,13090,13092,13094,13096,13098,13100],{"class":6126,"line":6152},[6124,13074,9656],{"class":6483},[6124,13076,13077],{"class":9578}," slowHandler",[6124,13079,9704],{"class":6479},[6124,13081,9967],{"class":9667},[6124,13083,9970],{"class":9605},[6124,13085,5787],{"class":6479},[6124,13087,9975],{"class":9605},[6124,13089,5259],{"class":6479},[6124,13091,9806],{"class":9667},[6124,13093,9982],{"class":6479},[6124,13095,6469],{"class":9605},[6124,13097,5787],{"class":6479},[6124,13099,9989],{"class":9605},[6124,13101,9817],{"class":6479},[6124,13103,13104],{"class":6126,"line":6158},[6124,13105,13106],{"class":9691},"    \u002F\u002F Можна перевірити, чи не скасовано контекст\n",[6124,13108,13109,13112],{"class":6126,"line":6164},[6124,13110,13111],{"class":6476},"    select",[6124,13113,10516],{"class":6479},[6124,13115,13116,13119,13122,13124,13126,13129,13131,13133,13135,13137,13139,13141],{"class":6126,"line":6170},[6124,13117,13118],{"class":6476},"    case",[6124,13120,13121],{"class":6479}," \u003C-",[6124,13123,11641],{"class":9667},[6124,13125,5787],{"class":6479},[6124,13127,13128],{"class":9578},"After",[6124,13130,9704],{"class":6479},[6124,13132,12601],{"class":6490},[6124,13134,12528],{"class":6479},[6124,13136,11641],{"class":9667},[6124,13138,5787],{"class":6479},[6124,13140,12535],{"class":9667},[6124,13142,13143],{"class":6479},"):\n",[6124,13145,13146,13148,13150,13152,13154,13156,13158,13161],{"class":6126,"line":6175},[6124,13147,11873],{"class":9667},[6124,13149,5787],{"class":6479},[6124,13151,10001],{"class":9578},[6124,13153,10004],{"class":6479},[6124,13155,10007],{"class":9605},[6124,13157,9704],{"class":6479},[6124,13159,13160],{"class":6503},"\"Done\"",[6124,13162,10015],{"class":6479},[6124,13164,13165,13167,13169,13171,13173,13175,13177,13180],{"class":6126,"line":6181},[6124,13166,13118],{"class":6476},[6124,13168,13121],{"class":6479},[6124,13170,9806],{"class":9667},[6124,13172,5787],{"class":6479},[6124,13174,12291],{"class":9578},[6124,13176,10167],{"class":6479},[6124,13178,13179],{"class":9578},"Done",[6124,13181,13182],{"class":6479},"():\n",[6124,13184,13185],{"class":6126,"line":6187},[6124,13186,13187],{"class":9691},"        \u002F\u002F Таймаут або клієнт розірвав з'єднання\n",[6124,13189,13190],{"class":6126,"line":6193},[6124,13191,10635],{"class":6476},[6124,13193,13194],{"class":6126,"line":6199},[6124,13195,10545],{"class":6479},[6124,13197,13198],{"class":6126,"line":6204},[6124,13199,6167],{"class":6479},[5374,13201,13203],{"id":13202},"монтування-суб-роутерів-через-mount","Монтування суб-роутерів через Mount",[5379,13205,13206,13209],{},[5288,13207,13208],{},"Mount"," дозволяє підключити окремий роутер як модуль:",[5530,13211,13213],{"className":9594,"code":13212,"language":9579,"meta":5538,"style":5538},"func main() {\n    r := chi.NewRouter()\n\n    \u002F\u002F Монтуємо API v1\n    r.Mount(\"\u002Fapi\u002Fv1\", apiV1Router())\n    \n    \u002F\u002F Монтуємо API v2\n    r.Mount(\"\u002Fapi\u002Fv2\", apiV2Router())\n    \n    \u002F\u002F Монтуємо адмін-панель\n    r.Mount(\"\u002Fadmin\", adminRouter())\n\n    http.ListenAndServe(\":8080\", r)\n}\n\nfunc apiV1Router() chi.Router {\n    r := chi.NewRouter()\n    r.Use(corsMiddleware)\n    \n    r.Get(\"\u002Forders\", listOrdersHandler)\n    r.Post(\"\u002Forders\", createOrderHandler)\n    \n    return r\n}\n\nfunc apiV2Router() chi.Router {\n    r := chi.NewRouter()\n    r.Use(corsMiddleware)\n    r.Use(authMiddleware) \u002F\u002F V2 вимагає автентифікації\n    \n    r.Get(\"\u002Forders\", listOrdersV2Handler)\n    r.Post(\"\u002Forders\", createOrderV2Handler)\n    \n    return r\n}\n\nfunc adminRouter() chi.Router {\n    r := chi.NewRouter()\n    r.Use(adminAuthMiddleware) \u002F\u002F Окрема автентифікація для адмінів\n    \n    r.Get(\"\u002Fusers\", listUsersHandler)\n    r.Get(\"\u002Fstats\", statsHandler)\n    \n    return r\n}\n",[5288,13214,13215,13223,13237,13241,13246,13266,13270,13275,13295,13299,13304,13324,13328,13346,13350,13354,13372,13386,13400,13404,13422,13440,13444,13451,13455,13459,13476,13490,13504,13521,13525,13544,13563,13567,13573,13577,13581,13598,13612,13630,13634,13654,13674,13678,13684],{"__ignoreMap":5538},[6124,13216,13217,13219,13221],{"class":6126,"line":6127},[6124,13218,9656],{"class":6483},[6124,13220,9659],{"class":9578},[6124,13222,9662],{"class":6479},[6124,13224,13225,13227,13229,13231,13233,13235],{"class":6126,"line":6133},[6124,13226,9668],{"class":9667},[6124,13228,9671],{"class":6479},[6124,13230,9674],{"class":9667},[6124,13232,5787],{"class":6479},[6124,13234,9679],{"class":9578},[6124,13236,9682],{"class":6479},[6124,13238,13239],{"class":6126,"line":6139},[6124,13240,6149],{"emptyLinePlaceholder":6148},[6124,13242,13243],{"class":6126,"line":6145},[6124,13244,13245],{"class":9691},"    \u002F\u002F Монтуємо API v1\n",[6124,13247,13248,13250,13252,13254,13256,13259,13261,13264],{"class":6126,"line":6152},[6124,13249,9668],{"class":9667},[6124,13251,5787],{"class":6479},[6124,13253,13208],{"class":9578},[6124,13255,9704],{"class":6479},[6124,13257,13258],{"class":6503},"\"\u002Fapi\u002Fv1\"",[6124,13260,5259],{"class":6479},[6124,13262,13263],{"class":9578},"apiV1Router",[6124,13265,12801],{"class":6479},[6124,13267,13268],{"class":6126,"line":6158},[6124,13269,10356],{"class":6479},[6124,13271,13272],{"class":6126,"line":6164},[6124,13273,13274],{"class":9691},"    \u002F\u002F Монтуємо API v2\n",[6124,13276,13277,13279,13281,13283,13285,13288,13290,13293],{"class":6126,"line":6170},[6124,13278,9668],{"class":9667},[6124,13280,5787],{"class":6479},[6124,13282,13208],{"class":9578},[6124,13284,9704],{"class":6479},[6124,13286,13287],{"class":6503},"\"\u002Fapi\u002Fv2\"",[6124,13289,5259],{"class":6479},[6124,13291,13292],{"class":9578},"apiV2Router",[6124,13294,12801],{"class":6479},[6124,13296,13297],{"class":6126,"line":6175},[6124,13298,10356],{"class":6479},[6124,13300,13301],{"class":6126,"line":6181},[6124,13302,13303],{"class":9691},"    \u002F\u002F Монтуємо адмін-панель\n",[6124,13305,13306,13308,13310,13312,13314,13317,13319,13322],{"class":6126,"line":6187},[6124,13307,9668],{"class":9667},[6124,13309,5787],{"class":6479},[6124,13311,13208],{"class":9578},[6124,13313,9704],{"class":6479},[6124,13315,13316],{"class":6503},"\"\u002Fadmin\"",[6124,13318,5259],{"class":6479},[6124,13320,13321],{"class":9578},"adminRouter",[6124,13323,12801],{"class":6479},[6124,13325,13326],{"class":6126,"line":6193},[6124,13327,6149],{"emptyLinePlaceholder":6148},[6124,13329,13330,13332,13334,13336,13338,13340,13342,13344],{"class":6126,"line":6199},[6124,13331,9931],{"class":9667},[6124,13333,5787],{"class":6479},[6124,13335,9936],{"class":9578},[6124,13337,9704],{"class":6479},[6124,13339,9941],{"class":6503},[6124,13341,5259],{"class":6479},[6124,13343,9806],{"class":9667},[6124,13345,9647],{"class":6479},[6124,13347,13348],{"class":6126,"line":6204},[6124,13349,6167],{"class":6479},[6124,13351,13352],{"class":6126,"line":6209},[6124,13353,6149],{"emptyLinePlaceholder":6148},[6124,13355,13356,13358,13361,13364,13366,13368,13370],{"class":6126,"line":6215},[6124,13357,9656],{"class":6483},[6124,13359,13360],{"class":9578}," apiV1Router",[6124,13362,13363],{"class":6479},"() ",[6124,13365,9674],{"class":9605},[6124,13367,5787],{"class":6479},[6124,13369,9814],{"class":9605},[6124,13371,10516],{"class":6479},[6124,13373,13374,13376,13378,13380,13382,13384],{"class":6126,"line":6221},[6124,13375,9668],{"class":9667},[6124,13377,9671],{"class":6479},[6124,13379,9674],{"class":9667},[6124,13381,5787],{"class":6479},[6124,13383,9679],{"class":9578},[6124,13385,9682],{"class":6479},[6124,13387,13388,13390,13392,13394,13396,13398],{"class":6126,"line":6227},[6124,13389,9668],{"class":9667},[6124,13391,5787],{"class":6479},[6124,13393,9701],{"class":9578},[6124,13395,9704],{"class":6479},[6124,13397,11359],{"class":9667},[6124,13399,9647],{"class":6479},[6124,13401,13402],{"class":6126,"line":6232},[6124,13403,10356],{"class":6479},[6124,13405,13406,13408,13410,13412,13414,13416,13418,13420],{"class":6126,"line":6237},[6124,13407,9668],{"class":9667},[6124,13409,5787],{"class":6479},[6124,13411,9751],{"class":9578},[6124,13413,9704],{"class":6479},[6124,13415,9831],{"class":6503},[6124,13417,5259],{"class":6479},[6124,13419,9836],{"class":9667},[6124,13421,9647],{"class":6479},[6124,13423,13424,13426,13428,13430,13432,13434,13436,13438],{"class":6126,"line":6243},[6124,13425,9668],{"class":9667},[6124,13427,5787],{"class":6479},[6124,13429,9847],{"class":9578},[6124,13431,9704],{"class":6479},[6124,13433,9831],{"class":6503},[6124,13435,5259],{"class":6479},[6124,13437,9856],{"class":9667},[6124,13439,9647],{"class":6479},[6124,13441,13442],{"class":6126,"line":6249},[6124,13443,10356],{"class":6479},[6124,13445,13446,13448],{"class":6126,"line":6255},[6124,13447,11596],{"class":6476},[6124,13449,13450],{"class":9667}," r\n",[6124,13452,13453],{"class":6126,"line":6261},[6124,13454,6167],{"class":6479},[6124,13456,13457],{"class":6126,"line":6267},[6124,13458,6149],{"emptyLinePlaceholder":6148},[6124,13460,13461,13463,13466,13468,13470,13472,13474],{"class":6126,"line":6272},[6124,13462,9656],{"class":6483},[6124,13464,13465],{"class":9578}," apiV2Router",[6124,13467,13363],{"class":6479},[6124,13469,9674],{"class":9605},[6124,13471,5787],{"class":6479},[6124,13473,9814],{"class":9605},[6124,13475,10516],{"class":6479},[6124,13477,13478,13480,13482,13484,13486,13488],{"class":6126,"line":6278},[6124,13479,9668],{"class":9667},[6124,13481,9671],{"class":6479},[6124,13483,9674],{"class":9667},[6124,13485,5787],{"class":6479},[6124,13487,9679],{"class":9578},[6124,13489,9682],{"class":6479},[6124,13491,13492,13494,13496,13498,13500,13502],{"class":6126,"line":6284},[6124,13493,9668],{"class":9667},[6124,13495,5787],{"class":6479},[6124,13497,9701],{"class":9578},[6124,13499,9704],{"class":6479},[6124,13501,11359],{"class":9667},[6124,13503,9647],{"class":6479},[6124,13505,13506,13508,13510,13512,13514,13516,13518],{"class":6126,"line":6290},[6124,13507,9668],{"class":9667},[6124,13509,5787],{"class":6479},[6124,13511,9701],{"class":9578},[6124,13513,9704],{"class":6479},[6124,13515,11374],{"class":9667},[6124,13517,7173],{"class":6479},[6124,13519,13520],{"class":9691},"\u002F\u002F V2 вимагає автентифікації\n",[6124,13522,13523],{"class":6126,"line":6296},[6124,13524,10356],{"class":6479},[6124,13526,13527,13529,13531,13533,13535,13537,13539,13542],{"class":6126,"line":6301},[6124,13528,9668],{"class":9667},[6124,13530,5787],{"class":6479},[6124,13532,9751],{"class":9578},[6124,13534,9704],{"class":6479},[6124,13536,9831],{"class":6503},[6124,13538,5259],{"class":6479},[6124,13540,13541],{"class":9667},"listOrdersV2Handler",[6124,13543,9647],{"class":6479},[6124,13545,13546,13548,13550,13552,13554,13556,13558,13561],{"class":6126,"line":6307},[6124,13547,9668],{"class":9667},[6124,13549,5787],{"class":6479},[6124,13551,9847],{"class":9578},[6124,13553,9704],{"class":6479},[6124,13555,9831],{"class":6503},[6124,13557,5259],{"class":6479},[6124,13559,13560],{"class":9667},"createOrderV2Handler",[6124,13562,9647],{"class":6479},[6124,13564,13565],{"class":6126,"line":6313},[6124,13566,10356],{"class":6479},[6124,13568,13569,13571],{"class":6126,"line":6319},[6124,13570,11596],{"class":6476},[6124,13572,13450],{"class":9667},[6124,13574,13575],{"class":6126,"line":6324},[6124,13576,6167],{"class":6479},[6124,13578,13579],{"class":6126,"line":8100},[6124,13580,6149],{"emptyLinePlaceholder":6148},[6124,13582,13583,13585,13588,13590,13592,13594,13596],{"class":6126,"line":8106},[6124,13584,9656],{"class":6483},[6124,13586,13587],{"class":9578}," adminRouter",[6124,13589,13363],{"class":6479},[6124,13591,9674],{"class":9605},[6124,13593,5787],{"class":6479},[6124,13595,9814],{"class":9605},[6124,13597,10516],{"class":6479},[6124,13599,13600,13602,13604,13606,13608,13610],{"class":6126,"line":8112},[6124,13601,9668],{"class":9667},[6124,13603,9671],{"class":6479},[6124,13605,9674],{"class":9667},[6124,13607,5787],{"class":6479},[6124,13609,9679],{"class":9578},[6124,13611,9682],{"class":6479},[6124,13613,13614,13616,13618,13620,13622,13625,13627],{"class":6126,"line":8117},[6124,13615,9668],{"class":9667},[6124,13617,5787],{"class":6479},[6124,13619,9701],{"class":9578},[6124,13621,9704],{"class":6479},[6124,13623,13624],{"class":9667},"adminAuthMiddleware",[6124,13626,7173],{"class":6479},[6124,13628,13629],{"class":9691},"\u002F\u002F Окрема автентифікація для адмінів\n",[6124,13631,13632],{"class":6126,"line":8123},[6124,13633,10356],{"class":6479},[6124,13635,13636,13638,13640,13642,13644,13647,13649,13652],{"class":6126,"line":8129},[6124,13637,9668],{"class":9667},[6124,13639,5787],{"class":6479},[6124,13641,9751],{"class":9578},[6124,13643,9704],{"class":6479},[6124,13645,13646],{"class":6503},"\"\u002Fusers\"",[6124,13648,5259],{"class":6479},[6124,13650,13651],{"class":9667},"listUsersHandler",[6124,13653,9647],{"class":6479},[6124,13655,13656,13658,13660,13662,13664,13667,13669,13672],{"class":6126,"line":8135},[6124,13657,9668],{"class":9667},[6124,13659,5787],{"class":6479},[6124,13661,9751],{"class":9578},[6124,13663,9704],{"class":6479},[6124,13665,13666],{"class":6503},"\"\u002Fstats\"",[6124,13668,5259],{"class":6479},[6124,13670,13671],{"class":9667},"statsHandler",[6124,13673,9647],{"class":6479},[6124,13675,13676],{"class":6126,"line":8141},[6124,13677,10356],{"class":6479},[6124,13679,13680,13682],{"class":6126,"line":8146},[6124,13681,11596],{"class":6476},[6124,13683,13450],{"class":9667},[6124,13685,13686],{"class":6126,"line":10209},[6124,13687,6167],{"class":6479},[5374,13689,13691],{"id":13690},"обробка-404-та-405-помилок","Обробка 404 та 405 помилок",[5379,13693,13694],{},"Chi дозволяє налаштувати користувацькі обробники для неіснуючих маршрутів:",[5530,13696,13698],{"className":9594,"code":13697,"language":9579,"meta":5538,"style":5538},"r := chi.NewRouter()\n\n\u002F\u002F Користувацький обробник для 404 Not Found\nr.NotFound(func(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusNotFound)\n    json.NewEncoder(w).Encode(map[string]interface{}{\n        \"error\": \"Route not found\",\n        \"path\":  r.URL.Path,\n        \"method\": r.Method,\n    })\n})\n\n\u002F\u002F Користувацький обробник для 405 Method Not Allowed\nr.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusMethodNotAllowed)\n    json.NewEncoder(w).Encode(map[string]interface{}{\n        \"error\": fmt.Sprintf(\"Method %s not allowed for %s\", r.Method, r.URL.Path),\n        \"allowed_methods\": []string{\"GET\", \"POST\"}, \u002F\u002F Можна динамічно визначати\n    })\n})\n",[5288,13699,13700,13714,13718,13723,13760,13782,13801,13831,13843,13862,13877,13881,13885,13889,13894,13931,13953,13972,14002,14053,14079,14083],{"__ignoreMap":5538},[6124,13701,13702,13704,13706,13708,13710,13712],{"class":6126,"line":6127},[6124,13703,9806],{"class":9667},[6124,13705,9671],{"class":6479},[6124,13707,9674],{"class":9667},[6124,13709,5787],{"class":6479},[6124,13711,9679],{"class":9578},[6124,13713,9682],{"class":6479},[6124,13715,13716],{"class":6126,"line":6133},[6124,13717,6149],{"emptyLinePlaceholder":6148},[6124,13719,13720],{"class":6126,"line":6139},[6124,13721,13722],{"class":9691},"\u002F\u002F Користувацький обробник для 404 Not Found\n",[6124,13724,13725,13727,13729,13732,13734,13736,13738,13740,13742,13744,13746,13748,13750,13752,13754,13756,13758],{"class":6126,"line":6145},[6124,13726,9806],{"class":9667},[6124,13728,5787],{"class":6479},[6124,13730,13731],{"class":9578},"NotFound",[6124,13733,9704],{"class":6479},[6124,13735,9656],{"class":6483},[6124,13737,9704],{"class":6479},[6124,13739,9967],{"class":9667},[6124,13741,9970],{"class":9605},[6124,13743,5787],{"class":6479},[6124,13745,9975],{"class":9605},[6124,13747,5259],{"class":6479},[6124,13749,9806],{"class":9667},[6124,13751,9982],{"class":6479},[6124,13753,6469],{"class":9605},[6124,13755,5787],{"class":6479},[6124,13757,9989],{"class":9605},[6124,13759,9817],{"class":6479},[6124,13761,13762,13764,13766,13768,13770,13772,13774,13776,13778,13780],{"class":6126,"line":6152},[6124,13763,9996],{"class":9667},[6124,13765,5787],{"class":6479},[6124,13767,10189],{"class":9578},[6124,13769,10167],{"class":6479},[6124,13771,10194],{"class":9578},[6124,13773,9704],{"class":6479},[6124,13775,10199],{"class":6503},[6124,13777,5259],{"class":6479},[6124,13779,10204],{"class":6503},[6124,13781,9647],{"class":6479},[6124,13783,13784,13786,13788,13790,13792,13794,13796,13799],{"class":6126,"line":6158},[6124,13785,9996],{"class":9667},[6124,13787,5787],{"class":6479},[6124,13789,10681],{"class":9578},[6124,13791,9704],{"class":6479},[6124,13793,6469],{"class":9667},[6124,13795,5787],{"class":6479},[6124,13797,13798],{"class":9667},"StatusNotFound",[6124,13800,9647],{"class":6479},[6124,13802,13803,13805,13807,13809,13811,13813,13815,13817,13819,13821,13823,13825,13827,13829],{"class":6126,"line":6164},[6124,13804,10059],{"class":9667},[6124,13806,5787],{"class":6479},[6124,13808,10064],{"class":9578},[6124,13810,9704],{"class":6479},[6124,13812,9967],{"class":9667},[6124,13814,5407],{"class":6479},[6124,13816,10073],{"class":9578},[6124,13818,9704],{"class":6479},[6124,13820,10078],{"class":6483},[6124,13822,10081],{"class":6479},[6124,13824,10084],{"class":9605},[6124,13826,10087],{"class":6479},[6124,13828,10236],{"class":6483},[6124,13830,10239],{"class":6479},[6124,13832,13833,13836,13838,13841],{"class":6126,"line":6170},[6124,13834,13835],{"class":6503},"        \"error\"",[6124,13837,6552],{"class":6479},[6124,13839,13840],{"class":6503},"\"Route not found\"",[6124,13842,6558],{"class":6479},[6124,13844,13845,13848,13850,13852,13854,13856,13858,13860],{"class":6126,"line":6175},[6124,13846,13847],{"class":6503},"        \"path\"",[6124,13849,10783],{"class":6479},[6124,13851,9806],{"class":9667},[6124,13853,5787],{"class":6479},[6124,13855,10159],{"class":9667},[6124,13857,5787],{"class":6479},[6124,13859,11754],{"class":9667},[6124,13861,6558],{"class":6479},[6124,13863,13864,13867,13869,13871,13873,13875],{"class":6126,"line":6181},[6124,13865,13866],{"class":6503},"        \"method\"",[6124,13868,6552],{"class":6479},[6124,13870,9806],{"class":9667},[6124,13872,5787],{"class":6479},[6124,13874,11741],{"class":9667},[6124,13876,6558],{"class":6479},[6124,13878,13879],{"class":6126,"line":6187},[6124,13880,9922],{"class":6479},[6124,13882,13883],{"class":6126,"line":6193},[6124,13884,10101],{"class":6479},[6124,13886,13887],{"class":6126,"line":6199},[6124,13888,6149],{"emptyLinePlaceholder":6148},[6124,13890,13891],{"class":6126,"line":6204},[6124,13892,13893],{"class":9691},"\u002F\u002F Користувацький обробник для 405 Method Not Allowed\n",[6124,13895,13896,13898,13900,13903,13905,13907,13909,13911,13913,13915,13917,13919,13921,13923,13925,13927,13929],{"class":6126,"line":6209},[6124,13897,9806],{"class":9667},[6124,13899,5787],{"class":6479},[6124,13901,13902],{"class":9578},"MethodNotAllowed",[6124,13904,9704],{"class":6479},[6124,13906,9656],{"class":6483},[6124,13908,9704],{"class":6479},[6124,13910,9967],{"class":9667},[6124,13912,9970],{"class":9605},[6124,13914,5787],{"class":6479},[6124,13916,9975],{"class":9605},[6124,13918,5259],{"class":6479},[6124,13920,9806],{"class":9667},[6124,13922,9982],{"class":6479},[6124,13924,6469],{"class":9605},[6124,13926,5787],{"class":6479},[6124,13928,9989],{"class":9605},[6124,13930,9817],{"class":6479},[6124,13932,13933,13935,13937,13939,13941,13943,13945,13947,13949,13951],{"class":6126,"line":6215},[6124,13934,9996],{"class":9667},[6124,13936,5787],{"class":6479},[6124,13938,10189],{"class":9578},[6124,13940,10167],{"class":6479},[6124,13942,10194],{"class":9578},[6124,13944,9704],{"class":6479},[6124,13946,10199],{"class":6503},[6124,13948,5259],{"class":6479},[6124,13950,10204],{"class":6503},[6124,13952,9647],{"class":6479},[6124,13954,13955,13957,13959,13961,13963,13965,13967,13970],{"class":6126,"line":6221},[6124,13956,9996],{"class":9667},[6124,13958,5787],{"class":6479},[6124,13960,10681],{"class":9578},[6124,13962,9704],{"class":6479},[6124,13964,6469],{"class":9667},[6124,13966,5787],{"class":6479},[6124,13968,13969],{"class":9667},"StatusMethodNotAllowed",[6124,13971,9647],{"class":6479},[6124,13973,13974,13976,13978,13980,13982,13984,13986,13988,13990,13992,13994,13996,13998,14000],{"class":6126,"line":6227},[6124,13975,10059],{"class":9667},[6124,13977,5787],{"class":6479},[6124,13979,10064],{"class":9578},[6124,13981,9704],{"class":6479},[6124,13983,9967],{"class":9667},[6124,13985,5407],{"class":6479},[6124,13987,10073],{"class":9578},[6124,13989,9704],{"class":6479},[6124,13991,10078],{"class":6483},[6124,13993,10081],{"class":6479},[6124,13995,10084],{"class":9605},[6124,13997,10087],{"class":6479},[6124,13999,10236],{"class":6483},[6124,14001,10239],{"class":6479},[6124,14003,14004,14006,14008,14011,14013,14016,14018,14021,14023,14026,14028,14030,14032,14034,14036,14038,14040,14042,14044,14046,14048,14050],{"class":6126,"line":6232},[6124,14005,13835],{"class":6503},[6124,14007,6552],{"class":6479},[6124,14009,14010],{"class":9667},"fmt",[6124,14012,5787],{"class":6479},[6124,14014,14015],{"class":9578},"Sprintf",[6124,14017,9704],{"class":6479},[6124,14019,14020],{"class":6503},"\"Method ",[6124,14022,11179],{"class":9667},[6124,14024,14025],{"class":6503}," not allowed for ",[6124,14027,11179],{"class":9667},[6124,14029,11182],{"class":6503},[6124,14031,5259],{"class":6479},[6124,14033,9806],{"class":9667},[6124,14035,5787],{"class":6479},[6124,14037,11741],{"class":9667},[6124,14039,5259],{"class":6479},[6124,14041,9806],{"class":9667},[6124,14043,5787],{"class":6479},[6124,14045,10159],{"class":9667},[6124,14047,5787],{"class":6479},[6124,14049,11754],{"class":9667},[6124,14051,14052],{"class":6479},"),\n",[6124,14054,14055,14058,14061,14063,14065,14068,14070,14073,14076],{"class":6126,"line":6237},[6124,14056,14057],{"class":6503},"        \"allowed_methods\"",[6124,14059,14060],{"class":6479},": []",[6124,14062,10084],{"class":9605},[6124,14064,8747],{"class":6479},[6124,14066,14067],{"class":6503},"\"GET\"",[6124,14069,5259],{"class":6479},[6124,14071,14072],{"class":6503},"\"POST\"",[6124,14074,14075],{"class":6479},"}, ",[6124,14077,14078],{"class":9691},"\u002F\u002F Можна динамічно визначати\n",[6124,14080,14081],{"class":6126,"line":6243},[6124,14082,9922],{"class":6479},[6124,14084,14085],{"class":6126,"line":6249},[6124,14086,10101],{"class":6479},[5374,14088,14090],{"id":14089},"передача-даних-через-context","Передача даних через Context",[5379,14092,14093,14094,14096],{},"Chi використовує стандартний ",[5288,14095,5758],{}," для передачі даних між middleware та обробниками:",[5530,14098,14100],{"className":9594,"code":14099,"language":9579,"meta":5538,"style":5538},"\u002F\u002F Middleware додає дані до контексту\nfunc userMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        userID := chi.URLParam(r, \"userID\")\n        \n        \u002F\u002F Завантажуємо користувача з БД\n        user, err := getUserFromDB(userID)\n        if err != nil {\n            http.Error(w, \"User not found\", http.StatusNotFound)\n            return\n        }\n\n        \u002F\u002F Додаємо користувача до контексту\n        ctx := context.WithValue(r.Context(), \"user\", user)\n        next.ServeHTTP(w, r.WithContext(ctx))\n    })\n}\n\n\u002F\u002F Обробник витягує дані з контексту\nfunc getUserOrdersHandler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Витягуємо користувача з контексту\n    user := r.Context().Value(\"user\").(*User)\n    \n    orders := getOrdersForUser(user.ID)\n    \n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(orders)\n}\n\n\u002F\u002F Використання\nr.Route(\"\u002Fusers\u002F{userID}\", func(r chi.Router) {\n    r.Use(userMiddleware) \u002F\u002F Застосовується до всіх маршрутів нижче\n    r.Get(\"\u002Forders\", getUserOrdersHandler)\n    r.Get(\"\u002Fprofile\", getUserProfileHandler)\n})\n",[5288,14101,14102,14107,14134,14172,14194,14198,14203,14223,14235,14262,14266,14270,14274,14279,14311,14337,14341,14345,14349,14354,14385,14390,14420,14424,14445,14449,14471,14494,14498,14502,14507,14536,14554,14573,14593],{"__ignoreMap":5538},[6124,14103,14104],{"class":6126,"line":6127},[6124,14105,14106],{"class":9691},"\u002F\u002F Middleware додає дані до контексту\n",[6124,14108,14109,14111,14114,14116,14118,14120,14122,14124,14126,14128,14130,14132],{"class":6126,"line":6133},[6124,14110,9656],{"class":6483},[6124,14112,14113],{"class":9578}," userMiddleware",[6124,14115,9704],{"class":6479},[6124,14117,11574],{"class":9667},[6124,14119,9970],{"class":9605},[6124,14121,5787],{"class":6479},[6124,14123,11581],{"class":9605},[6124,14125,7173],{"class":6479},[6124,14127,6469],{"class":9605},[6124,14129,5787],{"class":6479},[6124,14131,11581],{"class":9605},[6124,14133,10516],{"class":6479},[6124,14135,14136,14138,14140,14142,14144,14146,14148,14150,14152,14154,14156,14158,14160,14162,14164,14166,14168,14170],{"class":6126,"line":6139},[6124,14137,11596],{"class":6476},[6124,14139,9970],{"class":9667},[6124,14141,5787],{"class":6479},[6124,14143,11603],{"class":9578},[6124,14145,9704],{"class":6479},[6124,14147,9656],{"class":6483},[6124,14149,9704],{"class":6479},[6124,14151,9967],{"class":9667},[6124,14153,9970],{"class":9605},[6124,14155,5787],{"class":6479},[6124,14157,9975],{"class":9605},[6124,14159,5259],{"class":6479},[6124,14161,9806],{"class":9667},[6124,14163,9982],{"class":6479},[6124,14165,6469],{"class":9605},[6124,14167,5787],{"class":6479},[6124,14169,9989],{"class":9605},[6124,14171,9817],{"class":6479},[6124,14173,14174,14176,14178,14180,14182,14184,14186,14188,14190,14192],{"class":6126,"line":6145},[6124,14175,12196],{"class":9667},[6124,14177,9671],{"class":6479},[6124,14179,9674],{"class":9667},[6124,14181,5787],{"class":6479},[6124,14183,10339],{"class":9578},[6124,14185,9704],{"class":6479},[6124,14187,9806],{"class":9667},[6124,14189,5259],{"class":6479},[6124,14191,12297],{"class":6503},[6124,14193,9647],{"class":6479},[6124,14195,14196],{"class":6126,"line":6152},[6124,14197,11653],{"class":6479},[6124,14199,14200],{"class":6126,"line":6158},[6124,14201,14202],{"class":9691},"        \u002F\u002F Завантажуємо користувача з БД\n",[6124,14204,14205,14208,14210,14212,14214,14217,14219,14221],{"class":6126,"line":6164},[6124,14206,14207],{"class":9667},"        user",[6124,14209,5259],{"class":6479},[6124,14211,10590],{"class":9667},[6124,14213,9671],{"class":6479},[6124,14215,14216],{"class":9578},"getUserFromDB",[6124,14218,9704],{"class":6479},[6124,14220,10261],{"class":9667},[6124,14222,9647],{"class":6479},[6124,14224,14225,14227,14229,14231,14233],{"class":6126,"line":6170},[6124,14226,11955],{"class":6476},[6124,14228,10554],{"class":9667},[6124,14230,10593],{"class":6479},[6124,14232,10596],{"class":6483},[6124,14234,10516],{"class":6479},[6124,14236,14237,14239,14241,14243,14245,14247,14249,14252,14254,14256,14258,14260],{"class":6126,"line":6175},[6124,14238,12150],{"class":9667},[6124,14240,5787],{"class":6479},[6124,14242,10609],{"class":9578},[6124,14244,9704],{"class":6479},[6124,14246,9967],{"class":9667},[6124,14248,5259],{"class":6479},[6124,14250,14251],{"class":6503},"\"User not found\"",[6124,14253,5259],{"class":6479},[6124,14255,6469],{"class":9667},[6124,14257,5787],{"class":6479},[6124,14259,13798],{"class":9667},[6124,14261,9647],{"class":6479},[6124,14263,14264],{"class":6126,"line":6181},[6124,14265,11997],{"class":6476},[6124,14267,14268],{"class":6126,"line":6187},[6124,14269,12002],{"class":6479},[6124,14271,14272],{"class":6126,"line":6193},[6124,14273,6149],{"emptyLinePlaceholder":6148},[6124,14275,14276],{"class":6126,"line":6199},[6124,14277,14278],{"class":9691},"        \u002F\u002F Додаємо користувача до контексту\n",[6124,14280,14281,14283,14285,14287,14289,14291,14293,14295,14297,14299,14301,14304,14306,14309],{"class":6126,"line":6204},[6124,14282,12273],{"class":9667},[6124,14284,9671],{"class":6479},[6124,14286,5349],{"class":9667},[6124,14288,5787],{"class":6479},[6124,14290,12282],{"class":9578},[6124,14292,9704],{"class":6479},[6124,14294,9806],{"class":9667},[6124,14296,5787],{"class":6479},[6124,14298,12291],{"class":9578},[6124,14300,12294],{"class":6479},[6124,14302,14303],{"class":6503},"\"user\"",[6124,14305,5259],{"class":6479},[6124,14307,14308],{"class":9667},"user",[6124,14310,9647],{"class":6479},[6124,14312,14313,14315,14317,14319,14321,14323,14325,14327,14329,14331,14333,14335],{"class":6126,"line":6209},[6124,14314,11663],{"class":9667},[6124,14316,5787],{"class":6479},[6124,14318,11668],{"class":9578},[6124,14320,9704],{"class":6479},[6124,14322,9967],{"class":9667},[6124,14324,5259],{"class":6479},[6124,14326,9806],{"class":9667},[6124,14328,5787],{"class":6479},[6124,14330,12324],{"class":9578},[6124,14332,9704],{"class":6479},[6124,14334,12329],{"class":9667},[6124,14336,10015],{"class":6479},[6124,14338,14339],{"class":6126,"line":6215},[6124,14340,9922],{"class":6479},[6124,14342,14343],{"class":6126,"line":6221},[6124,14344,6167],{"class":6479},[6124,14346,14347],{"class":6126,"line":6227},[6124,14348,6149],{"emptyLinePlaceholder":6148},[6124,14350,14351],{"class":6126,"line":6232},[6124,14352,14353],{"class":9691},"\u002F\u002F Обробник витягує дані з контексту\n",[6124,14355,14356,14358,14361,14363,14365,14367,14369,14371,14373,14375,14377,14379,14381,14383],{"class":6126,"line":6237},[6124,14357,9656],{"class":6483},[6124,14359,14360],{"class":9578}," getUserOrdersHandler",[6124,14362,9704],{"class":6479},[6124,14364,9967],{"class":9667},[6124,14366,9970],{"class":9605},[6124,14368,5787],{"class":6479},[6124,14370,9975],{"class":9605},[6124,14372,5259],{"class":6479},[6124,14374,9806],{"class":9667},[6124,14376,9982],{"class":6479},[6124,14378,6469],{"class":9605},[6124,14380,5787],{"class":6479},[6124,14382,9989],{"class":9605},[6124,14384,9817],{"class":6479},[6124,14386,14387],{"class":6126,"line":6243},[6124,14388,14389],{"class":9691},"    \u002F\u002F Витягуємо користувача з контексту\n",[6124,14391,14392,14395,14397,14399,14401,14403,14405,14408,14410,14412,14415,14418],{"class":6126,"line":6249},[6124,14393,14394],{"class":9667},"    user",[6124,14396,9671],{"class":6479},[6124,14398,9806],{"class":9667},[6124,14400,5787],{"class":6479},[6124,14402,12291],{"class":9578},[6124,14404,10167],{"class":6479},[6124,14406,14407],{"class":9578},"Value",[6124,14409,9704],{"class":6479},[6124,14411,14303],{"class":6503},[6124,14413,14414],{"class":6479},").(*",[6124,14416,14417],{"class":9605},"User",[6124,14419,9647],{"class":6479},[6124,14421,14422],{"class":6126,"line":6255},[6124,14423,10356],{"class":6479},[6124,14425,14426,14429,14431,14434,14436,14438,14440,14443],{"class":6126,"line":6261},[6124,14427,14428],{"class":9667},"    orders",[6124,14430,9671],{"class":6479},[6124,14432,14433],{"class":9578},"getOrdersForUser",[6124,14435,9704],{"class":6479},[6124,14437,14308],{"class":9667},[6124,14439,5787],{"class":6479},[6124,14441,14442],{"class":9667},"ID",[6124,14444,9647],{"class":6479},[6124,14446,14447],{"class":6126,"line":6267},[6124,14448,10356],{"class":6479},[6124,14450,14451,14453,14455,14457,14459,14461,14463,14465,14467,14469],{"class":6126,"line":6272},[6124,14452,9996],{"class":9667},[6124,14454,5787],{"class":6479},[6124,14456,10189],{"class":9578},[6124,14458,10167],{"class":6479},[6124,14460,10194],{"class":9578},[6124,14462,9704],{"class":6479},[6124,14464,10199],{"class":6503},[6124,14466,5259],{"class":6479},[6124,14468,10204],{"class":6503},[6124,14470,9647],{"class":6479},[6124,14472,14473,14475,14477,14479,14481,14483,14485,14487,14489,14492],{"class":6126,"line":6278},[6124,14474,10059],{"class":9667},[6124,14476,5787],{"class":6479},[6124,14478,10064],{"class":9578},[6124,14480,9704],{"class":6479},[6124,14482,9967],{"class":9667},[6124,14484,5407],{"class":6479},[6124,14486,10073],{"class":9578},[6124,14488,9704],{"class":6479},[6124,14490,14491],{"class":9667},"orders",[6124,14493,9647],{"class":6479},[6124,14495,14496],{"class":6126,"line":6284},[6124,14497,6167],{"class":6479},[6124,14499,14500],{"class":6126,"line":6290},[6124,14501,6149],{"emptyLinePlaceholder":6148},[6124,14503,14504],{"class":6126,"line":6296},[6124,14505,14506],{"class":9691},"\u002F\u002F Використання\n",[6124,14508,14509,14511,14513,14515,14517,14520,14522,14524,14526,14528,14530,14532,14534],{"class":6126,"line":6301},[6124,14510,9806],{"class":9667},[6124,14512,5787],{"class":6479},[6124,14514,9792],{"class":9578},[6124,14516,9704],{"class":6479},[6124,14518,14519],{"class":6503},"\"\u002Fusers\u002F{userID}\"",[6124,14521,5259],{"class":6479},[6124,14523,9656],{"class":6483},[6124,14525,9704],{"class":6479},[6124,14527,9806],{"class":9667},[6124,14529,9809],{"class":9605},[6124,14531,5787],{"class":6479},[6124,14533,9814],{"class":9605},[6124,14535,9817],{"class":6479},[6124,14537,14538,14540,14542,14544,14546,14549,14551],{"class":6126,"line":6307},[6124,14539,9668],{"class":9667},[6124,14541,5787],{"class":6479},[6124,14543,9701],{"class":9578},[6124,14545,9704],{"class":6479},[6124,14547,14548],{"class":9667},"userMiddleware",[6124,14550,7173],{"class":6479},[6124,14552,14553],{"class":9691},"\u002F\u002F Застосовується до всіх маршрутів нижче\n",[6124,14555,14556,14558,14560,14562,14564,14566,14568,14571],{"class":6126,"line":6313},[6124,14557,9668],{"class":9667},[6124,14559,5787],{"class":6479},[6124,14561,9751],{"class":9578},[6124,14563,9704],{"class":6479},[6124,14565,9831],{"class":6503},[6124,14567,5259],{"class":6479},[6124,14569,14570],{"class":9667},"getUserOrdersHandler",[6124,14572,9647],{"class":6479},[6124,14574,14575,14577,14579,14581,14583,14586,14588,14591],{"class":6126,"line":6319},[6124,14576,9668],{"class":9667},[6124,14578,5787],{"class":6479},[6124,14580,9751],{"class":9578},[6124,14582,9704],{"class":6479},[6124,14584,14585],{"class":6503},"\"\u002Fprofile\"",[6124,14587,5259],{"class":6479},[6124,14589,14590],{"class":9667},"getUserProfileHandler",[6124,14592,9647],{"class":6479},[6124,14594,14595],{"class":6126,"line":6324},[6124,14596,10101],{"class":6479},[5587,14598,14599,14605],{},[5379,14600,14601,14604],{},[5205,14602,14603],{},"Типобезпечні контекстні ключі:"," Замість рядків використовуйте типізовані ключі:",[5530,14606,14608],{"className":9594,"code":14607,"language":9579,"meta":5538,"style":5538},"type contextKey string\n\nconst userKey contextKey = \"user\"\n\n\u002F\u002F Встановлення\nctx := context.WithValue(r.Context(), userKey, user)\n\n\u002F\u002F Отримання\nuser, ok := r.Context().Value(userKey).(*User)\nif !ok {\n    \u002F\u002F Обробка помилки\n}\n",[5288,14609,14610,14621,14625,14642,14646,14651,14682,14686,14691,14722,14733,14738],{"__ignoreMap":5538},[6124,14611,14612,14615,14618],{"class":6126,"line":6127},[6124,14613,14614],{"class":6483},"type",[6124,14616,14617],{"class":9605}," contextKey",[6124,14619,14620],{"class":9605}," string\n",[6124,14622,14623],{"class":6126,"line":6133},[6124,14624,6149],{"emptyLinePlaceholder":6148},[6124,14626,14627,14630,14634,14636,14639],{"class":6126,"line":6139},[6124,14628,14629],{"class":6483},"const",[6124,14631,14633],{"class":14632},"s-QsJ"," userKey",[6124,14635,14617],{"class":9605},[6124,14637,14638],{"class":6479}," = ",[6124,14640,14641],{"class":6503},"\"user\"\n",[6124,14643,14644],{"class":6126,"line":6145},[6124,14645,6149],{"emptyLinePlaceholder":6148},[6124,14647,14648],{"class":6126,"line":6152},[6124,14649,14650],{"class":9691},"\u002F\u002F Встановлення\n",[6124,14652,14653,14655,14657,14659,14661,14663,14665,14667,14669,14671,14673,14676,14678,14680],{"class":6126,"line":6158},[6124,14654,12329],{"class":9667},[6124,14656,9671],{"class":6479},[6124,14658,5349],{"class":9667},[6124,14660,5787],{"class":6479},[6124,14662,12282],{"class":9578},[6124,14664,9704],{"class":6479},[6124,14666,9806],{"class":9667},[6124,14668,5787],{"class":6479},[6124,14670,12291],{"class":9578},[6124,14672,12294],{"class":6479},[6124,14674,14675],{"class":9667},"userKey",[6124,14677,5259],{"class":6479},[6124,14679,14308],{"class":9667},[6124,14681,9647],{"class":6479},[6124,14683,14684],{"class":6126,"line":6164},[6124,14685,6149],{"emptyLinePlaceholder":6148},[6124,14687,14688],{"class":6126,"line":6170},[6124,14689,14690],{"class":9691},"\u002F\u002F Отримання\n",[6124,14692,14693,14695,14697,14700,14702,14704,14706,14708,14710,14712,14714,14716,14718,14720],{"class":6126,"line":6175},[6124,14694,14308],{"class":9667},[6124,14696,5259],{"class":6479},[6124,14698,14699],{"class":9667},"ok",[6124,14701,9671],{"class":6479},[6124,14703,9806],{"class":9667},[6124,14705,5787],{"class":6479},[6124,14707,12291],{"class":9578},[6124,14709,10167],{"class":6479},[6124,14711,14407],{"class":9578},[6124,14713,9704],{"class":6479},[6124,14715,14675],{"class":9667},[6124,14717,14414],{"class":6479},[6124,14719,14417],{"class":9605},[6124,14721,9647],{"class":6479},[6124,14723,14724,14726,14729,14731],{"class":6126,"line":6181},[6124,14725,11257],{"class":6476},[6124,14727,14728],{"class":6479}," !",[6124,14730,14699],{"class":9667},[6124,14732,10516],{"class":6479},[6124,14734,14735],{"class":6126,"line":6187},[6124,14736,14737],{"class":9691},"    \u002F\u002F Обробка помилки\n",[6124,14739,14740],{"class":6126,"line":6193},[6124,14741,6167],{"class":6479},[5374,14743,14745],{"id":14744},"regexp-паттерни-для-параметрів-розширена-валідація","Regexp-паттерни для параметрів (розширена валідація)",[5379,14747,14748],{},"Chi підтримує регулярні вирази для валідації параметрів шляху:",[5530,14750,14752],{"className":9594,"code":14751,"language":9579,"meta":5538,"style":5538},"\u002F\u002F Тільки числові ID\nr.Get(\"\u002Forders\u002F{orderID:[0-9]+}\", getOrderHandler)\n\n\u002F\u002F UUID формат\nr.Get(\"\u002Fusers\u002F{userID:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}\", getUserHandler)\n\n\u002F\u002F Дати у форматі YYYY-MM-DD\nr.Get(\"\u002Freports\u002F{date:[0-9]{4}-[0-9]{2}-[0-9]{2}}\", getReportHandler)\n\n\u002F\u002F Slug (латинські літери, цифри, дефіси)\nr.Get(\"\u002Fposts\u002F{slug:[a-z0-9-]+}\", getPostHandler)\n",[5288,14753,14754,14759,14778,14782,14787,14807,14811,14816,14836,14840,14845],{"__ignoreMap":5538},[6124,14755,14756],{"class":6126,"line":6127},[6124,14757,14758],{"class":9691},"\u002F\u002F Тільки числові ID\n",[6124,14760,14761,14763,14765,14767,14769,14772,14774,14776],{"class":6126,"line":6133},[6124,14762,9806],{"class":9667},[6124,14764,5787],{"class":6479},[6124,14766,9751],{"class":9578},[6124,14768,9704],{"class":6479},[6124,14770,14771],{"class":6503},"\"\u002Forders\u002F{orderID:[0-9]+}\"",[6124,14773,5259],{"class":6479},[6124,14775,9876],{"class":9667},[6124,14777,9647],{"class":6479},[6124,14779,14780],{"class":6126,"line":6139},[6124,14781,6149],{"emptyLinePlaceholder":6148},[6124,14783,14784],{"class":6126,"line":6145},[6124,14785,14786],{"class":9691},"\u002F\u002F UUID формат\n",[6124,14788,14789,14791,14793,14795,14797,14800,14802,14805],{"class":6126,"line":6152},[6124,14790,9806],{"class":9667},[6124,14792,5787],{"class":6479},[6124,14794,9751],{"class":9578},[6124,14796,9704],{"class":6479},[6124,14798,14799],{"class":6503},"\"\u002Fusers\u002F{userID:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}\"",[6124,14801,5259],{"class":6479},[6124,14803,14804],{"class":9667},"getUserHandler",[6124,14806,9647],{"class":6479},[6124,14808,14809],{"class":6126,"line":6158},[6124,14810,6149],{"emptyLinePlaceholder":6148},[6124,14812,14813],{"class":6126,"line":6164},[6124,14814,14815],{"class":9691},"\u002F\u002F Дати у форматі YYYY-MM-DD\n",[6124,14817,14818,14820,14822,14824,14826,14829,14831,14834],{"class":6126,"line":6170},[6124,14819,9806],{"class":9667},[6124,14821,5787],{"class":6479},[6124,14823,9751],{"class":9578},[6124,14825,9704],{"class":6479},[6124,14827,14828],{"class":6503},"\"\u002Freports\u002F{date:[0-9]{4}-[0-9]{2}-[0-9]{2}}\"",[6124,14830,5259],{"class":6479},[6124,14832,14833],{"class":9667},"getReportHandler",[6124,14835,9647],{"class":6479},[6124,14837,14838],{"class":6126,"line":6175},[6124,14839,6149],{"emptyLinePlaceholder":6148},[6124,14841,14842],{"class":6126,"line":6181},[6124,14843,14844],{"class":9691},"\u002F\u002F Slug (латинські літери, цифри, дефіси)\n",[6124,14846,14847,14849,14851,14853,14855,14858,14860,14863],{"class":6126,"line":6187},[6124,14848,9806],{"class":9667},[6124,14850,5787],{"class":6479},[6124,14852,9751],{"class":9578},[6124,14854,9704],{"class":6479},[6124,14856,14857],{"class":6503},"\"\u002Fposts\u002F{slug:[a-z0-9-]+}\"",[6124,14859,5259],{"class":6479},[6124,14861,14862],{"class":9667},"getPostHandler",[6124,14864,9647],{"class":6479},[5379,14866,14867],{},"Якщо параметр не відповідає regex, Chi поверне 404.",[5374,14869,14871],{"id":14870},"практичний-приклад-повний-сервер-з-chi","Практичний приклад: повний сервер з Chi",[5530,14873,14875],{"className":9594,"code":14874,"language":9579,"meta":5538,"style":5538},"package main\n\nimport (\n    \"context\"\n    \"encoding\u002Fjson\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"os\u002Fsignal\"\n    \"syscall\"\n    \"time\"\n\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\u002Fmiddleware\"\n)\n\nfunc main() {\n    r := chi.NewRouter()\n\n    \u002F\u002F Глобальні middleware\n    r.Use(middleware.RequestID)\n    r.Use(middleware.RealIP)\n    r.Use(middleware.Logger)\n    r.Use(middleware.Recoverer)\n    r.Use(middleware.Timeout(60 * time.Second))\n    r.Use(middleware.Compress(5))\n\n    \u002F\u002F Health check\n    r.Get(\"\u002Fhealth\", func(w http.ResponseWriter, r *http.Request) {\n        json.NewEncoder(w).Encode(map[string]string{\n            \"status\": \"healthy\",\n            \"time\":   time.Now().Format(time.RFC3339),\n        })\n    })\n\n    \u002F\u002F API v1\n    r.Route(\"\u002Fapi\u002Fv1\", func(r chi.Router) {\n        r.Use(corsMiddleware)\n        \n        \u002F\u002F Публічні маршрути\n        r.Group(func(r chi.Router) {\n            r.Post(\"\u002Fauth\u002Flogin\", loginHandler)\n            r.Post(\"\u002Fauth\u002Fregister\", registerHandler)\n        })\n\n        \u002F\u002F Захищені маршрути\n        r.Group(func(r chi.Router) {\n            r.Use(authMiddleware)\n            \n            r.Route(\"\u002Forders\", func(r chi.Router) {\n                r.Get(\"\u002F\", listOrdersHandler)\n                r.Post(\"\u002F\", createOrderHandler)\n                \n                r.Route(\"\u002F{orderID:[0-9]+}\", func(r chi.Router) {\n                    r.Get(\"\u002F\", getOrderHandler)\n                    r.Put(\"\u002F\", updateOrderHandler)\n                    r.Delete(\"\u002F\", deleteOrderHandler)\n                })\n            })\n        })\n    })\n\n    \u002F\u002F Користувацькі обробники помилок\n    r.NotFound(notFoundHandler)\n    r.MethodNotAllowed(methodNotAllowedHandler)\n\n    \u002F\u002F Graceful Shutdown\n    srv := &http.Server{\n        Addr:         \":8080\",\n        Handler:      r,\n        ReadTimeout:  15 * time.Second,\n        WriteTimeout: 15 * time.Second,\n        IdleTimeout:  60 * time.Second,\n    }\n\n    go func() {\n        log.Printf(\"🚀 Server starting on %s\", srv.Addr)\n        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n            log.Fatalf(\"Server error: %v\", err)\n        }\n    }()\n\n    \u002F\u002F Очікуємо сигнал завершення\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n    \u003C-quit\n\n    log.Println(\"⏳ Shutting down server...\")\n    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n\n    if err := srv.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Server forced to shutdown: %v\", err)\n    }\n\n    log.Println(\"✅ Server stopped gracefully\")\n}\n\n\u002F\u002F Заглушки для обробників (реалізуйте власну логіку)\nfunc loginHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\nfunc registerHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\nfunc listOrdersHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\nfunc createOrderHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\nfunc getOrderHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\nfunc updateOrderHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\nfunc deleteOrderHandler(w http.ResponseWriter, r *http.Request) { \u002F* ... *\u002F }\n\nfunc notFoundHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusNotFound)\n    json.NewEncoder(w).Encode(map[string]string{\n        \"error\": \"Route not found\",\n        \"path\":  r.URL.Path,\n    })\n}\n\nfunc methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusMethodNotAllowed)\n    json.NewEncoder(w).Encode(map[string]string{\n        \"error\": \"Method not allowed\",\n    })\n}\n",[5288,14876,14877,14883,14887,14893,14898,14902,14907,14911,14916,14921,14926,14931,14935,14939,14943,14947,14951,14959,14973,14977,14982,15000,15018,15036,15054,15084,15106,15110,15115,15155,15186,15197,15227,15232,15236,15240,15245,15273,15287,15291,15296,15321,15342,15362,15366,15370,15375,15399,15413,15418,15446,15465,15483,15488,15517,15536,15554,15572,15577,15582,15586,15590,15594,15599,15614,15629,15633,15638,15655,15667,15678,15698,15717,15736,15740,15744,15754,15783,15822,15848,15852,15857,15861,15866,15895,15931,15939,15943,15959,16002,16011,16015,16044,16067,16071,16075,16090,16095,16100,16106,16145,16181,16216,16251,16286,16321,16356,16361,16393,16416,16435,16466,16477,16496,16501,16506,16511,16543,16566,16585,16616,16628,16633],{"__ignoreMap":5538},[6124,14878,14879,14881],{"class":6126,"line":6127},[6124,14880,9602],{"class":6483},[6124,14882,9606],{"class":9605},[6124,14884,14885],{"class":6126,"line":6133},[6124,14886,6149],{"emptyLinePlaceholder":6148},[6124,14888,14889,14891],{"class":6126,"line":6139},[6124,14890,9615],{"class":6476},[6124,14892,9618],{"class":6479},[6124,14894,14895],{"class":6126,"line":6145},[6124,14896,14897],{"class":6503},"    \"context\"\n",[6124,14899,14900],{"class":6126,"line":6152},[6124,14901,9623],{"class":6503},[6124,14903,14904],{"class":6126,"line":6158},[6124,14905,14906],{"class":6503},"    \"log\"\n",[6124,14908,14909],{"class":6126,"line":6164},[6124,14910,9628],{"class":6503},[6124,14912,14913],{"class":6126,"line":6170},[6124,14914,14915],{"class":6503},"    \"os\"\n",[6124,14917,14918],{"class":6126,"line":6175},[6124,14919,14920],{"class":6503},"    \"os\u002Fsignal\"\n",[6124,14922,14923],{"class":6126,"line":6181},[6124,14924,14925],{"class":6503},"    \"syscall\"\n",[6124,14927,14928],{"class":6126,"line":6187},[6124,14929,14930],{"class":6503},"    \"time\"\n",[6124,14932,14933],{"class":6126,"line":6193},[6124,14934,6149],{"emptyLinePlaceholder":6148},[6124,14936,14937],{"class":6126,"line":6199},[6124,14938,9637],{"class":6503},[6124,14940,14941],{"class":6126,"line":6204},[6124,14942,9642],{"class":6503},[6124,14944,14945],{"class":6126,"line":6209},[6124,14946,9647],{"class":6479},[6124,14948,14949],{"class":6126,"line":6215},[6124,14950,6149],{"emptyLinePlaceholder":6148},[6124,14952,14953,14955,14957],{"class":6126,"line":6221},[6124,14954,9656],{"class":6483},[6124,14956,9659],{"class":9578},[6124,14958,9662],{"class":6479},[6124,14960,14961,14963,14965,14967,14969,14971],{"class":6126,"line":6227},[6124,14962,9668],{"class":9667},[6124,14964,9671],{"class":6479},[6124,14966,9674],{"class":9667},[6124,14968,5787],{"class":6479},[6124,14970,9679],{"class":9578},[6124,14972,9682],{"class":6479},[6124,14974,14975],{"class":6126,"line":6232},[6124,14976,6149],{"emptyLinePlaceholder":6148},[6124,14978,14979],{"class":6126,"line":6237},[6124,14980,14981],{"class":9691},"    \u002F\u002F Глобальні middleware\n",[6124,14983,14984,14986,14988,14990,14992,14994,14996,14998],{"class":6126,"line":6243},[6124,14985,9668],{"class":9667},[6124,14987,5787],{"class":6479},[6124,14989,9701],{"class":9578},[6124,14991,9704],{"class":6479},[6124,14993,9707],{"class":9667},[6124,14995,5787],{"class":6479},[6124,14997,12464],{"class":9667},[6124,14999,9647],{"class":6479},[6124,15001,15002,15004,15006,15008,15010,15012,15014,15016],{"class":6126,"line":6249},[6124,15003,9668],{"class":9667},[6124,15005,5787],{"class":6479},[6124,15007,9701],{"class":9578},[6124,15009,9704],{"class":6479},[6124,15011,9707],{"class":9667},[6124,15013,5787],{"class":6479},[6124,15015,12492],{"class":9667},[6124,15017,9647],{"class":6479},[6124,15019,15020,15022,15024,15026,15028,15030,15032,15034],{"class":6126,"line":6255},[6124,15021,9668],{"class":9667},[6124,15023,5787],{"class":6479},[6124,15025,9701],{"class":9578},[6124,15027,9704],{"class":6479},[6124,15029,9707],{"class":9667},[6124,15031,5787],{"class":6479},[6124,15033,9712],{"class":9667},[6124,15035,9647],{"class":6479},[6124,15037,15038,15040,15042,15044,15046,15048,15050,15052],{"class":6126,"line":6261},[6124,15039,9668],{"class":9667},[6124,15041,5787],{"class":6479},[6124,15043,9701],{"class":9578},[6124,15045,9704],{"class":6479},[6124,15047,9707],{"class":9667},[6124,15049,5787],{"class":6479},[6124,15051,9731],{"class":9667},[6124,15053,9647],{"class":6479},[6124,15055,15056,15058,15060,15062,15064,15066,15068,15070,15072,15074,15076,15078,15080,15082],{"class":6126,"line":6267},[6124,15057,9668],{"class":9667},[6124,15059,5787],{"class":6479},[6124,15061,9701],{"class":9578},[6124,15063,9704],{"class":6479},[6124,15065,9707],{"class":9667},[6124,15067,5787],{"class":6479},[6124,15069,12520],{"class":9578},[6124,15071,9704],{"class":6479},[6124,15073,12525],{"class":6490},[6124,15075,12528],{"class":6479},[6124,15077,11641],{"class":9667},[6124,15079,5787],{"class":6479},[6124,15081,12535],{"class":9667},[6124,15083,10015],{"class":6479},[6124,15085,15086,15088,15090,15092,15094,15096,15098,15100,15102,15104],{"class":6126,"line":6272},[6124,15087,9668],{"class":9667},[6124,15089,5787],{"class":6479},[6124,15091,9701],{"class":9578},[6124,15093,9704],{"class":6479},[6124,15095,9707],{"class":9667},[6124,15097,5787],{"class":6479},[6124,15099,12596],{"class":9578},[6124,15101,9704],{"class":6479},[6124,15103,12601],{"class":6490},[6124,15105,10015],{"class":6479},[6124,15107,15108],{"class":6126,"line":6278},[6124,15109,6149],{"emptyLinePlaceholder":6148},[6124,15111,15112],{"class":6126,"line":6284},[6124,15113,15114],{"class":9691},"    \u002F\u002F Health check\n",[6124,15116,15117,15119,15121,15123,15125,15127,15129,15131,15133,15135,15137,15139,15141,15143,15145,15147,15149,15151,15153],{"class":6126,"line":6290},[6124,15118,9668],{"class":9667},[6124,15120,5787],{"class":6479},[6124,15122,9751],{"class":9578},[6124,15124,9704],{"class":6479},[6124,15126,9776],{"class":6503},[6124,15128,5259],{"class":6479},[6124,15130,9656],{"class":6483},[6124,15132,9704],{"class":6479},[6124,15134,9967],{"class":9667},[6124,15136,9970],{"class":9605},[6124,15138,5787],{"class":6479},[6124,15140,9975],{"class":9605},[6124,15142,5259],{"class":6479},[6124,15144,9806],{"class":9667},[6124,15146,9982],{"class":6479},[6124,15148,6469],{"class":9605},[6124,15150,5787],{"class":6479},[6124,15152,9989],{"class":9605},[6124,15154,9817],{"class":6479},[6124,15156,15157,15160,15162,15164,15166,15168,15170,15172,15174,15176,15178,15180,15182,15184],{"class":6126,"line":6296},[6124,15158,15159],{"class":9667},"        json",[6124,15161,5787],{"class":6479},[6124,15163,10064],{"class":9578},[6124,15165,9704],{"class":6479},[6124,15167,9967],{"class":9667},[6124,15169,5407],{"class":6479},[6124,15171,10073],{"class":9578},[6124,15173,9704],{"class":6479},[6124,15175,10078],{"class":6483},[6124,15177,10081],{"class":6479},[6124,15179,10084],{"class":9605},[6124,15181,10087],{"class":6479},[6124,15183,10084],{"class":9605},[6124,15185,6543],{"class":6479},[6124,15187,15188,15191,15193,15195],{"class":6126,"line":6301},[6124,15189,15190],{"class":6503},"            \"status\"",[6124,15192,6552],{"class":6479},[6124,15194,10098],{"class":6503},[6124,15196,6558],{"class":6479},[6124,15198,15199,15202,15205,15207,15209,15211,15213,15216,15218,15220,15222,15225],{"class":6126,"line":6307},[6124,15200,15201],{"class":6503},"            \"time\"",[6124,15203,15204],{"class":6479},":   ",[6124,15206,11641],{"class":9667},[6124,15208,5787],{"class":6479},[6124,15210,11646],{"class":9578},[6124,15212,10167],{"class":6479},[6124,15214,15215],{"class":9578},"Format",[6124,15217,9704],{"class":6479},[6124,15219,11641],{"class":9667},[6124,15221,5787],{"class":6479},[6124,15223,15224],{"class":9667},"RFC3339",[6124,15226,14052],{"class":6479},[6124,15228,15229],{"class":6126,"line":6313},[6124,15230,15231],{"class":6479},"        })\n",[6124,15233,15234],{"class":6126,"line":6319},[6124,15235,9922],{"class":6479},[6124,15237,15238],{"class":6126,"line":6324},[6124,15239,6149],{"emptyLinePlaceholder":6148},[6124,15241,15242],{"class":6126,"line":8100},[6124,15243,15244],{"class":9691},"    \u002F\u002F API v1\n",[6124,15246,15247,15249,15251,15253,15255,15257,15259,15261,15263,15265,15267,15269,15271],{"class":6126,"line":8106},[6124,15248,9668],{"class":9667},[6124,15250,5787],{"class":6479},[6124,15252,9792],{"class":9578},[6124,15254,9704],{"class":6479},[6124,15256,13258],{"class":6503},[6124,15258,5259],{"class":6479},[6124,15260,9656],{"class":6483},[6124,15262,9704],{"class":6479},[6124,15264,9806],{"class":9667},[6124,15266,9809],{"class":9605},[6124,15268,5787],{"class":6479},[6124,15270,9814],{"class":9605},[6124,15272,9817],{"class":6479},[6124,15274,15275,15277,15279,15281,15283,15285],{"class":6126,"line":8112},[6124,15276,9822],{"class":9667},[6124,15278,5787],{"class":6479},[6124,15280,9701],{"class":9578},[6124,15282,9704],{"class":6479},[6124,15284,11359],{"class":9667},[6124,15286,9647],{"class":6479},[6124,15288,15289],{"class":6126,"line":8117},[6124,15290,11653],{"class":6479},[6124,15292,15293],{"class":6126,"line":8123},[6124,15294,15295],{"class":9691},"        \u002F\u002F Публічні маршрути\n",[6124,15297,15298,15300,15302,15305,15307,15309,15311,15313,15315,15317,15319],{"class":6126,"line":8129},[6124,15299,9822],{"class":9667},[6124,15301,5787],{"class":6479},[6124,15303,15304],{"class":9578},"Group",[6124,15306,9704],{"class":6479},[6124,15308,9656],{"class":6483},[6124,15310,9704],{"class":6479},[6124,15312,9806],{"class":9667},[6124,15314,9809],{"class":9605},[6124,15316,5787],{"class":6479},[6124,15318,9814],{"class":9605},[6124,15320,9817],{"class":6479},[6124,15322,15323,15326,15328,15330,15332,15335,15337,15340],{"class":6126,"line":8135},[6124,15324,15325],{"class":9667},"            r",[6124,15327,5787],{"class":6479},[6124,15329,9847],{"class":9578},[6124,15331,9704],{"class":6479},[6124,15333,15334],{"class":6503},"\"\u002Fauth\u002Flogin\"",[6124,15336,5259],{"class":6479},[6124,15338,15339],{"class":9667},"loginHandler",[6124,15341,9647],{"class":6479},[6124,15343,15344,15346,15348,15350,15352,15355,15357,15360],{"class":6126,"line":8141},[6124,15345,15325],{"class":9667},[6124,15347,5787],{"class":6479},[6124,15349,9847],{"class":9578},[6124,15351,9704],{"class":6479},[6124,15353,15354],{"class":6503},"\"\u002Fauth\u002Fregister\"",[6124,15356,5259],{"class":6479},[6124,15358,15359],{"class":9667},"registerHandler",[6124,15361,9647],{"class":6479},[6124,15363,15364],{"class":6126,"line":8146},[6124,15365,15231],{"class":6479},[6124,15367,15368],{"class":6126,"line":10209},[6124,15369,6149],{"emptyLinePlaceholder":6148},[6124,15371,15372],{"class":6126,"line":10242},[6124,15373,15374],{"class":9691},"        \u002F\u002F Захищені маршрути\n",[6124,15376,15377,15379,15381,15383,15385,15387,15389,15391,15393,15395,15397],{"class":6126,"line":10274},[6124,15378,9822],{"class":9667},[6124,15380,5787],{"class":6479},[6124,15382,15304],{"class":9578},[6124,15384,9704],{"class":6479},[6124,15386,9656],{"class":6483},[6124,15388,9704],{"class":6479},[6124,15390,9806],{"class":9667},[6124,15392,9809],{"class":9605},[6124,15394,5787],{"class":6479},[6124,15396,9814],{"class":9605},[6124,15398,9817],{"class":6479},[6124,15400,15401,15403,15405,15407,15409,15411],{"class":6126,"line":10279},[6124,15402,15325],{"class":9667},[6124,15404,5787],{"class":6479},[6124,15406,9701],{"class":9578},[6124,15408,9704],{"class":6479},[6124,15410,11374],{"class":9667},[6124,15412,9647],{"class":6479},[6124,15414,15415],{"class":6126,"line":10284},[6124,15416,15417],{"class":6479},"            \n",[6124,15419,15420,15422,15424,15426,15428,15430,15432,15434,15436,15438,15440,15442,15444],{"class":6126,"line":10289},[6124,15421,15325],{"class":9667},[6124,15423,5787],{"class":6479},[6124,15425,9792],{"class":9578},[6124,15427,9704],{"class":6479},[6124,15429,9831],{"class":6503},[6124,15431,5259],{"class":6479},[6124,15433,9656],{"class":6483},[6124,15435,9704],{"class":6479},[6124,15437,9806],{"class":9667},[6124,15439,9809],{"class":9605},[6124,15441,5787],{"class":6479},[6124,15443,9814],{"class":9605},[6124,15445,9817],{"class":6479},[6124,15447,15448,15451,15453,15455,15457,15459,15461,15463],{"class":6126,"line":10321},[6124,15449,15450],{"class":9667},"                r",[6124,15452,5787],{"class":6479},[6124,15454,9751],{"class":9578},[6124,15456,9704],{"class":6479},[6124,15458,9756],{"class":6503},[6124,15460,5259],{"class":6479},[6124,15462,9836],{"class":9667},[6124,15464,9647],{"class":6479},[6124,15466,15467,15469,15471,15473,15475,15477,15479,15481],{"class":6126,"line":10327},[6124,15468,15450],{"class":9667},[6124,15470,5787],{"class":6479},[6124,15472,9847],{"class":9578},[6124,15474,9704],{"class":6479},[6124,15476,9756],{"class":6503},[6124,15478,5259],{"class":6479},[6124,15480,9856],{"class":9667},[6124,15482,9647],{"class":6479},[6124,15484,15485],{"class":6126,"line":10353},[6124,15486,15487],{"class":6479},"                \n",[6124,15489,15490,15492,15494,15496,15498,15501,15503,15505,15507,15509,15511,15513,15515],{"class":6126,"line":10359},[6124,15491,15450],{"class":9667},[6124,15493,5787],{"class":6479},[6124,15495,9792],{"class":9578},[6124,15497,9704],{"class":6479},[6124,15499,15500],{"class":6503},"\"\u002F{orderID:[0-9]+}\"",[6124,15502,5259],{"class":6479},[6124,15504,9656],{"class":6483},[6124,15506,9704],{"class":6479},[6124,15508,9806],{"class":9667},[6124,15510,9809],{"class":9605},[6124,15512,5787],{"class":6479},[6124,15514,9814],{"class":9605},[6124,15516,9817],{"class":6479},[6124,15518,15519,15522,15524,15526,15528,15530,15532,15534],{"class":6126,"line":10365},[6124,15520,15521],{"class":9667},"                    r",[6124,15523,5787],{"class":6479},[6124,15525,9751],{"class":9578},[6124,15527,9704],{"class":6479},[6124,15529,9756],{"class":6503},[6124,15531,5259],{"class":6479},[6124,15533,9876],{"class":9667},[6124,15535,9647],{"class":6479},[6124,15537,15538,15540,15542,15544,15546,15548,15550,15552],{"class":6126,"line":10388},[6124,15539,15521],{"class":9667},[6124,15541,5787],{"class":6479},[6124,15543,9887],{"class":9578},[6124,15545,9704],{"class":6479},[6124,15547,9756],{"class":6503},[6124,15549,5259],{"class":6479},[6124,15551,9896],{"class":9667},[6124,15553,9647],{"class":6479},[6124,15555,15556,15558,15560,15562,15564,15566,15568,15570],{"class":6126,"line":10419},[6124,15557,15521],{"class":9667},[6124,15559,5787],{"class":6479},[6124,15561,8464],{"class":9578},[6124,15563,9704],{"class":6479},[6124,15565,9756],{"class":6503},[6124,15567,5259],{"class":6479},[6124,15569,9915],{"class":9667},[6124,15571,9647],{"class":6479},[6124,15573,15574],{"class":6126,"line":10433},[6124,15575,15576],{"class":6479},"                })\n",[6124,15578,15579],{"class":6126,"line":10445},[6124,15580,15581],{"class":6479},"            })\n",[6124,15583,15584],{"class":6126,"line":10457},[6124,15585,15231],{"class":6479},[6124,15587,15588],{"class":6126,"line":10462},[6124,15589,9922],{"class":6479},[6124,15591,15592],{"class":6126,"line":10467},[6124,15593,6149],{"emptyLinePlaceholder":6148},[6124,15595,15596],{"class":6126,"line":10472},[6124,15597,15598],{"class":9691},"    \u002F\u002F Користувацькі обробники помилок\n",[6124,15600,15601,15603,15605,15607,15609,15612],{"class":6126,"line":10504},[6124,15602,9668],{"class":9667},[6124,15604,5787],{"class":6479},[6124,15606,13731],{"class":9578},[6124,15608,9704],{"class":6479},[6124,15610,15611],{"class":9667},"notFoundHandler",[6124,15613,9647],{"class":6479},[6124,15615,15616,15618,15620,15622,15624,15627],{"class":6126,"line":10519},[6124,15617,9668],{"class":9667},[6124,15619,5787],{"class":6479},[6124,15621,13902],{"class":9578},[6124,15623,9704],{"class":6479},[6124,15625,15626],{"class":9667},"methodNotAllowedHandler",[6124,15628,9647],{"class":6479},[6124,15630,15631],{"class":6126,"line":10531},[6124,15632,6149],{"emptyLinePlaceholder":6148},[6124,15634,15635],{"class":6126,"line":10542},[6124,15636,15637],{"class":9691},"    \u002F\u002F Graceful Shutdown\n",[6124,15639,15640,15643,15646,15648,15650,15653],{"class":6126,"line":10548},[6124,15641,15642],{"class":9667},"    srv",[6124,15644,15645],{"class":6479}," := &",[6124,15647,6469],{"class":9605},[6124,15649,5787],{"class":6479},[6124,15651,15652],{"class":9605},"Server",[6124,15654,6543],{"class":6479},[6124,15656,15657,15660,15663,15665],{"class":6126,"line":10601},[6124,15658,15659],{"class":9667},"        Addr",[6124,15661,15662],{"class":6479},":         ",[6124,15664,9941],{"class":6503},[6124,15666,6558],{"class":6479},[6124,15668,15669,15672,15674,15676],{"class":6126,"line":10632},[6124,15670,15671],{"class":9667},"        Handler",[6124,15673,10754],{"class":6479},[6124,15675,9806],{"class":9667},[6124,15677,6558],{"class":6479},[6124,15679,15680,15683,15685,15688,15690,15692,15694,15696],{"class":6126,"line":10638},[6124,15681,15682],{"class":9667},"        ReadTimeout",[6124,15684,10783],{"class":6479},[6124,15686,15687],{"class":6490},"15",[6124,15689,12528],{"class":6479},[6124,15691,11641],{"class":9667},[6124,15693,5787],{"class":6479},[6124,15695,12535],{"class":9667},[6124,15697,6558],{"class":6479},[6124,15699,15700,15703,15705,15707,15709,15711,15713,15715],{"class":6126,"line":10643},[6124,15701,15702],{"class":9667},"        WriteTimeout",[6124,15704,6552],{"class":6479},[6124,15706,15687],{"class":6490},[6124,15708,12528],{"class":6479},[6124,15710,11641],{"class":9667},[6124,15712,5787],{"class":6479},[6124,15714,12535],{"class":9667},[6124,15716,6558],{"class":6479},[6124,15718,15719,15722,15724,15726,15728,15730,15732,15734],{"class":6126,"line":10663},[6124,15720,15721],{"class":9667},"        IdleTimeout",[6124,15723,10783],{"class":6479},[6124,15725,12525],{"class":6490},[6124,15727,12528],{"class":6479},[6124,15729,11641],{"class":9667},[6124,15731,5787],{"class":6479},[6124,15733,12535],{"class":9667},[6124,15735,6558],{"class":6479},[6124,15737,15738],{"class":6126,"line":10668},[6124,15739,10545],{"class":6479},[6124,15741,15742],{"class":6126,"line":10674},[6124,15743,6149],{"emptyLinePlaceholder":6148},[6124,15745,15746,15749,15752],{"class":6126,"line":10695},[6124,15747,15748],{"class":6476},"    go",[6124,15750,15751],{"class":6483}," func",[6124,15753,9662],{"class":6479},[6124,15755,15756,15758,15760,15762,15764,15767,15769,15771,15773,15776,15778,15781],{"class":6126,"line":10718},[6124,15757,11713],{"class":9667},[6124,15759,5787],{"class":6479},[6124,15761,11718],{"class":9578},[6124,15763,9704],{"class":6479},[6124,15765,15766],{"class":6503},"\"🚀 Server starting on ",[6124,15768,11179],{"class":9667},[6124,15770,11182],{"class":6503},[6124,15772,5259],{"class":6479},[6124,15774,15775],{"class":9667},"srv",[6124,15777,5787],{"class":6479},[6124,15779,15780],{"class":9667},"Addr",[6124,15782,9647],{"class":6479},[6124,15784,15785,15787,15789,15791,15793,15795,15797,15800,15802,15804,15806,15809,15811,15813,15815,15817,15820],{"class":6126,"line":10749},[6124,15786,11955],{"class":6476},[6124,15788,10554],{"class":9667},[6124,15790,9671],{"class":6479},[6124,15792,15775],{"class":9667},[6124,15794,5787],{"class":6479},[6124,15796,9936],{"class":9578},[6124,15798,15799],{"class":6479},"(); ",[6124,15801,10590],{"class":9667},[6124,15803,10593],{"class":6479},[6124,15805,10596],{"class":6483},[6124,15807,15808],{"class":6479}," && ",[6124,15810,10590],{"class":9667},[6124,15812,10593],{"class":6479},[6124,15814,6469],{"class":9667},[6124,15816,5787],{"class":6479},[6124,15818,15819],{"class":9667},"ErrServerClosed",[6124,15821,10516],{"class":6479},[6124,15823,15824,15827,15829,15832,15834,15837,15840,15842,15844,15846],{"class":6126,"line":10761},[6124,15825,15826],{"class":9667},"            log",[6124,15828,5787],{"class":6479},[6124,15830,15831],{"class":9578},"Fatalf",[6124,15833,9704],{"class":6479},[6124,15835,15836],{"class":6503},"\"Server error: ",[6124,15838,15839],{"class":9667},"%v",[6124,15841,11182],{"class":6503},[6124,15843,5259],{"class":6479},[6124,15845,10590],{"class":9667},[6124,15847,9647],{"class":6479},[6124,15849,15850],{"class":6126,"line":10778},[6124,15851,12002],{"class":6479},[6124,15853,15854],{"class":6126,"line":10795},[6124,15855,15856],{"class":6479},"    }()\n",[6124,15858,15859],{"class":6126,"line":10806},[6124,15860,6149],{"emptyLinePlaceholder":6148},[6124,15862,15863],{"class":6126,"line":10811},[6124,15864,15865],{"class":9691},"    \u002F\u002F Очікуємо сигнал завершення\n",[6124,15867,15868,15871,15873,15876,15878,15881,15884,15886,15889,15891,15893],{"class":6126,"line":10816},[6124,15869,15870],{"class":9667},"    quit",[6124,15872,9671],{"class":6479},[6124,15874,15875],{"class":9578},"make",[6124,15877,9704],{"class":6479},[6124,15879,15880],{"class":6483},"chan",[6124,15882,15883],{"class":9605}," os",[6124,15885,5787],{"class":6479},[6124,15887,15888],{"class":9605},"Signal",[6124,15890,5259],{"class":6479},[6124,15892,8576],{"class":6490},[6124,15894,9647],{"class":6479},[6124,15896,15897,15900,15902,15905,15907,15910,15912,15915,15917,15920,15922,15924,15926,15929],{"class":6126,"line":10821},[6124,15898,15899],{"class":9667},"    signal",[6124,15901,5787],{"class":6479},[6124,15903,15904],{"class":9578},"Notify",[6124,15906,9704],{"class":6479},[6124,15908,15909],{"class":9667},"quit",[6124,15911,5259],{"class":6479},[6124,15913,15914],{"class":9667},"syscall",[6124,15916,5787],{"class":6479},[6124,15918,15919],{"class":9667},"SIGINT",[6124,15921,5259],{"class":6479},[6124,15923,15914],{"class":9667},[6124,15925,5787],{"class":6479},[6124,15927,15928],{"class":9667},"SIGTERM",[6124,15930,9647],{"class":6479},[6124,15932,15933,15936],{"class":6126,"line":10853},[6124,15934,15935],{"class":6479},"    \u003C-",[6124,15937,15938],{"class":9667},"quit\n",[6124,15940,15941],{"class":6126,"line":10876},[6124,15942,6149],{"emptyLinePlaceholder":6148},[6124,15944,15945,15947,15949,15952,15954,15957],{"class":6126,"line":10882},[6124,15946,12806],{"class":9667},[6124,15948,5787],{"class":6479},[6124,15950,15951],{"class":9578},"Println",[6124,15953,9704],{"class":6479},[6124,15955,15956],{"class":6503},"\"⏳ Shutting down server...\"",[6124,15958,9647],{"class":6479},[6124,15960,15961,15964,15966,15969,15971,15973,15975,15978,15980,15982,15984,15987,15989,15991,15994,15996,15998,16000],{"class":6126,"line":10902},[6124,15962,15963],{"class":9667},"    ctx",[6124,15965,5259],{"class":6479},[6124,15967,15968],{"class":9667},"cancel",[6124,15970,9671],{"class":6479},[6124,15972,5349],{"class":9667},[6124,15974,5787],{"class":6479},[6124,15976,15977],{"class":9578},"WithTimeout",[6124,15979,9704],{"class":6479},[6124,15981,5349],{"class":9667},[6124,15983,5787],{"class":6479},[6124,15985,15986],{"class":9578},"Background",[6124,15988,12294],{"class":6479},[6124,15990,13056],{"class":6490},[6124,15992,15993],{"class":6479},"*",[6124,15995,11641],{"class":9667},[6124,15997,5787],{"class":6479},[6124,15999,12535],{"class":9667},[6124,16001,9647],{"class":6479},[6124,16003,16004,16006,16009],{"class":6126,"line":10950},[6124,16005,10646],{"class":6476},[6124,16007,16008],{"class":9578}," cancel",[6124,16010,9682],{"class":6479},[6124,16012,16013],{"class":6126,"line":10955},[6124,16014,6149],{"emptyLinePlaceholder":6148},[6124,16016,16017,16019,16021,16023,16025,16027,16030,16032,16034,16036,16038,16040,16042],{"class":6126,"line":10960},[6124,16018,10551],{"class":6476},[6124,16020,10554],{"class":9667},[6124,16022,9671],{"class":6479},[6124,16024,15775],{"class":9667},[6124,16026,5787],{"class":6479},[6124,16028,16029],{"class":9578},"Shutdown",[6124,16031,9704],{"class":6479},[6124,16033,12329],{"class":9667},[6124,16035,10587],{"class":6479},[6124,16037,10590],{"class":9667},[6124,16039,10593],{"class":6479},[6124,16041,10596],{"class":6483},[6124,16043,10516],{"class":6479},[6124,16045,16046,16048,16050,16052,16054,16057,16059,16061,16063,16065],{"class":6126,"line":10992},[6124,16047,11713],{"class":9667},[6124,16049,5787],{"class":6479},[6124,16051,15831],{"class":9578},[6124,16053,9704],{"class":6479},[6124,16055,16056],{"class":6503},"\"Server forced to shutdown: ",[6124,16058,15839],{"class":9667},[6124,16060,11182],{"class":6503},[6124,16062,5259],{"class":6479},[6124,16064,10590],{"class":9667},[6124,16066,9647],{"class":6479},[6124,16068,16069],{"class":6126,"line":11015},[6124,16070,10545],{"class":6479},[6124,16072,16073],{"class":6126,"line":11021},[6124,16074,6149],{"emptyLinePlaceholder":6148},[6124,16076,16077,16079,16081,16083,16085,16088],{"class":6126,"line":11041},[6124,16078,12806],{"class":9667},[6124,16080,5787],{"class":6479},[6124,16082,15951],{"class":9578},[6124,16084,9704],{"class":6479},[6124,16086,16087],{"class":6503},"\"✅ Server stopped gracefully\"",[6124,16089,9647],{"class":6479},[6124,16091,16093],{"class":6126,"line":16092},97,[6124,16094,6167],{"class":6479},[6124,16096,16098],{"class":6126,"line":16097},98,[6124,16099,6149],{"emptyLinePlaceholder":6148},[6124,16101,16103],{"class":6126,"line":16102},99,[6124,16104,16105],{"class":9691},"\u002F\u002F Заглушки для обробників (реалізуйте власну логіку)\n",[6124,16107,16109,16111,16114,16116,16118,16120,16122,16124,16126,16128,16130,16132,16134,16136,16139,16142],{"class":6126,"line":16108},100,[6124,16110,9656],{"class":6483},[6124,16112,16113],{"class":9578}," loginHandler",[6124,16115,9704],{"class":6479},[6124,16117,9967],{"class":9667},[6124,16119,9970],{"class":9605},[6124,16121,5787],{"class":6479},[6124,16123,9975],{"class":9605},[6124,16125,5259],{"class":6479},[6124,16127,9806],{"class":9667},[6124,16129,9982],{"class":6479},[6124,16131,6469],{"class":9605},[6124,16133,5787],{"class":6479},[6124,16135,9989],{"class":9605},[6124,16137,16138],{"class":6479},") { ",[6124,16140,16141],{"class":9691},"\u002F* ... *\u002F",[6124,16143,16144],{"class":6479}," }\n",[6124,16146,16148,16150,16153,16155,16157,16159,16161,16163,16165,16167,16169,16171,16173,16175,16177,16179],{"class":6126,"line":16147},101,[6124,16149,9656],{"class":6483},[6124,16151,16152],{"class":9578}," registerHandler",[6124,16154,9704],{"class":6479},[6124,16156,9967],{"class":9667},[6124,16158,9970],{"class":9605},[6124,16160,5787],{"class":6479},[6124,16162,9975],{"class":9605},[6124,16164,5259],{"class":6479},[6124,16166,9806],{"class":9667},[6124,16168,9982],{"class":6479},[6124,16170,6469],{"class":9605},[6124,16172,5787],{"class":6479},[6124,16174,9989],{"class":9605},[6124,16176,16138],{"class":6479},[6124,16178,16141],{"class":9691},[6124,16180,16144],{"class":6479},[6124,16182,16184,16186,16188,16190,16192,16194,16196,16198,16200,16202,16204,16206,16208,16210,16212,16214],{"class":6126,"line":16183},102,[6124,16185,9656],{"class":6483},[6124,16187,10116],{"class":9578},[6124,16189,9704],{"class":6479},[6124,16191,9967],{"class":9667},[6124,16193,9970],{"class":9605},[6124,16195,5787],{"class":6479},[6124,16197,9975],{"class":9605},[6124,16199,5259],{"class":6479},[6124,16201,9806],{"class":9667},[6124,16203,9982],{"class":6479},[6124,16205,6469],{"class":9605},[6124,16207,5787],{"class":6479},[6124,16209,9989],{"class":9605},[6124,16211,16138],{"class":6479},[6124,16213,16141],{"class":9691},[6124,16215,16144],{"class":6479},[6124,16217,16219,16221,16223,16225,16227,16229,16231,16233,16235,16237,16239,16241,16243,16245,16247,16249],{"class":6126,"line":16218},103,[6124,16220,9656],{"class":6483},[6124,16222,10477],{"class":9578},[6124,16224,9704],{"class":6479},[6124,16226,9967],{"class":9667},[6124,16228,9970],{"class":9605},[6124,16230,5787],{"class":6479},[6124,16232,9975],{"class":9605},[6124,16234,5259],{"class":6479},[6124,16236,9806],{"class":9667},[6124,16238,9982],{"class":6479},[6124,16240,6469],{"class":9605},[6124,16242,5787],{"class":6479},[6124,16244,9989],{"class":9605},[6124,16246,16138],{"class":6479},[6124,16248,16141],{"class":9691},[6124,16250,16144],{"class":6479},[6124,16252,16254,16256,16258,16260,16262,16264,16266,16268,16270,16272,16274,16276,16278,16280,16282,16284],{"class":6126,"line":16253},104,[6124,16255,9656],{"class":6483},[6124,16257,10294],{"class":9578},[6124,16259,9704],{"class":6479},[6124,16261,9967],{"class":9667},[6124,16263,9970],{"class":9605},[6124,16265,5787],{"class":6479},[6124,16267,9975],{"class":9605},[6124,16269,5259],{"class":6479},[6124,16271,9806],{"class":9667},[6124,16273,9982],{"class":6479},[6124,16275,6469],{"class":9605},[6124,16277,5787],{"class":6479},[6124,16279,9989],{"class":9605},[6124,16281,16138],{"class":6479},[6124,16283,16141],{"class":9691},[6124,16285,16144],{"class":6479},[6124,16287,16289,16291,16293,16295,16297,16299,16301,16303,16305,16307,16309,16311,16313,16315,16317,16319],{"class":6126,"line":16288},105,[6124,16290,9656],{"class":6483},[6124,16292,10826],{"class":9578},[6124,16294,9704],{"class":6479},[6124,16296,9967],{"class":9667},[6124,16298,9970],{"class":9605},[6124,16300,5787],{"class":6479},[6124,16302,9975],{"class":9605},[6124,16304,5259],{"class":6479},[6124,16306,9806],{"class":9667},[6124,16308,9982],{"class":6479},[6124,16310,6469],{"class":9605},[6124,16312,5787],{"class":6479},[6124,16314,9989],{"class":9605},[6124,16316,16138],{"class":6479},[6124,16318,16141],{"class":9691},[6124,16320,16144],{"class":6479},[6124,16322,16324,16326,16328,16330,16332,16334,16336,16338,16340,16342,16344,16346,16348,16350,16352,16354],{"class":6126,"line":16323},106,[6124,16325,9656],{"class":6483},[6124,16327,10965],{"class":9578},[6124,16329,9704],{"class":6479},[6124,16331,9967],{"class":9667},[6124,16333,9970],{"class":9605},[6124,16335,5787],{"class":6479},[6124,16337,9975],{"class":9605},[6124,16339,5259],{"class":6479},[6124,16341,9806],{"class":9667},[6124,16343,9982],{"class":6479},[6124,16345,6469],{"class":9605},[6124,16347,5787],{"class":6479},[6124,16349,9989],{"class":9605},[6124,16351,16138],{"class":6479},[6124,16353,16141],{"class":9691},[6124,16355,16144],{"class":6479},[6124,16357,16359],{"class":6126,"line":16358},107,[6124,16360,6149],{"emptyLinePlaceholder":6148},[6124,16362,16364,16366,16369,16371,16373,16375,16377,16379,16381,16383,16385,16387,16389,16391],{"class":6126,"line":16363},108,[6124,16365,9656],{"class":6483},[6124,16367,16368],{"class":9578}," notFoundHandler",[6124,16370,9704],{"class":6479},[6124,16372,9967],{"class":9667},[6124,16374,9970],{"class":9605},[6124,16376,5787],{"class":6479},[6124,16378,9975],{"class":9605},[6124,16380,5259],{"class":6479},[6124,16382,9806],{"class":9667},[6124,16384,9982],{"class":6479},[6124,16386,6469],{"class":9605},[6124,16388,5787],{"class":6479},[6124,16390,9989],{"class":9605},[6124,16392,9817],{"class":6479},[6124,16394,16396,16398,16400,16402,16404,16406,16408,16410,16412,16414],{"class":6126,"line":16395},109,[6124,16397,9996],{"class":9667},[6124,16399,5787],{"class":6479},[6124,16401,10189],{"class":9578},[6124,16403,10167],{"class":6479},[6124,16405,10194],{"class":9578},[6124,16407,9704],{"class":6479},[6124,16409,10199],{"class":6503},[6124,16411,5259],{"class":6479},[6124,16413,10204],{"class":6503},[6124,16415,9647],{"class":6479},[6124,16417,16419,16421,16423,16425,16427,16429,16431,16433],{"class":6126,"line":16418},110,[6124,16420,9996],{"class":9667},[6124,16422,5787],{"class":6479},[6124,16424,10681],{"class":9578},[6124,16426,9704],{"class":6479},[6124,16428,6469],{"class":9667},[6124,16430,5787],{"class":6479},[6124,16432,13798],{"class":9667},[6124,16434,9647],{"class":6479},[6124,16436,16438,16440,16442,16444,16446,16448,16450,16452,16454,16456,16458,16460,16462,16464],{"class":6126,"line":16437},111,[6124,16439,10059],{"class":9667},[6124,16441,5787],{"class":6479},[6124,16443,10064],{"class":9578},[6124,16445,9704],{"class":6479},[6124,16447,9967],{"class":9667},[6124,16449,5407],{"class":6479},[6124,16451,10073],{"class":9578},[6124,16453,9704],{"class":6479},[6124,16455,10078],{"class":6483},[6124,16457,10081],{"class":6479},[6124,16459,10084],{"class":9605},[6124,16461,10087],{"class":6479},[6124,16463,10084],{"class":9605},[6124,16465,6543],{"class":6479},[6124,16467,16469,16471,16473,16475],{"class":6126,"line":16468},112,[6124,16470,13835],{"class":6503},[6124,16472,6552],{"class":6479},[6124,16474,13840],{"class":6503},[6124,16476,6558],{"class":6479},[6124,16478,16480,16482,16484,16486,16488,16490,16492,16494],{"class":6126,"line":16479},113,[6124,16481,13847],{"class":6503},[6124,16483,10783],{"class":6479},[6124,16485,9806],{"class":9667},[6124,16487,5787],{"class":6479},[6124,16489,10159],{"class":9667},[6124,16491,5787],{"class":6479},[6124,16493,11754],{"class":9667},[6124,16495,6558],{"class":6479},[6124,16497,16499],{"class":6126,"line":16498},114,[6124,16500,9922],{"class":6479},[6124,16502,16504],{"class":6126,"line":16503},115,[6124,16505,6167],{"class":6479},[6124,16507,16509],{"class":6126,"line":16508},116,[6124,16510,6149],{"emptyLinePlaceholder":6148},[6124,16512,16514,16516,16519,16521,16523,16525,16527,16529,16531,16533,16535,16537,16539,16541],{"class":6126,"line":16513},117,[6124,16515,9656],{"class":6483},[6124,16517,16518],{"class":9578}," methodNotAllowedHandler",[6124,16520,9704],{"class":6479},[6124,16522,9967],{"class":9667},[6124,16524,9970],{"class":9605},[6124,16526,5787],{"class":6479},[6124,16528,9975],{"class":9605},[6124,16530,5259],{"class":6479},[6124,16532,9806],{"class":9667},[6124,16534,9982],{"class":6479},[6124,16536,6469],{"class":9605},[6124,16538,5787],{"class":6479},[6124,16540,9989],{"class":9605},[6124,16542,9817],{"class":6479},[6124,16544,16546,16548,16550,16552,16554,16556,16558,16560,16562,16564],{"class":6126,"line":16545},118,[6124,16547,9996],{"class":9667},[6124,16549,5787],{"class":6479},[6124,16551,10189],{"class":9578},[6124,16553,10167],{"class":6479},[6124,16555,10194],{"class":9578},[6124,16557,9704],{"class":6479},[6124,16559,10199],{"class":6503},[6124,16561,5259],{"class":6479},[6124,16563,10204],{"class":6503},[6124,16565,9647],{"class":6479},[6124,16567,16569,16571,16573,16575,16577,16579,16581,16583],{"class":6126,"line":16568},119,[6124,16570,9996],{"class":9667},[6124,16572,5787],{"class":6479},[6124,16574,10681],{"class":9578},[6124,16576,9704],{"class":6479},[6124,16578,6469],{"class":9667},[6124,16580,5787],{"class":6479},[6124,16582,13969],{"class":9667},[6124,16584,9647],{"class":6479},[6124,16586,16588,16590,16592,16594,16596,16598,16600,16602,16604,16606,16608,16610,16612,16614],{"class":6126,"line":16587},120,[6124,16589,10059],{"class":9667},[6124,16591,5787],{"class":6479},[6124,16593,10064],{"class":9578},[6124,16595,9704],{"class":6479},[6124,16597,9967],{"class":9667},[6124,16599,5407],{"class":6479},[6124,16601,10073],{"class":9578},[6124,16603,9704],{"class":6479},[6124,16605,10078],{"class":6483},[6124,16607,10081],{"class":6479},[6124,16609,10084],{"class":9605},[6124,16611,10087],{"class":6479},[6124,16613,10084],{"class":9605},[6124,16615,6543],{"class":6479},[6124,16617,16619,16621,16623,16626],{"class":6126,"line":16618},121,[6124,16620,13835],{"class":6503},[6124,16622,6552],{"class":6479},[6124,16624,16625],{"class":6503},"\"Method not allowed\"",[6124,16627,6558],{"class":6479},[6124,16629,16631],{"class":6126,"line":16630},122,[6124,16632,9922],{"class":6479},[6124,16634,16636],{"class":6126,"line":16635},123,[6124,16637,6167],{"class":6479},[5409,16639,16640,16646],{},[5379,16641,16642,16645],{},[5205,16643,16644],{},"Chi vs інші роутери:"," Chi вирізняється серед інших роутерів (Gin, Echo, Gorilla Mux) тим, що він:",[5198,16647,16648,16658,16664,16670,16676],{},[5201,16649,16650,16651,16654,16655,16657],{},"✅ ",[5205,16652,16653],{},"100% сумісний"," з ",[5288,16656,9562],{}," (не потребує власних типів)",[5201,16659,16650,16660,16663],{},[5205,16661,16662],{},"Мінімалістичний"," (лише маршрутизація та middleware, без зайвих абстракцій)",[5201,16665,16650,16666,16669],{},[5205,16667,16668],{},"Швидкий"," (використовує Radix Tree для O(log n) пошуку маршруту)",[5201,16671,16650,16672,16675],{},[5205,16673,16674],{},"Стандартний"," (ідіоматичний Go код, без магії)",[5201,16677,16650,16678,16681],{},[5205,16679,16680],{},"Гнучкий"," (підтримка суб-роутерів, груп, контекстів)",[5366,16683],{},[5374,16685,16687],{"id":16686},"серіалізація-та-десеріалізація-json","Серіалізація та десеріалізація JSON",[6994,16689,16691],{"id":16690},"базова-робота-з-json","Базова робота з JSON",[5379,16693,16694,16695,16697],{},"Стандартний пакет ",[5288,16696,5301],{}," надає зручні методи для роботи з JSON:",[5379,16699,16700],{},[5205,16701,16702],{},"Десеріалізація запиту:",[5530,16704,16706],{"className":9594,"code":16705,"language":9579,"meta":5538,"style":5538},"type CreateOrderRequest struct {\n    UserID string `json:\"user_id\"`\n    Recipe string `json:\"recipe\"`\n    Volume string `json:\"volume\"`\n}\n\nfunc createOrderHandler(w http.ResponseWriter, r *http.Request) {\n    var req CreateOrderRequest\n    \n    \u002F\u002F Декодуємо JSON з тіла запиту\n    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {\n        http.Error(w, \"Invalid JSON: \"+err.Error(), http.StatusBadRequest)\n        return\n    }\n    defer r.Body.Close()\n\n    \u002F\u002F Валідація\n    if req.UserID == \"\" || req.Recipe == \"\" {\n        http.Error(w, \"Missing required fields\", http.StatusBadRequest)\n        return\n    }\n\n    \u002F\u002F ... бізнес-логіка\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(map[string]interface{}{\n        \"id\":      \"order_123\",\n        \"user_id\": req.UserID,\n        \"recipe\":  req.Recipe,\n        \"status\":  \"pending\",\n    })\n}\n",[5288,16707,16708,16719,16728,16737,16747,16751,16755,16785,16794,16798,16803,16843,16879,16883,16887,16903,16907,16912,16941,16968,16972,16976,16980,16985,16989,17011,17029,17059,17069,17083,17097,17107,17111],{"__ignoreMap":5538},[6124,16709,16710,16712,16715,16717],{"class":6126,"line":6127},[6124,16711,14614],{"class":6483},[6124,16713,16714],{"class":9605}," CreateOrderRequest",[6124,16716,10513],{"class":6483},[6124,16718,10516],{"class":6479},[6124,16720,16721,16724,16726],{"class":6126,"line":6133},[6124,16722,16723],{"class":9667},"    UserID",[6124,16725,10525],{"class":9605},[6124,16727,10528],{"class":6503},[6124,16729,16730,16733,16735],{"class":6126,"line":6139},[6124,16731,16732],{"class":9667},"    Recipe",[6124,16734,10525],{"class":9605},[6124,16736,10539],{"class":6503},[6124,16738,16739,16742,16744],{"class":6126,"line":6145},[6124,16740,16741],{"class":9667},"    Volume",[6124,16743,10525],{"class":9605},[6124,16745,16746],{"class":6503}," `json:\"volume\"`\n",[6124,16748,16749],{"class":6126,"line":6152},[6124,16750,6167],{"class":6479},[6124,16752,16753],{"class":6126,"line":6158},[6124,16754,6149],{"emptyLinePlaceholder":6148},[6124,16756,16757,16759,16761,16763,16765,16767,16769,16771,16773,16775,16777,16779,16781,16783],{"class":6126,"line":6164},[6124,16758,9656],{"class":6483},[6124,16760,10477],{"class":9578},[6124,16762,9704],{"class":6479},[6124,16764,9967],{"class":9667},[6124,16766,9970],{"class":9605},[6124,16768,5787],{"class":6479},[6124,16770,9975],{"class":9605},[6124,16772,5259],{"class":6479},[6124,16774,9806],{"class":9667},[6124,16776,9982],{"class":6479},[6124,16778,6469],{"class":9605},[6124,16780,5787],{"class":6479},[6124,16782,9989],{"class":9605},[6124,16784,9817],{"class":6479},[6124,16786,16787,16789,16791],{"class":6126,"line":6170},[6124,16788,10507],{"class":6483},[6124,16790,10510],{"class":9667},[6124,16792,16793],{"class":9605}," CreateOrderRequest\n",[6124,16795,16796],{"class":6126,"line":6175},[6124,16797,10356],{"class":6479},[6124,16799,16800],{"class":6126,"line":6181},[6124,16801,16802],{"class":9691},"    \u002F\u002F Декодуємо JSON з тіла запиту\n",[6124,16804,16805,16807,16809,16811,16813,16815,16817,16819,16821,16823,16825,16827,16829,16831,16833,16835,16837,16839,16841],{"class":6126,"line":6187},[6124,16806,10551],{"class":6476},[6124,16808,10554],{"class":9667},[6124,16810,9671],{"class":6479},[6124,16812,10559],{"class":9667},[6124,16814,5787],{"class":6479},[6124,16816,10564],{"class":9578},[6124,16818,9704],{"class":6479},[6124,16820,9806],{"class":9667},[6124,16822,5787],{"class":6479},[6124,16824,10573],{"class":9667},[6124,16826,5407],{"class":6479},[6124,16828,10578],{"class":9578},[6124,16830,10581],{"class":6479},[6124,16832,10584],{"class":9667},[6124,16834,10587],{"class":6479},[6124,16836,10590],{"class":9667},[6124,16838,10593],{"class":6479},[6124,16840,10596],{"class":6483},[6124,16842,10516],{"class":6479},[6124,16844,16845,16847,16849,16851,16853,16855,16857,16860,16863,16865,16867,16869,16871,16873,16875,16877],{"class":6126,"line":6193},[6124,16846,10604],{"class":9667},[6124,16848,5787],{"class":6479},[6124,16850,10609],{"class":9578},[6124,16852,9704],{"class":6479},[6124,16854,9967],{"class":9667},[6124,16856,5259],{"class":6479},[6124,16858,16859],{"class":6503},"\"Invalid JSON: \"",[6124,16861,16862],{"class":6479},"+",[6124,16864,10590],{"class":9667},[6124,16866,5787],{"class":6479},[6124,16868,10609],{"class":9578},[6124,16870,12294],{"class":6479},[6124,16872,6469],{"class":9667},[6124,16874,5787],{"class":6479},[6124,16876,10627],{"class":9667},[6124,16878,9647],{"class":6479},[6124,16880,16881],{"class":6126,"line":6199},[6124,16882,10635],{"class":6476},[6124,16884,16885],{"class":6126,"line":6204},[6124,16886,10545],{"class":6479},[6124,16888,16889,16891,16893,16895,16897,16899,16901],{"class":6126,"line":6209},[6124,16890,10646],{"class":6476},[6124,16892,10649],{"class":9667},[6124,16894,5787],{"class":6479},[6124,16896,10573],{"class":9667},[6124,16898,5787],{"class":6479},[6124,16900,10658],{"class":9578},[6124,16902,9682],{"class":6479},[6124,16904,16905],{"class":6126,"line":6215},[6124,16906,6149],{"emptyLinePlaceholder":6148},[6124,16908,16909],{"class":6126,"line":6221},[6124,16910,16911],{"class":9691},"    \u002F\u002F Валідація\n",[6124,16913,16914,16916,16918,16920,16922,16924,16926,16929,16931,16933,16935,16937,16939],{"class":6126,"line":6227},[6124,16915,10551],{"class":6476},[6124,16917,10510],{"class":9667},[6124,16919,5787],{"class":6479},[6124,16921,10773],{"class":9667},[6124,16923,11964],{"class":6479},[6124,16925,12143],{"class":6503},[6124,16927,16928],{"class":6479}," || ",[6124,16930,10584],{"class":9667},[6124,16932,5787],{"class":6479},[6124,16934,10790],{"class":9667},[6124,16936,11964],{"class":6479},[6124,16938,12143],{"class":6503},[6124,16940,10516],{"class":6479},[6124,16942,16943,16945,16947,16949,16951,16953,16955,16958,16960,16962,16964,16966],{"class":6126,"line":6232},[6124,16944,10604],{"class":9667},[6124,16946,5787],{"class":6479},[6124,16948,10609],{"class":9578},[6124,16950,9704],{"class":6479},[6124,16952,9967],{"class":9667},[6124,16954,5259],{"class":6479},[6124,16956,16957],{"class":6503},"\"Missing required fields\"",[6124,16959,5259],{"class":6479},[6124,16961,6469],{"class":9667},[6124,16963,5787],{"class":6479},[6124,16965,10627],{"class":9667},[6124,16967,9647],{"class":6479},[6124,16969,16970],{"class":6126,"line":6237},[6124,16971,10635],{"class":6476},[6124,16973,16974],{"class":6126,"line":6243},[6124,16975,10545],{"class":6479},[6124,16977,16978],{"class":6126,"line":6249},[6124,16979,6149],{"emptyLinePlaceholder":6148},[6124,16981,16982],{"class":6126,"line":6255},[6124,16983,16984],{"class":9691},"    \u002F\u002F ... бізнес-логіка\n",[6124,16986,16987],{"class":6126,"line":6261},[6124,16988,6149],{"emptyLinePlaceholder":6148},[6124,16990,16991,16993,16995,16997,16999,17001,17003,17005,17007,17009],{"class":6126,"line":6267},[6124,16992,9996],{"class":9667},[6124,16994,5787],{"class":6479},[6124,16996,10189],{"class":9578},[6124,16998,10167],{"class":6479},[6124,17000,10194],{"class":9578},[6124,17002,9704],{"class":6479},[6124,17004,10199],{"class":6503},[6124,17006,5259],{"class":6479},[6124,17008,10204],{"class":6503},[6124,17010,9647],{"class":6479},[6124,17012,17013,17015,17017,17019,17021,17023,17025,17027],{"class":6126,"line":6272},[6124,17014,9996],{"class":9667},[6124,17016,5787],{"class":6479},[6124,17018,10681],{"class":9578},[6124,17020,9704],{"class":6479},[6124,17022,6469],{"class":9667},[6124,17024,5787],{"class":6479},[6124,17026,10690],{"class":9667},[6124,17028,9647],{"class":6479},[6124,17030,17031,17033,17035,17037,17039,17041,17043,17045,17047,17049,17051,17053,17055,17057],{"class":6126,"line":6278},[6124,17032,10059],{"class":9667},[6124,17034,5787],{"class":6479},[6124,17036,10064],{"class":9578},[6124,17038,9704],{"class":6479},[6124,17040,9967],{"class":9667},[6124,17042,5407],{"class":6479},[6124,17044,10073],{"class":9578},[6124,17046,9704],{"class":6479},[6124,17048,10078],{"class":6483},[6124,17050,10081],{"class":6479},[6124,17052,10084],{"class":9605},[6124,17054,10087],{"class":6479},[6124,17056,10236],{"class":6483},[6124,17058,10239],{"class":6479},[6124,17060,17061,17063,17065,17067],{"class":6126,"line":6284},[6124,17062,10422],{"class":6503},[6124,17064,10754],{"class":6479},[6124,17066,8897],{"class":6503},[6124,17068,6558],{"class":6479},[6124,17070,17071,17073,17075,17077,17079,17081],{"class":6126,"line":6290},[6124,17072,10764],{"class":6503},[6124,17074,6552],{"class":6479},[6124,17076,10584],{"class":9667},[6124,17078,5787],{"class":6479},[6124,17080,10773],{"class":9667},[6124,17082,6558],{"class":6479},[6124,17084,17085,17087,17089,17091,17093,17095],{"class":6126,"line":6296},[6124,17086,10436],{"class":6503},[6124,17088,10783],{"class":6479},[6124,17090,10584],{"class":9667},[6124,17092,5787],{"class":6479},[6124,17094,10790],{"class":9667},[6124,17096,6558],{"class":6479},[6124,17098,17099,17101,17103,17105],{"class":6126,"line":6301},[6124,17100,10448],{"class":6503},[6124,17102,10783],{"class":6479},[6124,17104,7614],{"class":6503},[6124,17106,6558],{"class":6479},[6124,17108,17109],{"class":6126,"line":6307},[6124,17110,9922],{"class":6479},[6124,17112,17113],{"class":6126,"line":6313},[6124,17114,6167],{"class":6479},[5379,17116,17117],{},[5205,17118,17119],{},"Теги структур JSON:",[5530,17121,17123],{"className":9594,"code":17122,"language":9579,"meta":5538,"style":5538},"type Order struct {\n    ID        string    `json:\"id\"`\n    UserID    string    `json:\"user_id\"`\n    Recipe    string    `json:\"recipe\"`\n    Volume    string    `json:\"volume,omitempty\"` \u002F\u002F Опускається, якщо порожнє\n    Status    string    `json:\"status\"`\n    CreatedAt time.Time `json:\"created_at\"`\n    UpdatedAt time.Time `json:\"-\"` \u002F\u002F Ніколи не серіалізується\n}\n",[5288,17124,17125,17136,17147,17157,17166,17178,17188,17204,17221],{"__ignoreMap":5538},[6124,17126,17127,17129,17132,17134],{"class":6126,"line":6127},[6124,17128,14614],{"class":6483},[6124,17130,17131],{"class":9605}," Order",[6124,17133,10513],{"class":6483},[6124,17135,10516],{"class":6479},[6124,17137,17138,17141,17144],{"class":6126,"line":6133},[6124,17139,17140],{"class":9667},"    ID",[6124,17142,17143],{"class":9605},"        string",[6124,17145,17146],{"class":6503},"    `json:\"id\"`\n",[6124,17148,17149,17151,17154],{"class":6126,"line":6139},[6124,17150,16723],{"class":9667},[6124,17152,17153],{"class":9605},"    string",[6124,17155,17156],{"class":6503},"    `json:\"user_id\"`\n",[6124,17158,17159,17161,17163],{"class":6126,"line":6145},[6124,17160,16732],{"class":9667},[6124,17162,17153],{"class":9605},[6124,17164,17165],{"class":6503},"    `json:\"recipe\"`\n",[6124,17167,17168,17170,17172,17175],{"class":6126,"line":6152},[6124,17169,16741],{"class":9667},[6124,17171,17153],{"class":9605},[6124,17173,17174],{"class":6503},"    `json:\"volume,omitempty\"`",[6124,17176,17177],{"class":9691}," \u002F\u002F Опускається, якщо порожнє\n",[6124,17179,17180,17183,17185],{"class":6126,"line":6158},[6124,17181,17182],{"class":9667},"    Status",[6124,17184,17153],{"class":9605},[6124,17186,17187],{"class":6503},"    `json:\"status\"`\n",[6124,17189,17190,17193,17196,17198,17201],{"class":6126,"line":6164},[6124,17191,17192],{"class":9667},"    CreatedAt",[6124,17194,17195],{"class":9605}," time",[6124,17197,5787],{"class":6479},[6124,17199,17200],{"class":9605},"Time",[6124,17202,17203],{"class":6503}," `json:\"created_at\"`\n",[6124,17205,17206,17209,17211,17213,17215,17218],{"class":6126,"line":6170},[6124,17207,17208],{"class":9667},"    UpdatedAt",[6124,17210,17195],{"class":9605},[6124,17212,5787],{"class":6479},[6124,17214,17200],{"class":9605},[6124,17216,17217],{"class":6503}," `json:\"-\"`",[6124,17219,17220],{"class":9691}," \u002F\u002F Ніколи не серіалізується\n",[6124,17222,17223],{"class":6126,"line":6175},[6124,17224,6167],{"class":6479},[5379,17226,17227],{},"Теги JSON:",[5198,17229,17230,17236,17242],{},[5201,17231,17232,17235],{},[5288,17233,17234],{},"json:\"field_name\""," — встановлює ім'я поля у JSON.",[5201,17237,17238,17241],{},[5288,17239,17240],{},"json:\"field,omitempty\""," — опускає поле, якщо воно має нульове значення.",[5201,17243,17244,17247],{},[5288,17245,17246],{},"json:\"-\""," — ігнорує поле при серіалізації\u002Fдесеріалізації.",[6994,17249,17251],{"id":17250},"стандартизовані-відповіді-про-помилки-rfc-7807-problem-details","Стандартизовані відповіді про помилки: RFC 7807 Problem Details",[5379,17253,17254],{},"RFC 7807 визначає стандартний формат для опису помилок у HTTP API:",[5530,17256,17258],{"className":9594,"code":17257,"language":9579,"meta":5538,"style":5538},"type ProblemDetails struct {\n    Type     string                 `json:\"type\"`\n    Title    string                 `json:\"title\"`\n    Status   int                    `json:\"status\"`\n    Detail   string                 `json:\"detail,omitempty\"`\n    Instance string                 `json:\"instance,omitempty\"`\n    Extra    map[string]interface{} `json:\"-\"`\n}\n\nfunc (p ProblemDetails) MarshalJSON() ([]byte, error) {\n    type Alias ProblemDetails\n    base := Alias(p)\n    \n    m := make(map[string]interface{})\n    data, _ := json.Marshal(base)\n    json.Unmarshal(data, &m)\n    \n    for k, v := range p.Extra {\n        m[k] = v\n    }\n    \n    return json.Marshal(m)\n}\n\nfunc respondWithError(w http.ResponseWriter, problem ProblemDetails) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fproblem+json\")\n    w.WriteHeader(problem.Status)\n    json.NewEncoder(w).Encode(problem)\n}\n\n\u002F\u002F Використання\nfunc getOrderHandler(w http.ResponseWriter, r *http.Request) {\n    orderID := chi.URLParam(r, \"orderID\")\n    \n    \u002F\u002F Припустимо, замовлення не знайдено\n    if orderID == \"999\" {\n        respondWithError(w, ProblemDetails{\n            Type:     \"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Forder-not-found\",\n            Title:    \"Order Not Found\",\n            Status:   http.StatusNotFound,\n            Detail:   fmt.Sprintf(\"Order with ID '%s' does not exist\", orderID),\n            Instance: r.URL.Path,\n        })\n        return\n    }\n\n    \u002F\u002F ... повернення замовлення\n}\n",[5288,17259,17260,17271,17282,17292,17302,17313,17323,17345,17349,17353,17381,17392,17408,17412,17436,17462,17484,17488,17516,17532,17536,17540,17557,17561,17565,17591,17614,17633,17655,17659,17663,17667,17697,17719,17723,17728,17742,17757,17769,17782,17797,17826,17845,17849,17853,17857,17861,17866],{"__ignoreMap":5538},[6124,17261,17262,17264,17267,17269],{"class":6126,"line":6127},[6124,17263,14614],{"class":6483},[6124,17265,17266],{"class":9605}," ProblemDetails",[6124,17268,10513],{"class":6483},[6124,17270,10516],{"class":6479},[6124,17272,17273,17276,17279],{"class":6126,"line":6133},[6124,17274,17275],{"class":9667},"    Type",[6124,17277,17278],{"class":9605},"     string",[6124,17280,17281],{"class":6503},"                 `json:\"type\"`\n",[6124,17283,17284,17287,17289],{"class":6126,"line":6139},[6124,17285,17286],{"class":9667},"    Title",[6124,17288,17153],{"class":9605},[6124,17290,17291],{"class":6503},"                 `json:\"title\"`\n",[6124,17293,17294,17296,17299],{"class":6126,"line":6145},[6124,17295,17182],{"class":9667},[6124,17297,17298],{"class":9605},"   int",[6124,17300,17301],{"class":6503},"                    `json:\"status\"`\n",[6124,17303,17304,17307,17310],{"class":6126,"line":6152},[6124,17305,17306],{"class":9667},"    Detail",[6124,17308,17309],{"class":9605},"   string",[6124,17311,17312],{"class":6503},"                 `json:\"detail,omitempty\"`\n",[6124,17314,17315,17318,17320],{"class":6126,"line":6158},[6124,17316,17317],{"class":9667},"    Instance",[6124,17319,10525],{"class":9605},[6124,17321,17322],{"class":6503},"                 `json:\"instance,omitempty\"`\n",[6124,17324,17325,17328,17331,17333,17335,17337,17339,17342],{"class":6126,"line":6164},[6124,17326,17327],{"class":9667},"    Extra",[6124,17329,17330],{"class":6483},"    map",[6124,17332,10081],{"class":6479},[6124,17334,10084],{"class":9605},[6124,17336,10087],{"class":6479},[6124,17338,10236],{"class":6483},[6124,17340,17341],{"class":6479},"{} ",[6124,17343,17344],{"class":6503},"`json:\"-\"`\n",[6124,17346,17347],{"class":6126,"line":6170},[6124,17348,6167],{"class":6479},[6124,17350,17351],{"class":6126,"line":6175},[6124,17352,6149],{"emptyLinePlaceholder":6148},[6124,17354,17355,17357,17359,17362,17365,17367,17370,17373,17375,17377,17379],{"class":6126,"line":6181},[6124,17356,9656],{"class":6483},[6124,17358,5222],{"class":6479},[6124,17360,17361],{"class":9667},"p ",[6124,17363,17364],{"class":9605},"ProblemDetails",[6124,17366,7173],{"class":6479},[6124,17368,17369],{"class":9578},"MarshalJSON",[6124,17371,17372],{"class":6479},"() ([]",[6124,17374,10007],{"class":9605},[6124,17376,5259],{"class":6479},[6124,17378,5762],{"class":9605},[6124,17380,9817],{"class":6479},[6124,17382,17383,17386,17389],{"class":6126,"line":6187},[6124,17384,17385],{"class":6483},"    type",[6124,17387,17388],{"class":9605}," Alias",[6124,17390,17391],{"class":9605}," ProblemDetails\n",[6124,17393,17394,17397,17399,17402,17404,17406],{"class":6126,"line":6193},[6124,17395,17396],{"class":9667},"    base",[6124,17398,9671],{"class":6479},[6124,17400,17401],{"class":9578},"Alias",[6124,17403,9704],{"class":6479},[6124,17405,5379],{"class":9667},[6124,17407,9647],{"class":6479},[6124,17409,17410],{"class":6126,"line":6199},[6124,17411,10356],{"class":6479},[6124,17413,17414,17417,17419,17421,17423,17425,17427,17429,17431,17433],{"class":6126,"line":6204},[6124,17415,17416],{"class":9667},"    m",[6124,17418,9671],{"class":6479},[6124,17420,15875],{"class":9578},[6124,17422,9704],{"class":6479},[6124,17424,10078],{"class":6483},[6124,17426,10081],{"class":6479},[6124,17428,10084],{"class":9605},[6124,17430,10087],{"class":6479},[6124,17432,10236],{"class":6483},[6124,17434,17435],{"class":6479},"{})\n",[6124,17437,17438,17441,17443,17446,17448,17450,17452,17455,17457,17460],{"class":6126,"line":6209},[6124,17439,17440],{"class":9667},"    data",[6124,17442,5259],{"class":6479},[6124,17444,17445],{"class":9667},"_",[6124,17447,9671],{"class":6479},[6124,17449,10559],{"class":9667},[6124,17451,5787],{"class":6479},[6124,17453,17454],{"class":9578},"Marshal",[6124,17456,9704],{"class":6479},[6124,17458,17459],{"class":9667},"base",[6124,17461,9647],{"class":6479},[6124,17463,17464,17466,17468,17471,17473,17476,17479,17482],{"class":6126,"line":6215},[6124,17465,10059],{"class":9667},[6124,17467,5787],{"class":6479},[6124,17469,17470],{"class":9578},"Unmarshal",[6124,17472,9704],{"class":6479},[6124,17474,17475],{"class":9667},"data",[6124,17477,17478],{"class":6479},", &",[6124,17480,17481],{"class":9667},"m",[6124,17483,9647],{"class":6479},[6124,17485,17486],{"class":6126,"line":6221},[6124,17487,10356],{"class":6479},[6124,17489,17490,17493,17496,17498,17501,17503,17506,17509,17511,17514],{"class":6126,"line":6227},[6124,17491,17492],{"class":6476},"    for",[6124,17494,17495],{"class":9667}," k",[6124,17497,5259],{"class":6479},[6124,17499,17500],{"class":9667},"v",[6124,17502,9671],{"class":6479},[6124,17504,17505],{"class":6476},"range",[6124,17507,17508],{"class":9667}," p",[6124,17510,5787],{"class":6479},[6124,17512,17513],{"class":9667},"Extra",[6124,17515,10516],{"class":6479},[6124,17517,17518,17521,17523,17526,17529],{"class":6126,"line":6232},[6124,17519,17520],{"class":9667},"        m",[6124,17522,10081],{"class":6479},[6124,17524,17525],{"class":9667},"k",[6124,17527,17528],{"class":6479},"] = ",[6124,17530,17531],{"class":9667},"v\n",[6124,17533,17534],{"class":6126,"line":6237},[6124,17535,10545],{"class":6479},[6124,17537,17538],{"class":6126,"line":6243},[6124,17539,10356],{"class":6479},[6124,17541,17542,17544,17547,17549,17551,17553,17555],{"class":6126,"line":6249},[6124,17543,11596],{"class":6476},[6124,17545,17546],{"class":9667}," json",[6124,17548,5787],{"class":6479},[6124,17550,17454],{"class":9578},[6124,17552,9704],{"class":6479},[6124,17554,17481],{"class":9667},[6124,17556,9647],{"class":6479},[6124,17558,17559],{"class":6126,"line":6255},[6124,17560,6167],{"class":6479},[6124,17562,17563],{"class":6126,"line":6261},[6124,17564,6149],{"emptyLinePlaceholder":6148},[6124,17566,17567,17569,17572,17574,17576,17578,17580,17582,17584,17587,17589],{"class":6126,"line":6267},[6124,17568,9656],{"class":6483},[6124,17570,17571],{"class":9578}," respondWithError",[6124,17573,9704],{"class":6479},[6124,17575,9967],{"class":9667},[6124,17577,9970],{"class":9605},[6124,17579,5787],{"class":6479},[6124,17581,9975],{"class":9605},[6124,17583,5259],{"class":6479},[6124,17585,17586],{"class":9667},"problem",[6124,17588,17266],{"class":9605},[6124,17590,9817],{"class":6479},[6124,17592,17593,17595,17597,17599,17601,17603,17605,17607,17609,17612],{"class":6126,"line":6272},[6124,17594,9996],{"class":9667},[6124,17596,5787],{"class":6479},[6124,17598,10189],{"class":9578},[6124,17600,10167],{"class":6479},[6124,17602,10194],{"class":9578},[6124,17604,9704],{"class":6479},[6124,17606,10199],{"class":6503},[6124,17608,5259],{"class":6479},[6124,17610,17611],{"class":6503},"\"application\u002Fproblem+json\"",[6124,17613,9647],{"class":6479},[6124,17615,17616,17618,17620,17622,17624,17626,17628,17631],{"class":6126,"line":6278},[6124,17617,9996],{"class":9667},[6124,17619,5787],{"class":6479},[6124,17621,10681],{"class":9578},[6124,17623,9704],{"class":6479},[6124,17625,17586],{"class":9667},[6124,17627,5787],{"class":6479},[6124,17629,17630],{"class":9667},"Status",[6124,17632,9647],{"class":6479},[6124,17634,17635,17637,17639,17641,17643,17645,17647,17649,17651,17653],{"class":6126,"line":6284},[6124,17636,10059],{"class":9667},[6124,17638,5787],{"class":6479},[6124,17640,10064],{"class":9578},[6124,17642,9704],{"class":6479},[6124,17644,9967],{"class":9667},[6124,17646,5407],{"class":6479},[6124,17648,10073],{"class":9578},[6124,17650,9704],{"class":6479},[6124,17652,17586],{"class":9667},[6124,17654,9647],{"class":6479},[6124,17656,17657],{"class":6126,"line":6290},[6124,17658,6167],{"class":6479},[6124,17660,17661],{"class":6126,"line":6296},[6124,17662,6149],{"emptyLinePlaceholder":6148},[6124,17664,17665],{"class":6126,"line":6301},[6124,17666,14506],{"class":9691},[6124,17668,17669,17671,17673,17675,17677,17679,17681,17683,17685,17687,17689,17691,17693,17695],{"class":6126,"line":6307},[6124,17670,9656],{"class":6483},[6124,17672,10294],{"class":9578},[6124,17674,9704],{"class":6479},[6124,17676,9967],{"class":9667},[6124,17678,9970],{"class":9605},[6124,17680,5787],{"class":6479},[6124,17682,9975],{"class":9605},[6124,17684,5259],{"class":6479},[6124,17686,9806],{"class":9667},[6124,17688,9982],{"class":6479},[6124,17690,6469],{"class":9605},[6124,17692,5787],{"class":6479},[6124,17694,9989],{"class":9605},[6124,17696,9817],{"class":6479},[6124,17698,17699,17701,17703,17705,17707,17709,17711,17713,17715,17717],{"class":6126,"line":6313},[6124,17700,10330],{"class":9667},[6124,17702,9671],{"class":6479},[6124,17704,9674],{"class":9667},[6124,17706,5787],{"class":6479},[6124,17708,10339],{"class":9578},[6124,17710,9704],{"class":6479},[6124,17712,9806],{"class":9667},[6124,17714,5259],{"class":6479},[6124,17716,10348],{"class":6503},[6124,17718,9647],{"class":6479},[6124,17720,17721],{"class":6126,"line":6319},[6124,17722,10356],{"class":6479},[6124,17724,17725],{"class":6126,"line":6324},[6124,17726,17727],{"class":9691},"    \u002F\u002F Припустимо, замовлення не знайдено\n",[6124,17729,17730,17732,17735,17737,17740],{"class":6126,"line":8100},[6124,17731,10551],{"class":6476},[6124,17733,17734],{"class":9667}," orderID",[6124,17736,11964],{"class":6479},[6124,17738,17739],{"class":6503},"\"999\"",[6124,17741,10516],{"class":6479},[6124,17743,17744,17747,17749,17751,17753,17755],{"class":6126,"line":8106},[6124,17745,17746],{"class":9578},"        respondWithError",[6124,17748,9704],{"class":6479},[6124,17750,9967],{"class":9667},[6124,17752,5259],{"class":6479},[6124,17754,17364],{"class":9605},[6124,17756,6543],{"class":6479},[6124,17758,17759,17762,17764,17767],{"class":6126,"line":8112},[6124,17760,17761],{"class":9667},"            Type",[6124,17763,10425],{"class":6479},[6124,17765,17766],{"class":6503},"\"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Forder-not-found\"",[6124,17768,6558],{"class":6479},[6124,17770,17771,17774,17777,17780],{"class":6126,"line":8117},[6124,17772,17773],{"class":9667},"            Title",[6124,17775,17776],{"class":6479},":    ",[6124,17778,17779],{"class":6503},"\"Order Not Found\"",[6124,17781,6558],{"class":6479},[6124,17783,17784,17787,17789,17791,17793,17795],{"class":6126,"line":8123},[6124,17785,17786],{"class":9667},"            Status",[6124,17788,15204],{"class":6479},[6124,17790,6469],{"class":9667},[6124,17792,5787],{"class":6479},[6124,17794,13798],{"class":9667},[6124,17796,6558],{"class":6479},[6124,17798,17799,17802,17804,17806,17808,17810,17812,17815,17817,17820,17822,17824],{"class":6126,"line":8129},[6124,17800,17801],{"class":9667},"            Detail",[6124,17803,15204],{"class":6479},[6124,17805,14010],{"class":9667},[6124,17807,5787],{"class":6479},[6124,17809,14015],{"class":9578},[6124,17811,9704],{"class":6479},[6124,17813,17814],{"class":6503},"\"Order with ID '",[6124,17816,11179],{"class":9667},[6124,17818,17819],{"class":6503},"' does not exist\"",[6124,17821,5259],{"class":6479},[6124,17823,10428],{"class":9667},[6124,17825,14052],{"class":6479},[6124,17827,17828,17831,17833,17835,17837,17839,17841,17843],{"class":6126,"line":8135},[6124,17829,17830],{"class":9667},"            Instance",[6124,17832,6552],{"class":6479},[6124,17834,9806],{"class":9667},[6124,17836,5787],{"class":6479},[6124,17838,10159],{"class":9667},[6124,17840,5787],{"class":6479},[6124,17842,11754],{"class":9667},[6124,17844,6558],{"class":6479},[6124,17846,17847],{"class":6126,"line":8141},[6124,17848,15231],{"class":6479},[6124,17850,17851],{"class":6126,"line":8146},[6124,17852,10635],{"class":6476},[6124,17854,17855],{"class":6126,"line":10209},[6124,17856,10545],{"class":6479},[6124,17858,17859],{"class":6126,"line":10242},[6124,17860,6149],{"emptyLinePlaceholder":6148},[6124,17862,17863],{"class":6126,"line":10274},[6124,17864,17865],{"class":9691},"    \u002F\u002F ... повернення замовлення\n",[6124,17867,17868],{"class":6126,"line":10279},[6124,17869,6167],{"class":6479},[5379,17871,17872],{},"Приклад відповіді про помилку:",[5530,17874,17877],{"className":17875,"code":17876,"language":10559,"meta":5538,"style":5538},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n  \"type\": \"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Forder-not-found\",\n  \"title\": \"Order Not Found\",\n  \"status\": 404,\n  \"detail\": \"Order with ID '999' does not exist\",\n  \"instance\": \"\u002Fv1\u002Forders\u002F999\"\n}\n",[5288,17878,17879,17883,17894,17905,17915,17927,17937],{"__ignoreMap":5538},[6124,17880,17881],{"class":6126,"line":6127},[6124,17882,6543],{"class":6479},[6124,17884,17885,17888,17890,17892],{"class":6126,"line":6133},[6124,17886,17887],{"class":6548},"  \"type\"",[6124,17889,6552],{"class":6479},[6124,17891,17766],{"class":6503},[6124,17893,6558],{"class":6479},[6124,17895,17896,17899,17901,17903],{"class":6126,"line":6139},[6124,17897,17898],{"class":6548},"  \"title\"",[6124,17900,6552],{"class":6479},[6124,17902,17779],{"class":6503},[6124,17904,6558],{"class":6479},[6124,17906,17907,17909,17911,17913],{"class":6126,"line":6145},[6124,17908,8622],{"class":6548},[6124,17910,6552],{"class":6479},[6124,17912,7471],{"class":6490},[6124,17914,6558],{"class":6479},[6124,17916,17917,17920,17922,17925],{"class":6126,"line":6152},[6124,17918,17919],{"class":6548},"  \"detail\"",[6124,17921,6552],{"class":6479},[6124,17923,17924],{"class":6503},"\"Order with ID '999' does not exist\"",[6124,17926,6558],{"class":6479},[6124,17928,17929,17932,17934],{"class":6126,"line":6158},[6124,17930,17931],{"class":6548},"  \"instance\"",[6124,17933,6552],{"class":6479},[6124,17935,17936],{"class":6503},"\"\u002Fv1\u002Forders\u002F999\"\n",[6124,17938,17939],{"class":6126,"line":6164},[6124,17940,6167],{"class":6479},[5366,17942],{},[5369,17944,17946],{"id":17945},"clean-architecture-у-rest-api-розділення-відповідальностей","Clean Architecture у REST API: розділення відповідальностей",[5374,17948,17950],{"id":17949},"шари-clean-architecture","Шари Clean Architecture",[5379,17952,17953,17955,17956,17959],{},[5205,17954,5315],{}," — це архітектурний патерн, запропонований Робертом Мартіном (",[5224,17957,17958],{},"Robert C. Martin"," \u002F «Uncle Bob»), що передбачає розділення коду на шари з чіткими межами відповідальності:",[6113,17961,17963],{"alt":17962},"Шари Clean Architecture у Go API",[5530,17964,17966],{"className":6118,"code":17965,"language":6120,"meta":5538,"style":5538},"@startuml\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nskinparam classAttributeIconSize 0\n\npackage \"Delivery Layer (HTTP Handlers)\" #F1F5F9 {\n    class OrderHandler {\n        - useCase: OrderUseCase\n        + List(w, r)\n        + Get(w, r)\n        + Create(w, r)\n        + Update(w, r)\n        + Delete(w, r)\n    }\n}\n\npackage \"UseCase Layer (Business Logic)\" #DBEAFE {\n    interface OrderUseCase {\n        + ListOrders(ctx, userID): ([]Order, error)\n        + GetOrder(ctx, id): (Order, error)\n        + CreateOrder(ctx, dto): (Order, error)\n        + UpdateOrder(ctx, id, dto): (Order, error)\n        + DeleteOrder(ctx, id): error\n    }\n    \n    class orderService {\n        - repo: OrderRepository\n        + ListOrders(...)\n        + CreateOrder(...)\n    }\n}\n\npackage \"Domain Layer (Entities)\" #FEF3C7 {\n    class Order {\n        + ID: string\n        + UserID: string\n        + Recipe: string\n        + Status: string\n        + CreatedAt: time.Time\n    }\n}\n\npackage \"Repository Layer (Database)\" #DCFCE7 {\n    interface OrderRepository {\n        + FindAll(ctx, filter): ([]Order, error)\n        + FindByID(ctx, id): (Order, error)\n        + Create(ctx, order): error\n        + Update(ctx, order): error\n        + Delete(ctx, id): error\n    }\n    \n    class pgOrderRepo {\n        - db: *pgxpool.Pool\n        + FindAll(...)\n        + Create(...)\n    }\n}\n\nOrderHandler o-- OrderUseCase : використовує\norderService ..|> OrderUseCase : реалізує\norderService o-- OrderRepository : використовує\npgOrderRepo ..|> OrderRepository : реалізує\norderService ..> Order : оперує\npgOrderRepo ..> Order : зберігає\n\nnote right of OrderHandler #F1F5F9\n  HTTP-специфічна логіка:\n  парсинг запитів, валідація,\n  формування відповідей\nend note\n\nnote right of orderService #DBEAFE\n  Бізнес-правила:\n  перевірка дозволів,\n  валідація даних,\n  оркестрація операцій\nend note\n\nnote right of pgOrderRepo #DCFCE7\n  Доступ до даних:\n  SQL-запити, транзакції,\n  маппінг на структури\nend note\n@enduml\n",[5288,17967,17968,17972,17976,17980,17985,17989,17994,17999,18004,18009,18014,18019,18024,18029,18033,18037,18041,18046,18051,18056,18061,18066,18071,18076,18080,18084,18089,18094,18099,18104,18108,18112,18116,18121,18126,18131,18136,18141,18146,18151,18155,18159,18163,18168,18173,18178,18183,18188,18193,18198,18202,18206,18211,18216,18221,18226,18230,18234,18238,18243,18248,18253,18258,18263,18268,18272,18277,18282,18287,18292,18296,18300,18305,18310,18315,18320,18325,18329,18333,18338,18343,18348,18353,18357],{"__ignoreMap":5538},[6124,17969,17970],{"class":6126,"line":6127},[6124,17971,6130],{},[6124,17973,17974],{"class":6126,"line":6133},[6124,17975,6136],{},[6124,17977,17978],{"class":6126,"line":6139},[6124,17979,6142],{},[6124,17981,17982],{"class":6126,"line":6145},[6124,17983,17984],{},"skinparam classAttributeIconSize 0\n",[6124,17986,17987],{"class":6126,"line":6152},[6124,17988,6149],{"emptyLinePlaceholder":6148},[6124,17990,17991],{"class":6126,"line":6158},[6124,17992,17993],{},"package \"Delivery Layer (HTTP Handlers)\" #F1F5F9 {\n",[6124,17995,17996],{"class":6126,"line":6164},[6124,17997,17998],{},"    class OrderHandler {\n",[6124,18000,18001],{"class":6126,"line":6170},[6124,18002,18003],{},"        - useCase: OrderUseCase\n",[6124,18005,18006],{"class":6126,"line":6175},[6124,18007,18008],{},"        + List(w, r)\n",[6124,18010,18011],{"class":6126,"line":6181},[6124,18012,18013],{},"        + Get(w, r)\n",[6124,18015,18016],{"class":6126,"line":6187},[6124,18017,18018],{},"        + Create(w, r)\n",[6124,18020,18021],{"class":6126,"line":6193},[6124,18022,18023],{},"        + Update(w, r)\n",[6124,18025,18026],{"class":6126,"line":6199},[6124,18027,18028],{},"        + Delete(w, r)\n",[6124,18030,18031],{"class":6126,"line":6204},[6124,18032,10545],{},[6124,18034,18035],{"class":6126,"line":6209},[6124,18036,6167],{},[6124,18038,18039],{"class":6126,"line":6215},[6124,18040,6149],{"emptyLinePlaceholder":6148},[6124,18042,18043],{"class":6126,"line":6221},[6124,18044,18045],{},"package \"UseCase Layer (Business Logic)\" #DBEAFE {\n",[6124,18047,18048],{"class":6126,"line":6227},[6124,18049,18050],{},"    interface OrderUseCase {\n",[6124,18052,18053],{"class":6126,"line":6232},[6124,18054,18055],{},"        + ListOrders(ctx, userID): ([]Order, error)\n",[6124,18057,18058],{"class":6126,"line":6237},[6124,18059,18060],{},"        + GetOrder(ctx, id): (Order, error)\n",[6124,18062,18063],{"class":6126,"line":6243},[6124,18064,18065],{},"        + CreateOrder(ctx, dto): (Order, error)\n",[6124,18067,18068],{"class":6126,"line":6249},[6124,18069,18070],{},"        + UpdateOrder(ctx, id, dto): (Order, error)\n",[6124,18072,18073],{"class":6126,"line":6255},[6124,18074,18075],{},"        + DeleteOrder(ctx, id): error\n",[6124,18077,18078],{"class":6126,"line":6261},[6124,18079,10545],{},[6124,18081,18082],{"class":6126,"line":6267},[6124,18083,10356],{},[6124,18085,18086],{"class":6126,"line":6272},[6124,18087,18088],{},"    class orderService {\n",[6124,18090,18091],{"class":6126,"line":6278},[6124,18092,18093],{},"        - repo: OrderRepository\n",[6124,18095,18096],{"class":6126,"line":6284},[6124,18097,18098],{},"        + ListOrders(...)\n",[6124,18100,18101],{"class":6126,"line":6290},[6124,18102,18103],{},"        + CreateOrder(...)\n",[6124,18105,18106],{"class":6126,"line":6296},[6124,18107,10545],{},[6124,18109,18110],{"class":6126,"line":6301},[6124,18111,6167],{},[6124,18113,18114],{"class":6126,"line":6307},[6124,18115,6149],{"emptyLinePlaceholder":6148},[6124,18117,18118],{"class":6126,"line":6313},[6124,18119,18120],{},"package \"Domain Layer (Entities)\" #FEF3C7 {\n",[6124,18122,18123],{"class":6126,"line":6319},[6124,18124,18125],{},"    class Order {\n",[6124,18127,18128],{"class":6126,"line":6324},[6124,18129,18130],{},"        + ID: string\n",[6124,18132,18133],{"class":6126,"line":8100},[6124,18134,18135],{},"        + UserID: string\n",[6124,18137,18138],{"class":6126,"line":8106},[6124,18139,18140],{},"        + Recipe: string\n",[6124,18142,18143],{"class":6126,"line":8112},[6124,18144,18145],{},"        + Status: string\n",[6124,18147,18148],{"class":6126,"line":8117},[6124,18149,18150],{},"        + CreatedAt: time.Time\n",[6124,18152,18153],{"class":6126,"line":8123},[6124,18154,10545],{},[6124,18156,18157],{"class":6126,"line":8129},[6124,18158,6167],{},[6124,18160,18161],{"class":6126,"line":8135},[6124,18162,6149],{"emptyLinePlaceholder":6148},[6124,18164,18165],{"class":6126,"line":8141},[6124,18166,18167],{},"package \"Repository Layer (Database)\" #DCFCE7 {\n",[6124,18169,18170],{"class":6126,"line":8146},[6124,18171,18172],{},"    interface OrderRepository {\n",[6124,18174,18175],{"class":6126,"line":10209},[6124,18176,18177],{},"        + FindAll(ctx, filter): ([]Order, error)\n",[6124,18179,18180],{"class":6126,"line":10242},[6124,18181,18182],{},"        + FindByID(ctx, id): (Order, error)\n",[6124,18184,18185],{"class":6126,"line":10274},[6124,18186,18187],{},"        + Create(ctx, order): error\n",[6124,18189,18190],{"class":6126,"line":10279},[6124,18191,18192],{},"        + Update(ctx, order): error\n",[6124,18194,18195],{"class":6126,"line":10284},[6124,18196,18197],{},"        + Delete(ctx, id): error\n",[6124,18199,18200],{"class":6126,"line":10289},[6124,18201,10545],{},[6124,18203,18204],{"class":6126,"line":10321},[6124,18205,10356],{},[6124,18207,18208],{"class":6126,"line":10327},[6124,18209,18210],{},"    class pgOrderRepo {\n",[6124,18212,18213],{"class":6126,"line":10353},[6124,18214,18215],{},"        - db: *pgxpool.Pool\n",[6124,18217,18218],{"class":6126,"line":10359},[6124,18219,18220],{},"        + FindAll(...)\n",[6124,18222,18223],{"class":6126,"line":10365},[6124,18224,18225],{},"        + Create(...)\n",[6124,18227,18228],{"class":6126,"line":10388},[6124,18229,10545],{},[6124,18231,18232],{"class":6126,"line":10419},[6124,18233,6167],{},[6124,18235,18236],{"class":6126,"line":10433},[6124,18237,6149],{"emptyLinePlaceholder":6148},[6124,18239,18240],{"class":6126,"line":10445},[6124,18241,18242],{},"OrderHandler o-- OrderUseCase : використовує\n",[6124,18244,18245],{"class":6126,"line":10457},[6124,18246,18247],{},"orderService ..|> OrderUseCase : реалізує\n",[6124,18249,18250],{"class":6126,"line":10462},[6124,18251,18252],{},"orderService o-- OrderRepository : використовує\n",[6124,18254,18255],{"class":6126,"line":10467},[6124,18256,18257],{},"pgOrderRepo ..|> OrderRepository : реалізує\n",[6124,18259,18260],{"class":6126,"line":10472},[6124,18261,18262],{},"orderService ..> Order : оперує\n",[6124,18264,18265],{"class":6126,"line":10504},[6124,18266,18267],{},"pgOrderRepo ..> Order : зберігає\n",[6124,18269,18270],{"class":6126,"line":10519},[6124,18271,6149],{"emptyLinePlaceholder":6148},[6124,18273,18274],{"class":6126,"line":10531},[6124,18275,18276],{},"note right of OrderHandler #F1F5F9\n",[6124,18278,18279],{"class":6126,"line":10542},[6124,18280,18281],{},"  HTTP-специфічна логіка:\n",[6124,18283,18284],{"class":6126,"line":10548},[6124,18285,18286],{},"  парсинг запитів, валідація,\n",[6124,18288,18289],{"class":6126,"line":10601},[6124,18290,18291],{},"  формування відповідей\n",[6124,18293,18294],{"class":6126,"line":10632},[6124,18295,6293],{},[6124,18297,18298],{"class":6126,"line":10638},[6124,18299,6149],{"emptyLinePlaceholder":6148},[6124,18301,18302],{"class":6126,"line":10643},[6124,18303,18304],{},"note right of orderService #DBEAFE\n",[6124,18306,18307],{"class":6126,"line":10663},[6124,18308,18309],{},"  Бізнес-правила:\n",[6124,18311,18312],{"class":6126,"line":10668},[6124,18313,18314],{},"  перевірка дозволів,\n",[6124,18316,18317],{"class":6126,"line":10674},[6124,18318,18319],{},"  валідація даних,\n",[6124,18321,18322],{"class":6126,"line":10695},[6124,18323,18324],{},"  оркестрація операцій\n",[6124,18326,18327],{"class":6126,"line":10718},[6124,18328,6293],{},[6124,18330,18331],{"class":6126,"line":10749},[6124,18332,6149],{"emptyLinePlaceholder":6148},[6124,18334,18335],{"class":6126,"line":10761},[6124,18336,18337],{},"note right of pgOrderRepo #DCFCE7\n",[6124,18339,18340],{"class":6126,"line":10778},[6124,18341,18342],{},"  Доступ до даних:\n",[6124,18344,18345],{"class":6126,"line":10795},[6124,18346,18347],{},"  SQL-запити, транзакції,\n",[6124,18349,18350],{"class":6126,"line":10806},[6124,18351,18352],{},"  маппінг на структури\n",[6124,18354,18355],{"class":6126,"line":10811},[6124,18356,6293],{},[6124,18358,18359],{"class":6126,"line":10816},[6124,18360,6327],{},[5379,18362,18363],{},[5205,18364,18365],{},"1. Domain Layer (Домен):",[5379,18367,18368],{},"Містить сутності предметної області без залежностей:",[5530,18370,18372],{"className":9594,"code":18371,"language":9579,"meta":5538,"style":5538},"\u002F\u002F internal\u002Fdomain\u002Forder.go\npackage domain\n\nimport \"time\"\n\ntype Order struct {\n    ID        string\n    UserID    string\n    Recipe    string\n    Volume    string\n    Status    OrderStatus\n    CreatedAt time.Time\n    UpdatedAt time.Time\n}\n\ntype OrderStatus string\n\nconst (\n    OrderStatusPending   OrderStatus = \"pending\"\n    OrderStatusPreparing OrderStatus = \"preparing\"\n    OrderStatusCompleted OrderStatus = \"completed\"\n    OrderStatusCancelled OrderStatus = \"cancelled\"\n)\n\nfunc (o *Order) CanBeCancelled() bool {\n    return o.Status == OrderStatusPending || o.Status == OrderStatusPreparing\n}\n",[5288,18373,18374,18379,18386,18390,18397,18401,18411,18418,18425,18431,18437,18444,18455,18465,18469,18473,18482,18486,18492,18504,18516,18527,18539,18543,18547,18573,18603],{"__ignoreMap":5538},[6124,18375,18376],{"class":6126,"line":6127},[6124,18377,18378],{"class":9691},"\u002F\u002F internal\u002Fdomain\u002Forder.go\n",[6124,18380,18381,18383],{"class":6126,"line":6133},[6124,18382,9602],{"class":6483},[6124,18384,18385],{"class":9605}," domain\n",[6124,18387,18388],{"class":6126,"line":6139},[6124,18389,6149],{"emptyLinePlaceholder":6148},[6124,18391,18392,18394],{"class":6126,"line":6145},[6124,18393,9615],{"class":6476},[6124,18395,18396],{"class":6503}," \"time\"\n",[6124,18398,18399],{"class":6126,"line":6152},[6124,18400,6149],{"emptyLinePlaceholder":6148},[6124,18402,18403,18405,18407,18409],{"class":6126,"line":6158},[6124,18404,14614],{"class":6483},[6124,18406,17131],{"class":9605},[6124,18408,10513],{"class":6483},[6124,18410,10516],{"class":6479},[6124,18412,18413,18415],{"class":6126,"line":6164},[6124,18414,17140],{"class":9667},[6124,18416,18417],{"class":9605},"        string\n",[6124,18419,18420,18422],{"class":6126,"line":6170},[6124,18421,16723],{"class":9667},[6124,18423,18424],{"class":9605},"    string\n",[6124,18426,18427,18429],{"class":6126,"line":6175},[6124,18428,16732],{"class":9667},[6124,18430,18424],{"class":9605},[6124,18432,18433,18435],{"class":6126,"line":6181},[6124,18434,16741],{"class":9667},[6124,18436,18424],{"class":9605},[6124,18438,18439,18441],{"class":6126,"line":6187},[6124,18440,17182],{"class":9667},[6124,18442,18443],{"class":9605},"    OrderStatus\n",[6124,18445,18446,18448,18450,18452],{"class":6126,"line":6193},[6124,18447,17192],{"class":9667},[6124,18449,17195],{"class":9605},[6124,18451,5787],{"class":6479},[6124,18453,18454],{"class":9605},"Time\n",[6124,18456,18457,18459,18461,18463],{"class":6126,"line":6199},[6124,18458,17208],{"class":9667},[6124,18460,17195],{"class":9605},[6124,18462,5787],{"class":6479},[6124,18464,18454],{"class":9605},[6124,18466,18467],{"class":6126,"line":6204},[6124,18468,6167],{"class":6479},[6124,18470,18471],{"class":6126,"line":6209},[6124,18472,6149],{"emptyLinePlaceholder":6148},[6124,18474,18475,18477,18480],{"class":6126,"line":6215},[6124,18476,14614],{"class":6483},[6124,18478,18479],{"class":9605}," OrderStatus",[6124,18481,14620],{"class":9605},[6124,18483,18484],{"class":6126,"line":6221},[6124,18485,6149],{"emptyLinePlaceholder":6148},[6124,18487,18488,18490],{"class":6126,"line":6227},[6124,18489,14629],{"class":6483},[6124,18491,9618],{"class":6479},[6124,18493,18494,18497,18500,18502],{"class":6126,"line":6232},[6124,18495,18496],{"class":14632},"    OrderStatusPending",[6124,18498,18499],{"class":9605},"   OrderStatus",[6124,18501,14638],{"class":6479},[6124,18503,8627],{"class":6503},[6124,18505,18506,18509,18511,18513],{"class":6126,"line":6237},[6124,18507,18508],{"class":14632},"    OrderStatusPreparing",[6124,18510,18479],{"class":9605},[6124,18512,14638],{"class":6479},[6124,18514,18515],{"class":6503},"\"preparing\"\n",[6124,18517,18518,18521,18523,18525],{"class":6126,"line":6243},[6124,18519,18520],{"class":14632},"    OrderStatusCompleted",[6124,18522,18479],{"class":9605},[6124,18524,14638],{"class":6479},[6124,18526,8929],{"class":6503},[6124,18528,18529,18532,18534,18536],{"class":6126,"line":6249},[6124,18530,18531],{"class":14632},"    OrderStatusCancelled",[6124,18533,18479],{"class":9605},[6124,18535,14638],{"class":6479},[6124,18537,18538],{"class":6503},"\"cancelled\"\n",[6124,18540,18541],{"class":6126,"line":6255},[6124,18542,9647],{"class":6479},[6124,18544,18545],{"class":6126,"line":6261},[6124,18546,6149],{"emptyLinePlaceholder":6148},[6124,18548,18549,18551,18553,18556,18558,18561,18563,18566,18568,18571],{"class":6126,"line":6267},[6124,18550,9656],{"class":6483},[6124,18552,5222],{"class":6479},[6124,18554,18555],{"class":9667},"o ",[6124,18557,15993],{"class":6479},[6124,18559,18560],{"class":9605},"Order",[6124,18562,7173],{"class":6479},[6124,18564,18565],{"class":9578},"CanBeCancelled",[6124,18567,13363],{"class":6479},[6124,18569,18570],{"class":9605},"bool",[6124,18572,10516],{"class":6479},[6124,18574,18575,18577,18580,18582,18584,18586,18589,18591,18594,18596,18598,18600],{"class":6126,"line":6272},[6124,18576,11596],{"class":6476},[6124,18578,18579],{"class":9667}," o",[6124,18581,5787],{"class":6479},[6124,18583,17630],{"class":9667},[6124,18585,11964],{"class":6479},[6124,18587,18588],{"class":9667},"OrderStatusPending",[6124,18590,16928],{"class":6479},[6124,18592,18593],{"class":9667},"o",[6124,18595,5787],{"class":6479},[6124,18597,17630],{"class":9667},[6124,18599,11964],{"class":6479},[6124,18601,18602],{"class":9667},"OrderStatusPreparing\n",[6124,18604,18605],{"class":6126,"line":6278},[6124,18606,6167],{"class":6479},[5379,18608,18609],{},[5205,18610,18611],{},"2. Repository Layer (Репозиторій):",[5379,18613,18614],{},"Інтерфейс доступу до даних:",[5530,18616,18618],{"className":9594,"code":18617,"language":9579,"meta":5538,"style":5538},"\u002F\u002F internal\u002Frepository\u002Forder_repository.go\npackage repository\n\nimport (\n    \"context\"\n    \"myapp\u002Finternal\u002Fdomain\"\n)\n\ntype OrderRepository interface {\n    FindAll(ctx context.Context, userID string) ([]domain.Order, error)\n    FindByID(ctx context.Context, id string) (domain.Order, error)\n    Create(ctx context.Context, order *domain.Order) error\n    Update(ctx context.Context, order *domain.Order) error\n    Delete(ctx context.Context, id string) error\n}\n",[5288,18619,18620,18625,18632,18636,18642,18646,18651,18655,18659,18671,18709,18745,18778,18809,18834],{"__ignoreMap":5538},[6124,18621,18622],{"class":6126,"line":6127},[6124,18623,18624],{"class":9691},"\u002F\u002F internal\u002Frepository\u002Forder_repository.go\n",[6124,18626,18627,18629],{"class":6126,"line":6133},[6124,18628,9602],{"class":6483},[6124,18630,18631],{"class":9605}," repository\n",[6124,18633,18634],{"class":6126,"line":6139},[6124,18635,6149],{"emptyLinePlaceholder":6148},[6124,18637,18638,18640],{"class":6126,"line":6145},[6124,18639,9615],{"class":6476},[6124,18641,9618],{"class":6479},[6124,18643,18644],{"class":6126,"line":6152},[6124,18645,14897],{"class":6503},[6124,18647,18648],{"class":6126,"line":6158},[6124,18649,18650],{"class":6503},"    \"myapp\u002Finternal\u002Fdomain\"\n",[6124,18652,18653],{"class":6126,"line":6164},[6124,18654,9647],{"class":6479},[6124,18656,18657],{"class":6126,"line":6170},[6124,18658,6149],{"emptyLinePlaceholder":6148},[6124,18660,18661,18663,18666,18669],{"class":6126,"line":6175},[6124,18662,14614],{"class":6483},[6124,18664,18665],{"class":9605}," OrderRepository",[6124,18667,18668],{"class":6483}," interface",[6124,18670,10516],{"class":6479},[6124,18672,18673,18676,18678,18680,18683,18685,18687,18689,18691,18693,18696,18699,18701,18703,18705,18707],{"class":6126,"line":6181},[6124,18674,18675],{"class":9578},"    FindAll",[6124,18677,9704],{"class":6479},[6124,18679,12329],{"class":9667},[6124,18681,18682],{"class":9605}," context",[6124,18684,5787],{"class":6479},[6124,18686,12291],{"class":9605},[6124,18688,5259],{"class":6479},[6124,18690,10261],{"class":9667},[6124,18692,10525],{"class":9605},[6124,18694,18695],{"class":6479},") ([]",[6124,18697,18698],{"class":9605},"domain",[6124,18700,5787],{"class":6479},[6124,18702,18560],{"class":9605},[6124,18704,5259],{"class":6479},[6124,18706,5762],{"class":9605},[6124,18708,9647],{"class":6479},[6124,18710,18711,18714,18716,18718,18720,18722,18724,18726,18728,18730,18733,18735,18737,18739,18741,18743],{"class":6126,"line":6187},[6124,18712,18713],{"class":9578},"    FindByID",[6124,18715,9704],{"class":6479},[6124,18717,12329],{"class":9667},[6124,18719,18682],{"class":9605},[6124,18721,5787],{"class":6479},[6124,18723,12291],{"class":9605},[6124,18725,5259],{"class":6479},[6124,18727,11232],{"class":9667},[6124,18729,10525],{"class":9605},[6124,18731,18732],{"class":6479},") (",[6124,18734,18698],{"class":9605},[6124,18736,5787],{"class":6479},[6124,18738,18560],{"class":9605},[6124,18740,5259],{"class":6479},[6124,18742,5762],{"class":9605},[6124,18744,9647],{"class":6479},[6124,18746,18747,18750,18752,18754,18756,18758,18760,18762,18765,18767,18769,18771,18773,18775],{"class":6126,"line":6193},[6124,18748,18749],{"class":9578},"    Create",[6124,18751,9704],{"class":6479},[6124,18753,12329],{"class":9667},[6124,18755,18682],{"class":9605},[6124,18757,5787],{"class":6479},[6124,18759,12291],{"class":9605},[6124,18761,5259],{"class":6479},[6124,18763,18764],{"class":9667},"order",[6124,18766,9982],{"class":6479},[6124,18768,18698],{"class":9605},[6124,18770,5787],{"class":6479},[6124,18772,18560],{"class":9605},[6124,18774,7173],{"class":6479},[6124,18776,18777],{"class":9605},"error\n",[6124,18779,18780,18783,18785,18787,18789,18791,18793,18795,18797,18799,18801,18803,18805,18807],{"class":6126,"line":6199},[6124,18781,18782],{"class":9578},"    Update",[6124,18784,9704],{"class":6479},[6124,18786,12329],{"class":9667},[6124,18788,18682],{"class":9605},[6124,18790,5787],{"class":6479},[6124,18792,12291],{"class":9605},[6124,18794,5259],{"class":6479},[6124,18796,18764],{"class":9667},[6124,18798,9982],{"class":6479},[6124,18800,18698],{"class":9605},[6124,18802,5787],{"class":6479},[6124,18804,18560],{"class":9605},[6124,18806,7173],{"class":6479},[6124,18808,18777],{"class":9605},[6124,18810,18811,18814,18816,18818,18820,18822,18824,18826,18828,18830,18832],{"class":6126,"line":6204},[6124,18812,18813],{"class":9578},"    Delete",[6124,18815,9704],{"class":6479},[6124,18817,12329],{"class":9667},[6124,18819,18682],{"class":9605},[6124,18821,5787],{"class":6479},[6124,18823,12291],{"class":9605},[6124,18825,5259],{"class":6479},[6124,18827,11232],{"class":9667},[6124,18829,10525],{"class":9605},[6124,18831,7173],{"class":6479},[6124,18833,18777],{"class":9605},[6124,18835,18836],{"class":6126,"line":6209},[6124,18837,6167],{"class":6479},[5379,18839,18840],{},"Конкретна імплементація для PostgreSQL:",[5530,18842,18844],{"className":9594,"code":18843,"language":9579,"meta":5538,"style":5538},"\u002F\u002F internal\u002Frepository\u002Fpostgres\u002Forder_repository.go\npackage postgres\n\nimport (\n    \"context\"\n    \"myapp\u002Finternal\u002Fdomain\"\n    \"github.com\u002Fjackc\u002Fpgx\u002Fv5\u002Fpgxpool\"\n)\n\ntype OrderRepository struct {\n    db *pgxpool.Pool\n}\n\nfunc NewOrderRepository(db *pgxpool.Pool) *OrderRepository {\n    return &OrderRepository{db: db}\n}\n\nfunc (r *OrderRepository) FindByID(ctx context.Context, id string) (domain.Order, error) {\n    var order domain.Order\n    query := `\n        SELECT id, user_id, recipe, volume, status, created_at, updated_at\n        FROM orders\n        WHERE id = $1\n    `\n    err := r.db.QueryRow(ctx, query, id).Scan(\n        &order.ID,\n        &order.UserID,\n        &order.Recipe,\n        &order.Volume,\n        &order.Status,\n        &order.CreatedAt,\n        &order.UpdatedAt,\n    )\n    if err != nil {\n        return domain.Order{}, err\n    }\n    return order, nil\n}\n\nfunc (r *OrderRepository) Create(ctx context.Context, order *domain.Order) error {\n    query := `\n        INSERT INTO orders (id, user_id, recipe, volume, status, created_at, updated_at)\n        VALUES ($1, $2, $3, $4, $5, $6, $7)\n    `\n    _, err := r.db.Exec(ctx, query,\n        order.ID,\n        order.UserID,\n        order.Recipe,\n        order.Volume,\n        order.Status,\n        order.CreatedAt,\n        order.UpdatedAt,\n    )\n    return err\n}\n\n\u002F\u002F ... інші методи\n",[5288,18845,18846,18851,18858,18862,18868,18872,18876,18881,18885,18889,18899,18914,18918,18922,18951,18970,18974,18978,19026,19041,19051,19056,19061,19066,19071,19109,19122,19134,19146,19159,19171,19184,19197,19202,19214,19231,19235,19246,19250,19254,19298,19306,19311,19316,19320,19352,19363,19373,19383,19393,19403,19413,19423,19427,19434,19438,19442],{"__ignoreMap":5538},[6124,18847,18848],{"class":6126,"line":6127},[6124,18849,18850],{"class":9691},"\u002F\u002F internal\u002Frepository\u002Fpostgres\u002Forder_repository.go\n",[6124,18852,18853,18855],{"class":6126,"line":6133},[6124,18854,9602],{"class":6483},[6124,18856,18857],{"class":9605}," postgres\n",[6124,18859,18860],{"class":6126,"line":6139},[6124,18861,6149],{"emptyLinePlaceholder":6148},[6124,18863,18864,18866],{"class":6126,"line":6145},[6124,18865,9615],{"class":6476},[6124,18867,9618],{"class":6479},[6124,18869,18870],{"class":6126,"line":6152},[6124,18871,14897],{"class":6503},[6124,18873,18874],{"class":6126,"line":6158},[6124,18875,18650],{"class":6503},[6124,18877,18878],{"class":6126,"line":6164},[6124,18879,18880],{"class":6503},"    \"github.com\u002Fjackc\u002Fpgx\u002Fv5\u002Fpgxpool\"\n",[6124,18882,18883],{"class":6126,"line":6170},[6124,18884,9647],{"class":6479},[6124,18886,18887],{"class":6126,"line":6175},[6124,18888,6149],{"emptyLinePlaceholder":6148},[6124,18890,18891,18893,18895,18897],{"class":6126,"line":6181},[6124,18892,14614],{"class":6483},[6124,18894,18665],{"class":9605},[6124,18896,10513],{"class":6483},[6124,18898,10516],{"class":6479},[6124,18900,18901,18904,18906,18909,18911],{"class":6126,"line":6187},[6124,18902,18903],{"class":9667},"    db",[6124,18905,9982],{"class":6479},[6124,18907,18908],{"class":9605},"pgxpool",[6124,18910,5787],{"class":6479},[6124,18912,18913],{"class":9605},"Pool\n",[6124,18915,18916],{"class":6126,"line":6193},[6124,18917,6167],{"class":6479},[6124,18919,18920],{"class":6126,"line":6199},[6124,18921,6149],{"emptyLinePlaceholder":6148},[6124,18923,18924,18926,18929,18931,18934,18936,18938,18940,18943,18946,18949],{"class":6126,"line":6204},[6124,18925,9656],{"class":6483},[6124,18927,18928],{"class":9578}," NewOrderRepository",[6124,18930,9704],{"class":6479},[6124,18932,18933],{"class":9667},"db",[6124,18935,9982],{"class":6479},[6124,18937,18908],{"class":9605},[6124,18939,5787],{"class":6479},[6124,18941,18942],{"class":9605},"Pool",[6124,18944,18945],{"class":6479},") *",[6124,18947,18948],{"class":9605},"OrderRepository",[6124,18950,10516],{"class":6479},[6124,18952,18953,18955,18958,18960,18962,18964,18966,18968],{"class":6126,"line":6209},[6124,18954,11596],{"class":6476},[6124,18956,18957],{"class":6479}," &",[6124,18959,18948],{"class":9605},[6124,18961,8747],{"class":6479},[6124,18963,18933],{"class":9667},[6124,18965,6552],{"class":6479},[6124,18967,18933],{"class":9667},[6124,18969,6167],{"class":6479},[6124,18971,18972],{"class":6126,"line":6215},[6124,18973,6167],{"class":6479},[6124,18975,18976],{"class":6126,"line":6221},[6124,18977,6149],{"emptyLinePlaceholder":6148},[6124,18979,18980,18982,18984,18987,18989,18991,18993,18996,18998,19000,19002,19004,19006,19008,19010,19012,19014,19016,19018,19020,19022,19024],{"class":6126,"line":6227},[6124,18981,9656],{"class":6483},[6124,18983,5222],{"class":6479},[6124,18985,18986],{"class":9667},"r ",[6124,18988,15993],{"class":6479},[6124,18990,18948],{"class":9605},[6124,18992,7173],{"class":6479},[6124,18994,18995],{"class":9578},"FindByID",[6124,18997,9704],{"class":6479},[6124,18999,12329],{"class":9667},[6124,19001,18682],{"class":9605},[6124,19003,5787],{"class":6479},[6124,19005,12291],{"class":9605},[6124,19007,5259],{"class":6479},[6124,19009,11232],{"class":9667},[6124,19011,10525],{"class":9605},[6124,19013,18732],{"class":6479},[6124,19015,18698],{"class":9605},[6124,19017,5787],{"class":6479},[6124,19019,18560],{"class":9605},[6124,19021,5259],{"class":6479},[6124,19023,5762],{"class":9605},[6124,19025,9817],{"class":6479},[6124,19027,19028,19030,19033,19036,19038],{"class":6126,"line":6232},[6124,19029,10507],{"class":6483},[6124,19031,19032],{"class":9667}," order",[6124,19034,19035],{"class":9605}," domain",[6124,19037,5787],{"class":6479},[6124,19039,19040],{"class":9605},"Order\n",[6124,19042,19043,19046,19048],{"class":6126,"line":6237},[6124,19044,19045],{"class":9667},"    query",[6124,19047,9671],{"class":6479},[6124,19049,19050],{"class":6503},"`\n",[6124,19052,19053],{"class":6126,"line":6243},[6124,19054,19055],{"class":6503},"        SELECT id, user_id, recipe, volume, status, created_at, updated_at\n",[6124,19057,19058],{"class":6126,"line":6249},[6124,19059,19060],{"class":6503},"        FROM orders\n",[6124,19062,19063],{"class":6126,"line":6255},[6124,19064,19065],{"class":6503},"        WHERE id = $1\n",[6124,19067,19068],{"class":6126,"line":6261},[6124,19069,19070],{"class":6503},"    `\n",[6124,19072,19073,19076,19078,19080,19082,19084,19086,19089,19091,19093,19095,19097,19099,19101,19103,19106],{"class":6126,"line":6267},[6124,19074,19075],{"class":9667},"    err",[6124,19077,9671],{"class":6479},[6124,19079,9806],{"class":9667},[6124,19081,5787],{"class":6479},[6124,19083,18933],{"class":9667},[6124,19085,5787],{"class":6479},[6124,19087,19088],{"class":9578},"QueryRow",[6124,19090,9704],{"class":6479},[6124,19092,12329],{"class":9667},[6124,19094,5259],{"class":6479},[6124,19096,5248],{"class":9667},[6124,19098,5259],{"class":6479},[6124,19100,11232],{"class":9667},[6124,19102,5407],{"class":6479},[6124,19104,19105],{"class":9578},"Scan",[6124,19107,19108],{"class":6479},"(\n",[6124,19110,19111,19114,19116,19118,19120],{"class":6126,"line":6272},[6124,19112,19113],{"class":6479},"        &",[6124,19115,18764],{"class":9667},[6124,19117,5787],{"class":6479},[6124,19119,14442],{"class":9667},[6124,19121,6558],{"class":6479},[6124,19123,19124,19126,19128,19130,19132],{"class":6126,"line":6278},[6124,19125,19113],{"class":6479},[6124,19127,18764],{"class":9667},[6124,19129,5787],{"class":6479},[6124,19131,10773],{"class":9667},[6124,19133,6558],{"class":6479},[6124,19135,19136,19138,19140,19142,19144],{"class":6126,"line":6284},[6124,19137,19113],{"class":6479},[6124,19139,18764],{"class":9667},[6124,19141,5787],{"class":6479},[6124,19143,10790],{"class":9667},[6124,19145,6558],{"class":6479},[6124,19147,19148,19150,19152,19154,19157],{"class":6126,"line":6290},[6124,19149,19113],{"class":6479},[6124,19151,18764],{"class":9667},[6124,19153,5787],{"class":6479},[6124,19155,19156],{"class":9667},"Volume",[6124,19158,6558],{"class":6479},[6124,19160,19161,19163,19165,19167,19169],{"class":6126,"line":6296},[6124,19162,19113],{"class":6479},[6124,19164,18764],{"class":9667},[6124,19166,5787],{"class":6479},[6124,19168,17630],{"class":9667},[6124,19170,6558],{"class":6479},[6124,19172,19173,19175,19177,19179,19182],{"class":6126,"line":6301},[6124,19174,19113],{"class":6479},[6124,19176,18764],{"class":9667},[6124,19178,5787],{"class":6479},[6124,19180,19181],{"class":9667},"CreatedAt",[6124,19183,6558],{"class":6479},[6124,19185,19186,19188,19190,19192,19195],{"class":6126,"line":6307},[6124,19187,19113],{"class":6479},[6124,19189,18764],{"class":9667},[6124,19191,5787],{"class":6479},[6124,19193,19194],{"class":9667},"UpdatedAt",[6124,19196,6558],{"class":6479},[6124,19198,19199],{"class":6126,"line":6313},[6124,19200,19201],{"class":6479},"    )\n",[6124,19203,19204,19206,19208,19210,19212],{"class":6126,"line":6319},[6124,19205,10551],{"class":6476},[6124,19207,10554],{"class":9667},[6124,19209,10593],{"class":6479},[6124,19211,10596],{"class":6483},[6124,19213,10516],{"class":6479},[6124,19215,19216,19219,19221,19223,19225,19228],{"class":6126,"line":6324},[6124,19217,19218],{"class":6476},"        return",[6124,19220,19035],{"class":9605},[6124,19222,5787],{"class":6479},[6124,19224,18560],{"class":9605},[6124,19226,19227],{"class":6479},"{}, ",[6124,19229,19230],{"class":9667},"err\n",[6124,19232,19233],{"class":6126,"line":8100},[6124,19234,10545],{"class":6479},[6124,19236,19237,19239,19241,19243],{"class":6126,"line":8106},[6124,19238,11596],{"class":6476},[6124,19240,19032],{"class":9667},[6124,19242,5259],{"class":6479},[6124,19244,19245],{"class":6483},"nil\n",[6124,19247,19248],{"class":6126,"line":8112},[6124,19249,6167],{"class":6479},[6124,19251,19252],{"class":6126,"line":8117},[6124,19253,6149],{"emptyLinePlaceholder":6148},[6124,19255,19256,19258,19260,19262,19264,19266,19268,19270,19272,19274,19276,19278,19280,19282,19284,19286,19288,19290,19292,19294,19296],{"class":6126,"line":8123},[6124,19257,9656],{"class":6483},[6124,19259,5222],{"class":6479},[6124,19261,18986],{"class":9667},[6124,19263,15993],{"class":6479},[6124,19265,18948],{"class":9605},[6124,19267,7173],{"class":6479},[6124,19269,8394],{"class":9578},[6124,19271,9704],{"class":6479},[6124,19273,12329],{"class":9667},[6124,19275,18682],{"class":9605},[6124,19277,5787],{"class":6479},[6124,19279,12291],{"class":9605},[6124,19281,5259],{"class":6479},[6124,19283,18764],{"class":9667},[6124,19285,9982],{"class":6479},[6124,19287,18698],{"class":9605},[6124,19289,5787],{"class":6479},[6124,19291,18560],{"class":9605},[6124,19293,7173],{"class":6479},[6124,19295,5762],{"class":9605},[6124,19297,10516],{"class":6479},[6124,19299,19300,19302,19304],{"class":6126,"line":8129},[6124,19301,19045],{"class":9667},[6124,19303,9671],{"class":6479},[6124,19305,19050],{"class":6503},[6124,19307,19308],{"class":6126,"line":8135},[6124,19309,19310],{"class":6503},"        INSERT INTO orders (id, user_id, recipe, volume, status, created_at, updated_at)\n",[6124,19312,19313],{"class":6126,"line":8141},[6124,19314,19315],{"class":6503},"        VALUES ($1, $2, $3, $4, $5, $6, $7)\n",[6124,19317,19318],{"class":6126,"line":8146},[6124,19319,19070],{"class":6503},[6124,19321,19322,19325,19327,19329,19331,19333,19335,19337,19339,19342,19344,19346,19348,19350],{"class":6126,"line":10209},[6124,19323,19324],{"class":9667},"    _",[6124,19326,5259],{"class":6479},[6124,19328,10590],{"class":9667},[6124,19330,9671],{"class":6479},[6124,19332,9806],{"class":9667},[6124,19334,5787],{"class":6479},[6124,19336,18933],{"class":9667},[6124,19338,5787],{"class":6479},[6124,19340,19341],{"class":9578},"Exec",[6124,19343,9704],{"class":6479},[6124,19345,12329],{"class":9667},[6124,19347,5259],{"class":6479},[6124,19349,5248],{"class":9667},[6124,19351,6558],{"class":6479},[6124,19353,19354,19357,19359,19361],{"class":6126,"line":10242},[6124,19355,19356],{"class":9667},"        order",[6124,19358,5787],{"class":6479},[6124,19360,14442],{"class":9667},[6124,19362,6558],{"class":6479},[6124,19364,19365,19367,19369,19371],{"class":6126,"line":10274},[6124,19366,19356],{"class":9667},[6124,19368,5787],{"class":6479},[6124,19370,10773],{"class":9667},[6124,19372,6558],{"class":6479},[6124,19374,19375,19377,19379,19381],{"class":6126,"line":10279},[6124,19376,19356],{"class":9667},[6124,19378,5787],{"class":6479},[6124,19380,10790],{"class":9667},[6124,19382,6558],{"class":6479},[6124,19384,19385,19387,19389,19391],{"class":6126,"line":10284},[6124,19386,19356],{"class":9667},[6124,19388,5787],{"class":6479},[6124,19390,19156],{"class":9667},[6124,19392,6558],{"class":6479},[6124,19394,19395,19397,19399,19401],{"class":6126,"line":10289},[6124,19396,19356],{"class":9667},[6124,19398,5787],{"class":6479},[6124,19400,17630],{"class":9667},[6124,19402,6558],{"class":6479},[6124,19404,19405,19407,19409,19411],{"class":6126,"line":10321},[6124,19406,19356],{"class":9667},[6124,19408,5787],{"class":6479},[6124,19410,19181],{"class":9667},[6124,19412,6558],{"class":6479},[6124,19414,19415,19417,19419,19421],{"class":6126,"line":10327},[6124,19416,19356],{"class":9667},[6124,19418,5787],{"class":6479},[6124,19420,19194],{"class":9667},[6124,19422,6558],{"class":6479},[6124,19424,19425],{"class":6126,"line":10353},[6124,19426,19201],{"class":6479},[6124,19428,19429,19431],{"class":6126,"line":10359},[6124,19430,11596],{"class":6476},[6124,19432,19433],{"class":9667}," err\n",[6124,19435,19436],{"class":6126,"line":10365},[6124,19437,6167],{"class":6479},[6124,19439,19440],{"class":6126,"line":10388},[6124,19441,6149],{"emptyLinePlaceholder":6148},[6124,19443,19444],{"class":6126,"line":10419},[6124,19445,19446],{"class":9691},"\u002F\u002F ... інші методи\n",[5379,19448,19449],{},[5205,19450,19451],{},"3. UseCase Layer (Бізнес-логіка):",[5530,19453,19455],{"className":9594,"code":19454,"language":9579,"meta":5538,"style":5538},"\u002F\u002F internal\u002Fusecase\u002Forder_usecase.go\npackage usecase\n\nimport (\n    \"context\"\n    \"myapp\u002Finternal\u002Fdomain\"\n    \"myapp\u002Finternal\u002Frepository\"\n    \"time\"\n    \"github.com\u002Fgoogle\u002Fuuid\"\n)\n\ntype OrderUseCase interface {\n    GetOrder(ctx context.Context, id string) (domain.Order, error)\n    CreateOrder(ctx context.Context, dto CreateOrderDTO) (domain.Order, error)\n}\n\ntype CreateOrderDTO struct {\n    UserID string\n    Recipe string\n    Volume string\n}\n\ntype orderService struct {\n    repo repository.OrderRepository\n}\n\nfunc NewOrderService(repo repository.OrderRepository) OrderUseCase {\n    return &orderService{repo: repo}\n}\n\nfunc (s *orderService) GetOrder(ctx context.Context, id string) (domain.Order, error) {\n    return s.repo.FindByID(ctx, id)\n}\n\nfunc (s *orderService) CreateOrder(ctx context.Context, dto CreateOrderDTO) (domain.Order, error) {\n    \u002F\u002F Бізнес-валідація\n    if dto.Recipe == \"\" {\n        return domain.Order{}, ErrInvalidRecipe\n    }\n\n    order := domain.Order{\n        ID:        uuid.New().String(),\n        UserID:    dto.UserID,\n        Recipe:    dto.Recipe,\n        Volume:    dto.Volume,\n        Status:    domain.OrderStatusPending,\n        CreatedAt: time.Now(),\n        UpdatedAt: time.Now(),\n    }\n\n    if err := s.repo.Create(ctx, &order); err != nil {\n        return domain.Order{}, err\n    }\n\n    return order, nil\n}\n",[5288,19456,19457,19462,19469,19473,19479,19483,19487,19492,19496,19501,19505,19509,19520,19555,19592,19596,19600,19610,19616,19622,19628,19632,19636,19647,19660,19664,19668,19693,19712,19716,19720,19768,19793,19797,19801,19848,19853,19870,19885,19889,19893,19908,19932,19946,19960,19975,19990,20005,20020,20024,20028,20065,20079,20083,20087,20097],{"__ignoreMap":5538},[6124,19458,19459],{"class":6126,"line":6127},[6124,19460,19461],{"class":9691},"\u002F\u002F internal\u002Fusecase\u002Forder_usecase.go\n",[6124,19463,19464,19466],{"class":6126,"line":6133},[6124,19465,9602],{"class":6483},[6124,19467,19468],{"class":9605}," usecase\n",[6124,19470,19471],{"class":6126,"line":6139},[6124,19472,6149],{"emptyLinePlaceholder":6148},[6124,19474,19475,19477],{"class":6126,"line":6145},[6124,19476,9615],{"class":6476},[6124,19478,9618],{"class":6479},[6124,19480,19481],{"class":6126,"line":6152},[6124,19482,14897],{"class":6503},[6124,19484,19485],{"class":6126,"line":6158},[6124,19486,18650],{"class":6503},[6124,19488,19489],{"class":6126,"line":6164},[6124,19490,19491],{"class":6503},"    \"myapp\u002Finternal\u002Frepository\"\n",[6124,19493,19494],{"class":6126,"line":6170},[6124,19495,14930],{"class":6503},[6124,19497,19498],{"class":6126,"line":6175},[6124,19499,19500],{"class":6503},"    \"github.com\u002Fgoogle\u002Fuuid\"\n",[6124,19502,19503],{"class":6126,"line":6181},[6124,19504,9647],{"class":6479},[6124,19506,19507],{"class":6126,"line":6187},[6124,19508,6149],{"emptyLinePlaceholder":6148},[6124,19510,19511,19513,19516,19518],{"class":6126,"line":6193},[6124,19512,14614],{"class":6483},[6124,19514,19515],{"class":9605}," OrderUseCase",[6124,19517,18668],{"class":6483},[6124,19519,10516],{"class":6479},[6124,19521,19522,19525,19527,19529,19531,19533,19535,19537,19539,19541,19543,19545,19547,19549,19551,19553],{"class":6126,"line":6199},[6124,19523,19524],{"class":9578},"    GetOrder",[6124,19526,9704],{"class":6479},[6124,19528,12329],{"class":9667},[6124,19530,18682],{"class":9605},[6124,19532,5787],{"class":6479},[6124,19534,12291],{"class":9605},[6124,19536,5259],{"class":6479},[6124,19538,11232],{"class":9667},[6124,19540,10525],{"class":9605},[6124,19542,18732],{"class":6479},[6124,19544,18698],{"class":9605},[6124,19546,5787],{"class":6479},[6124,19548,18560],{"class":9605},[6124,19550,5259],{"class":6479},[6124,19552,5762],{"class":9605},[6124,19554,9647],{"class":6479},[6124,19556,19557,19560,19562,19564,19566,19568,19570,19572,19575,19578,19580,19582,19584,19586,19588,19590],{"class":6126,"line":6204},[6124,19558,19559],{"class":9578},"    CreateOrder",[6124,19561,9704],{"class":6479},[6124,19563,12329],{"class":9667},[6124,19565,18682],{"class":9605},[6124,19567,5787],{"class":6479},[6124,19569,12291],{"class":9605},[6124,19571,5259],{"class":6479},[6124,19573,19574],{"class":9667},"dto",[6124,19576,19577],{"class":9605}," CreateOrderDTO",[6124,19579,18732],{"class":6479},[6124,19581,18698],{"class":9605},[6124,19583,5787],{"class":6479},[6124,19585,18560],{"class":9605},[6124,19587,5259],{"class":6479},[6124,19589,5762],{"class":9605},[6124,19591,9647],{"class":6479},[6124,19593,19594],{"class":6126,"line":6209},[6124,19595,6167],{"class":6479},[6124,19597,19598],{"class":6126,"line":6215},[6124,19599,6149],{"emptyLinePlaceholder":6148},[6124,19601,19602,19604,19606,19608],{"class":6126,"line":6221},[6124,19603,14614],{"class":6483},[6124,19605,19577],{"class":9605},[6124,19607,10513],{"class":6483},[6124,19609,10516],{"class":6479},[6124,19611,19612,19614],{"class":6126,"line":6227},[6124,19613,16723],{"class":9667},[6124,19615,14620],{"class":9605},[6124,19617,19618,19620],{"class":6126,"line":6232},[6124,19619,16732],{"class":9667},[6124,19621,14620],{"class":9605},[6124,19623,19624,19626],{"class":6126,"line":6237},[6124,19625,16741],{"class":9667},[6124,19627,14620],{"class":9605},[6124,19629,19630],{"class":6126,"line":6243},[6124,19631,6167],{"class":6479},[6124,19633,19634],{"class":6126,"line":6249},[6124,19635,6149],{"emptyLinePlaceholder":6148},[6124,19637,19638,19640,19643,19645],{"class":6126,"line":6255},[6124,19639,14614],{"class":6483},[6124,19641,19642],{"class":9605}," orderService",[6124,19644,10513],{"class":6483},[6124,19646,10516],{"class":6479},[6124,19648,19649,19652,19655,19657],{"class":6126,"line":6261},[6124,19650,19651],{"class":9667},"    repo",[6124,19653,19654],{"class":9605}," repository",[6124,19656,5787],{"class":6479},[6124,19658,19659],{"class":9605},"OrderRepository\n",[6124,19661,19662],{"class":6126,"line":6267},[6124,19663,6167],{"class":6479},[6124,19665,19666],{"class":6126,"line":6272},[6124,19667,6149],{"emptyLinePlaceholder":6148},[6124,19669,19670,19672,19675,19677,19680,19682,19684,19686,19688,19691],{"class":6126,"line":6278},[6124,19671,9656],{"class":6483},[6124,19673,19674],{"class":9578}," NewOrderService",[6124,19676,9704],{"class":6479},[6124,19678,19679],{"class":9667},"repo",[6124,19681,19654],{"class":9605},[6124,19683,5787],{"class":6479},[6124,19685,18948],{"class":9605},[6124,19687,7173],{"class":6479},[6124,19689,19690],{"class":9605},"OrderUseCase",[6124,19692,10516],{"class":6479},[6124,19694,19695,19697,19699,19702,19704,19706,19708,19710],{"class":6126,"line":6284},[6124,19696,11596],{"class":6476},[6124,19698,18957],{"class":6479},[6124,19700,19701],{"class":9605},"orderService",[6124,19703,8747],{"class":6479},[6124,19705,19679],{"class":9667},[6124,19707,6552],{"class":6479},[6124,19709,19679],{"class":9667},[6124,19711,6167],{"class":6479},[6124,19713,19714],{"class":6126,"line":6290},[6124,19715,6167],{"class":6479},[6124,19717,19718],{"class":6126,"line":6296},[6124,19719,6149],{"emptyLinePlaceholder":6148},[6124,19721,19722,19724,19726,19729,19731,19733,19735,19738,19740,19742,19744,19746,19748,19750,19752,19754,19756,19758,19760,19762,19764,19766],{"class":6126,"line":6301},[6124,19723,9656],{"class":6483},[6124,19725,5222],{"class":6479},[6124,19727,19728],{"class":9667},"s ",[6124,19730,15993],{"class":6479},[6124,19732,19701],{"class":9605},[6124,19734,7173],{"class":6479},[6124,19736,19737],{"class":9578},"GetOrder",[6124,19739,9704],{"class":6479},[6124,19741,12329],{"class":9667},[6124,19743,18682],{"class":9605},[6124,19745,5787],{"class":6479},[6124,19747,12291],{"class":9605},[6124,19749,5259],{"class":6479},[6124,19751,11232],{"class":9667},[6124,19753,10525],{"class":9605},[6124,19755,18732],{"class":6479},[6124,19757,18698],{"class":9605},[6124,19759,5787],{"class":6479},[6124,19761,18560],{"class":9605},[6124,19763,5259],{"class":6479},[6124,19765,5762],{"class":9605},[6124,19767,9817],{"class":6479},[6124,19769,19770,19772,19775,19777,19779,19781,19783,19785,19787,19789,19791],{"class":6126,"line":6307},[6124,19771,11596],{"class":6476},[6124,19773,19774],{"class":9667}," s",[6124,19776,5787],{"class":6479},[6124,19778,19679],{"class":9667},[6124,19780,5787],{"class":6479},[6124,19782,18995],{"class":9578},[6124,19784,9704],{"class":6479},[6124,19786,12329],{"class":9667},[6124,19788,5259],{"class":6479},[6124,19790,11232],{"class":9667},[6124,19792,9647],{"class":6479},[6124,19794,19795],{"class":6126,"line":6313},[6124,19796,6167],{"class":6479},[6124,19798,19799],{"class":6126,"line":6319},[6124,19800,6149],{"emptyLinePlaceholder":6148},[6124,19802,19803,19805,19807,19809,19811,19813,19815,19818,19820,19822,19824,19826,19828,19830,19832,19834,19836,19838,19840,19842,19844,19846],{"class":6126,"line":6324},[6124,19804,9656],{"class":6483},[6124,19806,5222],{"class":6479},[6124,19808,19728],{"class":9667},[6124,19810,15993],{"class":6479},[6124,19812,19701],{"class":9605},[6124,19814,7173],{"class":6479},[6124,19816,19817],{"class":9578},"CreateOrder",[6124,19819,9704],{"class":6479},[6124,19821,12329],{"class":9667},[6124,19823,18682],{"class":9605},[6124,19825,5787],{"class":6479},[6124,19827,12291],{"class":9605},[6124,19829,5259],{"class":6479},[6124,19831,19574],{"class":9667},[6124,19833,19577],{"class":9605},[6124,19835,18732],{"class":6479},[6124,19837,18698],{"class":9605},[6124,19839,5787],{"class":6479},[6124,19841,18560],{"class":9605},[6124,19843,5259],{"class":6479},[6124,19845,5762],{"class":9605},[6124,19847,9817],{"class":6479},[6124,19849,19850],{"class":6126,"line":8100},[6124,19851,19852],{"class":9691},"    \u002F\u002F Бізнес-валідація\n",[6124,19854,19855,19857,19860,19862,19864,19866,19868],{"class":6126,"line":8106},[6124,19856,10551],{"class":6476},[6124,19858,19859],{"class":9667}," dto",[6124,19861,5787],{"class":6479},[6124,19863,10790],{"class":9667},[6124,19865,11964],{"class":6479},[6124,19867,12143],{"class":6503},[6124,19869,10516],{"class":6479},[6124,19871,19872,19874,19876,19878,19880,19882],{"class":6126,"line":8112},[6124,19873,19218],{"class":6476},[6124,19875,19035],{"class":9605},[6124,19877,5787],{"class":6479},[6124,19879,18560],{"class":9605},[6124,19881,19227],{"class":6479},[6124,19883,19884],{"class":9667},"ErrInvalidRecipe\n",[6124,19886,19887],{"class":6126,"line":8117},[6124,19888,10545],{"class":6479},[6124,19890,19891],{"class":6126,"line":8123},[6124,19892,6149],{"emptyLinePlaceholder":6148},[6124,19894,19895,19898,19900,19902,19904,19906],{"class":6126,"line":8129},[6124,19896,19897],{"class":9667},"    order",[6124,19899,9671],{"class":6479},[6124,19901,18698],{"class":9605},[6124,19903,5787],{"class":6479},[6124,19905,18560],{"class":9605},[6124,19907,6543],{"class":6479},[6124,19909,19910,19913,19916,19919,19921,19924,19926,19929],{"class":6126,"line":8135},[6124,19911,19912],{"class":9667},"        ID",[6124,19914,19915],{"class":6479},":        ",[6124,19917,19918],{"class":9667},"uuid",[6124,19920,5787],{"class":6479},[6124,19922,19923],{"class":9578},"New",[6124,19925,10167],{"class":6479},[6124,19927,19928],{"class":9578},"String",[6124,19930,19931],{"class":6479},"(),\n",[6124,19933,19934,19936,19938,19940,19942,19944],{"class":6126,"line":8141},[6124,19935,10522],{"class":9667},[6124,19937,17776],{"class":6479},[6124,19939,19574],{"class":9667},[6124,19941,5787],{"class":6479},[6124,19943,10773],{"class":9667},[6124,19945,6558],{"class":6479},[6124,19947,19948,19950,19952,19954,19956,19958],{"class":6126,"line":8146},[6124,19949,10534],{"class":9667},[6124,19951,17776],{"class":6479},[6124,19953,19574],{"class":9667},[6124,19955,5787],{"class":6479},[6124,19957,10790],{"class":9667},[6124,19959,6558],{"class":6479},[6124,19961,19962,19965,19967,19969,19971,19973],{"class":6126,"line":10209},[6124,19963,19964],{"class":9667},"        Volume",[6124,19966,17776],{"class":6479},[6124,19968,19574],{"class":9667},[6124,19970,5787],{"class":6479},[6124,19972,19156],{"class":9667},[6124,19974,6558],{"class":6479},[6124,19976,19977,19980,19982,19984,19986,19988],{"class":6126,"line":10242},[6124,19978,19979],{"class":9667},"        Status",[6124,19981,17776],{"class":6479},[6124,19983,18698],{"class":9667},[6124,19985,5787],{"class":6479},[6124,19987,18588],{"class":9667},[6124,19989,6558],{"class":6479},[6124,19991,19992,19995,19997,19999,20001,20003],{"class":6126,"line":10274},[6124,19993,19994],{"class":9667},"        CreatedAt",[6124,19996,6552],{"class":6479},[6124,19998,11641],{"class":9667},[6124,20000,5787],{"class":6479},[6124,20002,11646],{"class":9578},[6124,20004,19931],{"class":6479},[6124,20006,20007,20010,20012,20014,20016,20018],{"class":6126,"line":10279},[6124,20008,20009],{"class":9667},"        UpdatedAt",[6124,20011,6552],{"class":6479},[6124,20013,11641],{"class":9667},[6124,20015,5787],{"class":6479},[6124,20017,11646],{"class":9578},[6124,20019,19931],{"class":6479},[6124,20021,20022],{"class":6126,"line":10284},[6124,20023,10545],{"class":6479},[6124,20025,20026],{"class":6126,"line":10289},[6124,20027,6149],{"emptyLinePlaceholder":6148},[6124,20029,20030,20032,20034,20036,20039,20041,20043,20045,20047,20049,20051,20053,20055,20057,20059,20061,20063],{"class":6126,"line":10321},[6124,20031,10551],{"class":6476},[6124,20033,10554],{"class":9667},[6124,20035,9671],{"class":6479},[6124,20037,20038],{"class":9667},"s",[6124,20040,5787],{"class":6479},[6124,20042,19679],{"class":9667},[6124,20044,5787],{"class":6479},[6124,20046,8394],{"class":9578},[6124,20048,9704],{"class":6479},[6124,20050,12329],{"class":9667},[6124,20052,17478],{"class":6479},[6124,20054,18764],{"class":9667},[6124,20056,10587],{"class":6479},[6124,20058,10590],{"class":9667},[6124,20060,10593],{"class":6479},[6124,20062,10596],{"class":6483},[6124,20064,10516],{"class":6479},[6124,20066,20067,20069,20071,20073,20075,20077],{"class":6126,"line":10327},[6124,20068,19218],{"class":6476},[6124,20070,19035],{"class":9605},[6124,20072,5787],{"class":6479},[6124,20074,18560],{"class":9605},[6124,20076,19227],{"class":6479},[6124,20078,19230],{"class":9667},[6124,20080,20081],{"class":6126,"line":10353},[6124,20082,10545],{"class":6479},[6124,20084,20085],{"class":6126,"line":10359},[6124,20086,6149],{"emptyLinePlaceholder":6148},[6124,20088,20089,20091,20093,20095],{"class":6126,"line":10365},[6124,20090,11596],{"class":6476},[6124,20092,19032],{"class":9667},[6124,20094,5259],{"class":6479},[6124,20096,19245],{"class":6483},[6124,20098,20099],{"class":6126,"line":10388},[6124,20100,6167],{"class":6479},[5379,20102,20103],{},[5205,20104,20105],{},"4. Delivery Layer (HTTP Handlers):",[5530,20107,20109],{"className":9594,"code":20108,"language":9579,"meta":5538,"style":5538},"\u002F\u002F internal\u002Fdelivery\u002Fhttp\u002Forder_handler.go\npackage http\n\nimport (\n    \"encoding\u002Fjson\"\n    \"net\u002Fhttp\"\n    \"myapp\u002Finternal\u002Fusecase\"\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n)\n\ntype OrderHandler struct {\n    useCase usecase.OrderUseCase\n}\n\nfunc NewOrderHandler(useCase usecase.OrderUseCase) *OrderHandler {\n    return &OrderHandler{useCase: useCase}\n}\n\nfunc (h *OrderHandler) RegisterRoutes(r chi.Router) {\n    r.Get(\"\u002Forders\u002F{id}\", h.Get)\n    r.Post(\"\u002Forders\", h.Create)\n}\n\nfunc (h *OrderHandler) Get(w http.ResponseWriter, r *http.Request) {\n    id := chi.URLParam(r, \"id\")\n\n    order, err := h.useCase.GetOrder(r.Context(), id)\n    if err != nil {\n        http.Error(w, \"Order not found\", http.StatusNotFound)\n        return\n    }\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(order)\n}\n\nfunc (h *OrderHandler) Create(w http.ResponseWriter, r *http.Request) {\n    var req struct {\n        UserID string `json:\"user_id\"`\n        Recipe string `json:\"recipe\"`\n        Volume string `json:\"volume\"`\n    }\n\n    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {\n        http.Error(w, \"Invalid JSON\", http.StatusBadRequest)\n        return\n    }\n\n    dto := usecase.CreateOrderDTO{\n        UserID: req.UserID,\n        Recipe: req.Recipe,\n        Volume: req.Volume,\n    }\n\n    order, err := h.useCase.CreateOrder(r.Context(), dto)\n    if err != nil {\n        http.Error(w, err.Error(), http.StatusBadRequest)\n        return\n    }\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(order)\n}\n",[5288,20110,20111,20116,20123,20127,20133,20137,20141,20146,20150,20154,20158,20169,20182,20186,20190,20215,20233,20237,20241,20271,20295,20317,20321,20325,20365,20388,20392,20426,20438,20465,20469,20473,20477,20499,20521,20525,20529,20569,20579,20587,20595,20603,20607,20611,20651,20677,20681,20685,20689,20706,20720,20734,20748,20752,20756,20790,20802,20832,20836,20840,20844,20866,20884,20906],{"__ignoreMap":5538},[6124,20112,20113],{"class":6126,"line":6127},[6124,20114,20115],{"class":9691},"\u002F\u002F internal\u002Fdelivery\u002Fhttp\u002Forder_handler.go\n",[6124,20117,20118,20120],{"class":6126,"line":6133},[6124,20119,9602],{"class":6483},[6124,20121,20122],{"class":9605}," http\n",[6124,20124,20125],{"class":6126,"line":6139},[6124,20126,6149],{"emptyLinePlaceholder":6148},[6124,20128,20129,20131],{"class":6126,"line":6145},[6124,20130,9615],{"class":6476},[6124,20132,9618],{"class":6479},[6124,20134,20135],{"class":6126,"line":6152},[6124,20136,9623],{"class":6503},[6124,20138,20139],{"class":6126,"line":6158},[6124,20140,9628],{"class":6503},[6124,20142,20143],{"class":6126,"line":6164},[6124,20144,20145],{"class":6503},"    \"myapp\u002Finternal\u002Fusecase\"\n",[6124,20147,20148],{"class":6126,"line":6170},[6124,20149,9637],{"class":6503},[6124,20151,20152],{"class":6126,"line":6175},[6124,20153,9647],{"class":6479},[6124,20155,20156],{"class":6126,"line":6181},[6124,20157,6149],{"emptyLinePlaceholder":6148},[6124,20159,20160,20162,20165,20167],{"class":6126,"line":6187},[6124,20161,14614],{"class":6483},[6124,20163,20164],{"class":9605}," OrderHandler",[6124,20166,10513],{"class":6483},[6124,20168,10516],{"class":6479},[6124,20170,20171,20174,20177,20179],{"class":6126,"line":6193},[6124,20172,20173],{"class":9667},"    useCase",[6124,20175,20176],{"class":9605}," usecase",[6124,20178,5787],{"class":6479},[6124,20180,20181],{"class":9605},"OrderUseCase\n",[6124,20183,20184],{"class":6126,"line":6199},[6124,20185,6167],{"class":6479},[6124,20187,20188],{"class":6126,"line":6204},[6124,20189,6149],{"emptyLinePlaceholder":6148},[6124,20191,20192,20194,20197,20199,20202,20204,20206,20208,20210,20213],{"class":6126,"line":6209},[6124,20193,9656],{"class":6483},[6124,20195,20196],{"class":9578}," NewOrderHandler",[6124,20198,9704],{"class":6479},[6124,20200,20201],{"class":9667},"useCase",[6124,20203,20176],{"class":9605},[6124,20205,5787],{"class":6479},[6124,20207,19690],{"class":9605},[6124,20209,18945],{"class":6479},[6124,20211,20212],{"class":9605},"OrderHandler",[6124,20214,10516],{"class":6479},[6124,20216,20217,20219,20221,20223,20225,20227,20229,20231],{"class":6126,"line":6215},[6124,20218,11596],{"class":6476},[6124,20220,18957],{"class":6479},[6124,20222,20212],{"class":9605},[6124,20224,8747],{"class":6479},[6124,20226,20201],{"class":9667},[6124,20228,6552],{"class":6479},[6124,20230,20201],{"class":9667},[6124,20232,6167],{"class":6479},[6124,20234,20235],{"class":6126,"line":6221},[6124,20236,6167],{"class":6479},[6124,20238,20239],{"class":6126,"line":6227},[6124,20240,6149],{"emptyLinePlaceholder":6148},[6124,20242,20243,20245,20247,20250,20252,20254,20256,20259,20261,20263,20265,20267,20269],{"class":6126,"line":6232},[6124,20244,9656],{"class":6483},[6124,20246,5222],{"class":6479},[6124,20248,20249],{"class":9667},"h ",[6124,20251,15993],{"class":6479},[6124,20253,20212],{"class":9605},[6124,20255,7173],{"class":6479},[6124,20257,20258],{"class":9578},"RegisterRoutes",[6124,20260,9704],{"class":6479},[6124,20262,9806],{"class":9667},[6124,20264,9809],{"class":9605},[6124,20266,5787],{"class":6479},[6124,20268,9814],{"class":9605},[6124,20270,9817],{"class":6479},[6124,20272,20273,20275,20277,20279,20281,20284,20286,20289,20291,20293],{"class":6126,"line":6237},[6124,20274,9668],{"class":9667},[6124,20276,5787],{"class":6479},[6124,20278,9751],{"class":9578},[6124,20280,9704],{"class":6479},[6124,20282,20283],{"class":6503},"\"\u002Forders\u002F{id}\"",[6124,20285,5259],{"class":6479},[6124,20287,20288],{"class":9667},"h",[6124,20290,5787],{"class":6479},[6124,20292,9751],{"class":9667},[6124,20294,9647],{"class":6479},[6124,20296,20297,20299,20301,20303,20305,20307,20309,20311,20313,20315],{"class":6126,"line":6243},[6124,20298,9668],{"class":9667},[6124,20300,5787],{"class":6479},[6124,20302,9847],{"class":9578},[6124,20304,9704],{"class":6479},[6124,20306,9831],{"class":6503},[6124,20308,5259],{"class":6479},[6124,20310,20288],{"class":9667},[6124,20312,5787],{"class":6479},[6124,20314,8394],{"class":9667},[6124,20316,9647],{"class":6479},[6124,20318,20319],{"class":6126,"line":6249},[6124,20320,6167],{"class":6479},[6124,20322,20323],{"class":6126,"line":6255},[6124,20324,6149],{"emptyLinePlaceholder":6148},[6124,20326,20327,20329,20331,20333,20335,20337,20339,20341,20343,20345,20347,20349,20351,20353,20355,20357,20359,20361,20363],{"class":6126,"line":6261},[6124,20328,9656],{"class":6483},[6124,20330,5222],{"class":6479},[6124,20332,20249],{"class":9667},[6124,20334,15993],{"class":6479},[6124,20336,20212],{"class":9605},[6124,20338,7173],{"class":6479},[6124,20340,9751],{"class":9578},[6124,20342,9704],{"class":6479},[6124,20344,9967],{"class":9667},[6124,20346,9970],{"class":9605},[6124,20348,5787],{"class":6479},[6124,20350,9975],{"class":9605},[6124,20352,5259],{"class":6479},[6124,20354,9806],{"class":9667},[6124,20356,9982],{"class":6479},[6124,20358,6469],{"class":9605},[6124,20360,5787],{"class":6479},[6124,20362,9989],{"class":9605},[6124,20364,9817],{"class":6479},[6124,20366,20367,20370,20372,20374,20376,20378,20380,20382,20384,20386],{"class":6126,"line":6267},[6124,20368,20369],{"class":9667},"    id",[6124,20371,9671],{"class":6479},[6124,20373,9674],{"class":9667},[6124,20375,5787],{"class":6479},[6124,20377,10339],{"class":9578},[6124,20379,9704],{"class":6479},[6124,20381,9806],{"class":9667},[6124,20383,5259],{"class":6479},[6124,20385,7599],{"class":6503},[6124,20387,9647],{"class":6479},[6124,20389,20390],{"class":6126,"line":6272},[6124,20391,6149],{"emptyLinePlaceholder":6148},[6124,20393,20394,20396,20398,20400,20402,20404,20406,20408,20410,20412,20414,20416,20418,20420,20422,20424],{"class":6126,"line":6278},[6124,20395,19897],{"class":9667},[6124,20397,5259],{"class":6479},[6124,20399,10590],{"class":9667},[6124,20401,9671],{"class":6479},[6124,20403,20288],{"class":9667},[6124,20405,5787],{"class":6479},[6124,20407,20201],{"class":9667},[6124,20409,5787],{"class":6479},[6124,20411,19737],{"class":9578},[6124,20413,9704],{"class":6479},[6124,20415,9806],{"class":9667},[6124,20417,5787],{"class":6479},[6124,20419,12291],{"class":9578},[6124,20421,12294],{"class":6479},[6124,20423,11232],{"class":9667},[6124,20425,9647],{"class":6479},[6124,20427,20428,20430,20432,20434,20436],{"class":6126,"line":6284},[6124,20429,10551],{"class":6476},[6124,20431,10554],{"class":9667},[6124,20433,10593],{"class":6479},[6124,20435,10596],{"class":6483},[6124,20437,10516],{"class":6479},[6124,20439,20440,20442,20444,20446,20448,20450,20452,20455,20457,20459,20461,20463],{"class":6126,"line":6290},[6124,20441,10604],{"class":9667},[6124,20443,5787],{"class":6479},[6124,20445,10609],{"class":9578},[6124,20447,9704],{"class":6479},[6124,20449,9967],{"class":9667},[6124,20451,5259],{"class":6479},[6124,20453,20454],{"class":6503},"\"Order not found\"",[6124,20456,5259],{"class":6479},[6124,20458,6469],{"class":9667},[6124,20460,5787],{"class":6479},[6124,20462,13798],{"class":9667},[6124,20464,9647],{"class":6479},[6124,20466,20467],{"class":6126,"line":6296},[6124,20468,10635],{"class":6476},[6124,20470,20471],{"class":6126,"line":6301},[6124,20472,10545],{"class":6479},[6124,20474,20475],{"class":6126,"line":6307},[6124,20476,6149],{"emptyLinePlaceholder":6148},[6124,20478,20479,20481,20483,20485,20487,20489,20491,20493,20495,20497],{"class":6126,"line":6313},[6124,20480,9996],{"class":9667},[6124,20482,5787],{"class":6479},[6124,20484,10189],{"class":9578},[6124,20486,10167],{"class":6479},[6124,20488,10194],{"class":9578},[6124,20490,9704],{"class":6479},[6124,20492,10199],{"class":6503},[6124,20494,5259],{"class":6479},[6124,20496,10204],{"class":6503},[6124,20498,9647],{"class":6479},[6124,20500,20501,20503,20505,20507,20509,20511,20513,20515,20517,20519],{"class":6126,"line":6319},[6124,20502,10059],{"class":9667},[6124,20504,5787],{"class":6479},[6124,20506,10064],{"class":9578},[6124,20508,9704],{"class":6479},[6124,20510,9967],{"class":9667},[6124,20512,5407],{"class":6479},[6124,20514,10073],{"class":9578},[6124,20516,9704],{"class":6479},[6124,20518,18764],{"class":9667},[6124,20520,9647],{"class":6479},[6124,20522,20523],{"class":6126,"line":6324},[6124,20524,6167],{"class":6479},[6124,20526,20527],{"class":6126,"line":8100},[6124,20528,6149],{"emptyLinePlaceholder":6148},[6124,20530,20531,20533,20535,20537,20539,20541,20543,20545,20547,20549,20551,20553,20555,20557,20559,20561,20563,20565,20567],{"class":6126,"line":8106},[6124,20532,9656],{"class":6483},[6124,20534,5222],{"class":6479},[6124,20536,20249],{"class":9667},[6124,20538,15993],{"class":6479},[6124,20540,20212],{"class":9605},[6124,20542,7173],{"class":6479},[6124,20544,8394],{"class":9578},[6124,20546,9704],{"class":6479},[6124,20548,9967],{"class":9667},[6124,20550,9970],{"class":9605},[6124,20552,5787],{"class":6479},[6124,20554,9975],{"class":9605},[6124,20556,5259],{"class":6479},[6124,20558,9806],{"class":9667},[6124,20560,9982],{"class":6479},[6124,20562,6469],{"class":9605},[6124,20564,5787],{"class":6479},[6124,20566,9989],{"class":9605},[6124,20568,9817],{"class":6479},[6124,20570,20571,20573,20575,20577],{"class":6126,"line":8112},[6124,20572,10507],{"class":6483},[6124,20574,10510],{"class":9667},[6124,20576,10513],{"class":6483},[6124,20578,10516],{"class":6479},[6124,20580,20581,20583,20585],{"class":6126,"line":8117},[6124,20582,10522],{"class":9667},[6124,20584,10525],{"class":9605},[6124,20586,10528],{"class":6503},[6124,20588,20589,20591,20593],{"class":6126,"line":8123},[6124,20590,10534],{"class":9667},[6124,20592,10525],{"class":9605},[6124,20594,10539],{"class":6503},[6124,20596,20597,20599,20601],{"class":6126,"line":8129},[6124,20598,19964],{"class":9667},[6124,20600,10525],{"class":9605},[6124,20602,16746],{"class":6503},[6124,20604,20605],{"class":6126,"line":8135},[6124,20606,10545],{"class":6479},[6124,20608,20609],{"class":6126,"line":8141},[6124,20610,6149],{"emptyLinePlaceholder":6148},[6124,20612,20613,20615,20617,20619,20621,20623,20625,20627,20629,20631,20633,20635,20637,20639,20641,20643,20645,20647,20649],{"class":6126,"line":8146},[6124,20614,10551],{"class":6476},[6124,20616,10554],{"class":9667},[6124,20618,9671],{"class":6479},[6124,20620,10559],{"class":9667},[6124,20622,5787],{"class":6479},[6124,20624,10564],{"class":9578},[6124,20626,9704],{"class":6479},[6124,20628,9806],{"class":9667},[6124,20630,5787],{"class":6479},[6124,20632,10573],{"class":9667},[6124,20634,5407],{"class":6479},[6124,20636,10578],{"class":9578},[6124,20638,10581],{"class":6479},[6124,20640,10584],{"class":9667},[6124,20642,10587],{"class":6479},[6124,20644,10590],{"class":9667},[6124,20646,10593],{"class":6479},[6124,20648,10596],{"class":6483},[6124,20650,10516],{"class":6479},[6124,20652,20653,20655,20657,20659,20661,20663,20665,20667,20669,20671,20673,20675],{"class":6126,"line":10209},[6124,20654,10604],{"class":9667},[6124,20656,5787],{"class":6479},[6124,20658,10609],{"class":9578},[6124,20660,9704],{"class":6479},[6124,20662,9967],{"class":9667},[6124,20664,5259],{"class":6479},[6124,20666,10618],{"class":6503},[6124,20668,5259],{"class":6479},[6124,20670,6469],{"class":9667},[6124,20672,5787],{"class":6479},[6124,20674,10627],{"class":9667},[6124,20676,9647],{"class":6479},[6124,20678,20679],{"class":6126,"line":10242},[6124,20680,10635],{"class":6476},[6124,20682,20683],{"class":6126,"line":10274},[6124,20684,10545],{"class":6479},[6124,20686,20687],{"class":6126,"line":10279},[6124,20688,6149],{"emptyLinePlaceholder":6148},[6124,20690,20691,20694,20696,20699,20701,20704],{"class":6126,"line":10284},[6124,20692,20693],{"class":9667},"    dto",[6124,20695,9671],{"class":6479},[6124,20697,20698],{"class":9605},"usecase",[6124,20700,5787],{"class":6479},[6124,20702,20703],{"class":9605},"CreateOrderDTO",[6124,20705,6543],{"class":6479},[6124,20707,20708,20710,20712,20714,20716,20718],{"class":6126,"line":10289},[6124,20709,10522],{"class":9667},[6124,20711,6552],{"class":6479},[6124,20713,10584],{"class":9667},[6124,20715,5787],{"class":6479},[6124,20717,10773],{"class":9667},[6124,20719,6558],{"class":6479},[6124,20721,20722,20724,20726,20728,20730,20732],{"class":6126,"line":10321},[6124,20723,10534],{"class":9667},[6124,20725,6552],{"class":6479},[6124,20727,10584],{"class":9667},[6124,20729,5787],{"class":6479},[6124,20731,10790],{"class":9667},[6124,20733,6558],{"class":6479},[6124,20735,20736,20738,20740,20742,20744,20746],{"class":6126,"line":10327},[6124,20737,19964],{"class":9667},[6124,20739,6552],{"class":6479},[6124,20741,10584],{"class":9667},[6124,20743,5787],{"class":6479},[6124,20745,19156],{"class":9667},[6124,20747,6558],{"class":6479},[6124,20749,20750],{"class":6126,"line":10353},[6124,20751,10545],{"class":6479},[6124,20753,20754],{"class":6126,"line":10359},[6124,20755,6149],{"emptyLinePlaceholder":6148},[6124,20757,20758,20760,20762,20764,20766,20768,20770,20772,20774,20776,20778,20780,20782,20784,20786,20788],{"class":6126,"line":10365},[6124,20759,19897],{"class":9667},[6124,20761,5259],{"class":6479},[6124,20763,10590],{"class":9667},[6124,20765,9671],{"class":6479},[6124,20767,20288],{"class":9667},[6124,20769,5787],{"class":6479},[6124,20771,20201],{"class":9667},[6124,20773,5787],{"class":6479},[6124,20775,19817],{"class":9578},[6124,20777,9704],{"class":6479},[6124,20779,9806],{"class":9667},[6124,20781,5787],{"class":6479},[6124,20783,12291],{"class":9578},[6124,20785,12294],{"class":6479},[6124,20787,19574],{"class":9667},[6124,20789,9647],{"class":6479},[6124,20791,20792,20794,20796,20798,20800],{"class":6126,"line":10388},[6124,20793,10551],{"class":6476},[6124,20795,10554],{"class":9667},[6124,20797,10593],{"class":6479},[6124,20799,10596],{"class":6483},[6124,20801,10516],{"class":6479},[6124,20803,20804,20806,20808,20810,20812,20814,20816,20818,20820,20822,20824,20826,20828,20830],{"class":6126,"line":10419},[6124,20805,10604],{"class":9667},[6124,20807,5787],{"class":6479},[6124,20809,10609],{"class":9578},[6124,20811,9704],{"class":6479},[6124,20813,9967],{"class":9667},[6124,20815,5259],{"class":6479},[6124,20817,10590],{"class":9667},[6124,20819,5787],{"class":6479},[6124,20821,10609],{"class":9578},[6124,20823,12294],{"class":6479},[6124,20825,6469],{"class":9667},[6124,20827,5787],{"class":6479},[6124,20829,10627],{"class":9667},[6124,20831,9647],{"class":6479},[6124,20833,20834],{"class":6126,"line":10433},[6124,20835,10635],{"class":6476},[6124,20837,20838],{"class":6126,"line":10445},[6124,20839,10545],{"class":6479},[6124,20841,20842],{"class":6126,"line":10457},[6124,20843,6149],{"emptyLinePlaceholder":6148},[6124,20845,20846,20848,20850,20852,20854,20856,20858,20860,20862,20864],{"class":6126,"line":10462},[6124,20847,9996],{"class":9667},[6124,20849,5787],{"class":6479},[6124,20851,10189],{"class":9578},[6124,20853,10167],{"class":6479},[6124,20855,10194],{"class":9578},[6124,20857,9704],{"class":6479},[6124,20859,10199],{"class":6503},[6124,20861,5259],{"class":6479},[6124,20863,10204],{"class":6503},[6124,20865,9647],{"class":6479},[6124,20867,20868,20870,20872,20874,20876,20878,20880,20882],{"class":6126,"line":10467},[6124,20869,9996],{"class":9667},[6124,20871,5787],{"class":6479},[6124,20873,10681],{"class":9578},[6124,20875,9704],{"class":6479},[6124,20877,6469],{"class":9667},[6124,20879,5787],{"class":6479},[6124,20881,10690],{"class":9667},[6124,20883,9647],{"class":6479},[6124,20885,20886,20888,20890,20892,20894,20896,20898,20900,20902,20904],{"class":6126,"line":10472},[6124,20887,10059],{"class":9667},[6124,20889,5787],{"class":6479},[6124,20891,10064],{"class":9578},[6124,20893,9704],{"class":6479},[6124,20895,9967],{"class":9667},[6124,20897,5407],{"class":6479},[6124,20899,10073],{"class":9578},[6124,20901,9704],{"class":6479},[6124,20903,18764],{"class":9667},[6124,20905,9647],{"class":6479},[6124,20907,20908],{"class":6126,"line":10504},[6124,20909,6167],{"class":6479},[5374,20911,20913],{"id":20912},"dependency-injection-звязування-шарів","Dependency Injection: зв'язування шарів",[5379,20915,20916],{},[5205,20917,20918],{},"Точка входу (main.go):",[5530,20920,20922],{"className":9594,"code":20921,"language":9579,"meta":5538,"style":5538},"\u002F\u002F cmd\u002Fserver\u002Fmain.go\npackage main\n\nimport (\n    \"context\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"os\u002Fsignal\"\n    \"syscall\"\n    \"time\"\n\n    \"myapp\u002Finternal\u002Fdelivery\u002Fhttp\u002Fhandler\"\n    \"myapp\u002Finternal\u002Frepository\u002Fpostgres\"\n    \"myapp\u002Finternal\u002Fusecase\"\n\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\u002Fmiddleware\"\n    \"github.com\u002Fjackc\u002Fpgx\u002Fv5\u002Fpgxpool\"\n)\n\nfunc main() {\n    \u002F\u002F Підключення до бази даних\n    dbURL := os.Getenv(\"DATABASE_URL\")\n    if dbURL == \"\" {\n        log.Fatal(\"DATABASE_URL not set\")\n    }\n\n    pool, err := pgxpool.New(context.Background(), dbURL)\n    if err != nil {\n        log.Fatalf(\"Unable to connect to database: %v\", err)\n    }\n    defer pool.Close()\n\n    \u002F\u002F Ініціалізація шарів (Dependency Injection)\n    orderRepo := postgres.NewOrderRepository(pool)\n    orderUseCase := usecase.NewOrderService(orderRepo)\n    orderHandler := handler.NewOrderHandler(orderUseCase)\n\n    \u002F\u002F Налаштування роутера\n    r := chi.NewRouter()\n    r.Use(middleware.Logger)\n    r.Use(middleware.Recoverer)\n    r.Use(middleware.RequestID)\n    r.Use(middleware.Timeout(60 * time.Second))\n\n    \u002F\u002F Реєстрація маршрутів\n    r.Get(\"\u002Fhealth\", healthCheckHandler)\n    r.Route(\"\u002Fv1\", func(r chi.Router) {\n        orderHandler.RegisterRoutes(r)\n    })\n\n    \u002F\u002F Налаштування сервера з Graceful Shutdown\n    srv := &http.Server{\n        Addr:         \":8080\",\n        Handler:      r,\n        ReadTimeout:  15 * time.Second,\n        WriteTimeout: 15 * time.Second,\n        IdleTimeout:  60 * time.Second,\n    }\n\n    \u002F\u002F Запуск сервера у горутині\n    go func() {\n        log.Printf(\"🚀 Server starting on %s\", srv.Addr)\n        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {\n            log.Fatalf(\"Server failed: %v\", err)\n        }\n    }()\n\n    \u002F\u002F Очікування сигналу завершення\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n    \u003C-quit\n\n    log.Println(\"⏳ Shutting down server...\")\n\n    \u002F\u002F Graceful Shutdown з таймаутом 30 секунд\n    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n\n    if err := srv.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Server forced to shutdown: %v\", err)\n    }\n\n    log.Println(\"✅ Server stopped gracefully\")\n}\n\nfunc healthCheckHandler(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    w.WriteHeader(http.StatusOK)\n    w.Write([]byte(`{\"status\":\"healthy\",\"timestamp\":\"` + time.Now().Format(time.RFC3339) + `\"}`))\n}\n",[5288,20923,20924,20929,20935,20939,20945,20949,20953,20957,20961,20965,20969,20973,20977,20982,20987,20991,20995,20999,21003,21007,21011,21015,21023,21028,21050,21063,21079,21083,21087,21119,21131,21154,21158,21171,21175,21180,21202,21223,21245,21249,21254,21268,21286,21304,21322,21352,21356,21361,21379,21407,21422,21426,21430,21435,21449,21459,21469,21487,21505,21523,21527,21531,21536,21544,21570,21606,21629,21633,21637,21641,21646,21670,21700,21706,21710,21724,21728,21733,21771,21779,21783,21811,21833,21837,21841,21855,21859,21863,21893,21915,21933,21979],{"__ignoreMap":5538},[6124,20925,20926],{"class":6126,"line":6127},[6124,20927,20928],{"class":9691},"\u002F\u002F cmd\u002Fserver\u002Fmain.go\n",[6124,20930,20931,20933],{"class":6126,"line":6133},[6124,20932,9602],{"class":6483},[6124,20934,9606],{"class":9605},[6124,20936,20937],{"class":6126,"line":6139},[6124,20938,6149],{"emptyLinePlaceholder":6148},[6124,20940,20941,20943],{"class":6126,"line":6145},[6124,20942,9615],{"class":6476},[6124,20944,9618],{"class":6479},[6124,20946,20947],{"class":6126,"line":6152},[6124,20948,14897],{"class":6503},[6124,20950,20951],{"class":6126,"line":6158},[6124,20952,14906],{"class":6503},[6124,20954,20955],{"class":6126,"line":6164},[6124,20956,9628],{"class":6503},[6124,20958,20959],{"class":6126,"line":6170},[6124,20960,14915],{"class":6503},[6124,20962,20963],{"class":6126,"line":6175},[6124,20964,14920],{"class":6503},[6124,20966,20967],{"class":6126,"line":6181},[6124,20968,14925],{"class":6503},[6124,20970,20971],{"class":6126,"line":6187},[6124,20972,14930],{"class":6503},[6124,20974,20975],{"class":6126,"line":6193},[6124,20976,6149],{"emptyLinePlaceholder":6148},[6124,20978,20979],{"class":6126,"line":6199},[6124,20980,20981],{"class":6503},"    \"myapp\u002Finternal\u002Fdelivery\u002Fhttp\u002Fhandler\"\n",[6124,20983,20984],{"class":6126,"line":6204},[6124,20985,20986],{"class":6503},"    \"myapp\u002Finternal\u002Frepository\u002Fpostgres\"\n",[6124,20988,20989],{"class":6126,"line":6209},[6124,20990,20145],{"class":6503},[6124,20992,20993],{"class":6126,"line":6215},[6124,20994,6149],{"emptyLinePlaceholder":6148},[6124,20996,20997],{"class":6126,"line":6221},[6124,20998,9637],{"class":6503},[6124,21000,21001],{"class":6126,"line":6227},[6124,21002,9642],{"class":6503},[6124,21004,21005],{"class":6126,"line":6232},[6124,21006,18880],{"class":6503},[6124,21008,21009],{"class":6126,"line":6237},[6124,21010,9647],{"class":6479},[6124,21012,21013],{"class":6126,"line":6243},[6124,21014,6149],{"emptyLinePlaceholder":6148},[6124,21016,21017,21019,21021],{"class":6126,"line":6249},[6124,21018,9656],{"class":6483},[6124,21020,9659],{"class":9578},[6124,21022,9662],{"class":6479},[6124,21024,21025],{"class":6126,"line":6255},[6124,21026,21027],{"class":9691},"    \u002F\u002F Підключення до бази даних\n",[6124,21029,21030,21033,21035,21038,21040,21043,21045,21048],{"class":6126,"line":6261},[6124,21031,21032],{"class":9667},"    dbURL",[6124,21034,9671],{"class":6479},[6124,21036,21037],{"class":9667},"os",[6124,21039,5787],{"class":6479},[6124,21041,21042],{"class":9578},"Getenv",[6124,21044,9704],{"class":6479},[6124,21046,21047],{"class":6503},"\"DATABASE_URL\"",[6124,21049,9647],{"class":6479},[6124,21051,21052,21054,21057,21059,21061],{"class":6126,"line":6267},[6124,21053,10551],{"class":6476},[6124,21055,21056],{"class":9667}," dbURL",[6124,21058,11964],{"class":6479},[6124,21060,12143],{"class":6503},[6124,21062,10516],{"class":6479},[6124,21064,21065,21067,21069,21072,21074,21077],{"class":6126,"line":6272},[6124,21066,11713],{"class":9667},[6124,21068,5787],{"class":6479},[6124,21070,21071],{"class":9578},"Fatal",[6124,21073,9704],{"class":6479},[6124,21075,21076],{"class":6503},"\"DATABASE_URL not set\"",[6124,21078,9647],{"class":6479},[6124,21080,21081],{"class":6126,"line":6278},[6124,21082,10545],{"class":6479},[6124,21084,21085],{"class":6126,"line":6284},[6124,21086,6149],{"emptyLinePlaceholder":6148},[6124,21088,21089,21092,21094,21096,21098,21100,21102,21104,21106,21108,21110,21112,21114,21117],{"class":6126,"line":6290},[6124,21090,21091],{"class":9667},"    pool",[6124,21093,5259],{"class":6479},[6124,21095,10590],{"class":9667},[6124,21097,9671],{"class":6479},[6124,21099,18908],{"class":9667},[6124,21101,5787],{"class":6479},[6124,21103,19923],{"class":9578},[6124,21105,9704],{"class":6479},[6124,21107,5349],{"class":9667},[6124,21109,5787],{"class":6479},[6124,21111,15986],{"class":9578},[6124,21113,12294],{"class":6479},[6124,21115,21116],{"class":9667},"dbURL",[6124,21118,9647],{"class":6479},[6124,21120,21121,21123,21125,21127,21129],{"class":6126,"line":6296},[6124,21122,10551],{"class":6476},[6124,21124,10554],{"class":9667},[6124,21126,10593],{"class":6479},[6124,21128,10596],{"class":6483},[6124,21130,10516],{"class":6479},[6124,21132,21133,21135,21137,21139,21141,21144,21146,21148,21150,21152],{"class":6126,"line":6301},[6124,21134,11713],{"class":9667},[6124,21136,5787],{"class":6479},[6124,21138,15831],{"class":9578},[6124,21140,9704],{"class":6479},[6124,21142,21143],{"class":6503},"\"Unable to connect to database: ",[6124,21145,15839],{"class":9667},[6124,21147,11182],{"class":6503},[6124,21149,5259],{"class":6479},[6124,21151,10590],{"class":9667},[6124,21153,9647],{"class":6479},[6124,21155,21156],{"class":6126,"line":6307},[6124,21157,10545],{"class":6479},[6124,21159,21160,21162,21165,21167,21169],{"class":6126,"line":6313},[6124,21161,10646],{"class":6476},[6124,21163,21164],{"class":9667}," pool",[6124,21166,5787],{"class":6479},[6124,21168,10658],{"class":9578},[6124,21170,9682],{"class":6479},[6124,21172,21173],{"class":6126,"line":6319},[6124,21174,6149],{"emptyLinePlaceholder":6148},[6124,21176,21177],{"class":6126,"line":6324},[6124,21178,21179],{"class":9691},"    \u002F\u002F Ініціалізація шарів (Dependency Injection)\n",[6124,21181,21182,21185,21187,21190,21192,21195,21197,21200],{"class":6126,"line":8100},[6124,21183,21184],{"class":9667},"    orderRepo",[6124,21186,9671],{"class":6479},[6124,21188,21189],{"class":9667},"postgres",[6124,21191,5787],{"class":6479},[6124,21193,21194],{"class":9578},"NewOrderRepository",[6124,21196,9704],{"class":6479},[6124,21198,21199],{"class":9667},"pool",[6124,21201,9647],{"class":6479},[6124,21203,21204,21207,21209,21211,21213,21216,21218,21221],{"class":6126,"line":8106},[6124,21205,21206],{"class":9667},"    orderUseCase",[6124,21208,9671],{"class":6479},[6124,21210,20698],{"class":9667},[6124,21212,5787],{"class":6479},[6124,21214,21215],{"class":9578},"NewOrderService",[6124,21217,9704],{"class":6479},[6124,21219,21220],{"class":9667},"orderRepo",[6124,21222,9647],{"class":6479},[6124,21224,21225,21228,21230,21233,21235,21238,21240,21243],{"class":6126,"line":8112},[6124,21226,21227],{"class":9667},"    orderHandler",[6124,21229,9671],{"class":6479},[6124,21231,21232],{"class":9667},"handler",[6124,21234,5787],{"class":6479},[6124,21236,21237],{"class":9578},"NewOrderHandler",[6124,21239,9704],{"class":6479},[6124,21241,21242],{"class":9667},"orderUseCase",[6124,21244,9647],{"class":6479},[6124,21246,21247],{"class":6126,"line":8117},[6124,21248,6149],{"emptyLinePlaceholder":6148},[6124,21250,21251],{"class":6126,"line":8123},[6124,21252,21253],{"class":9691},"    \u002F\u002F Налаштування роутера\n",[6124,21255,21256,21258,21260,21262,21264,21266],{"class":6126,"line":8129},[6124,21257,9668],{"class":9667},[6124,21259,9671],{"class":6479},[6124,21261,9674],{"class":9667},[6124,21263,5787],{"class":6479},[6124,21265,9679],{"class":9578},[6124,21267,9682],{"class":6479},[6124,21269,21270,21272,21274,21276,21278,21280,21282,21284],{"class":6126,"line":8135},[6124,21271,9668],{"class":9667},[6124,21273,5787],{"class":6479},[6124,21275,9701],{"class":9578},[6124,21277,9704],{"class":6479},[6124,21279,9707],{"class":9667},[6124,21281,5787],{"class":6479},[6124,21283,9712],{"class":9667},[6124,21285,9647],{"class":6479},[6124,21287,21288,21290,21292,21294,21296,21298,21300,21302],{"class":6126,"line":8141},[6124,21289,9668],{"class":9667},[6124,21291,5787],{"class":6479},[6124,21293,9701],{"class":9578},[6124,21295,9704],{"class":6479},[6124,21297,9707],{"class":9667},[6124,21299,5787],{"class":6479},[6124,21301,9731],{"class":9667},[6124,21303,9647],{"class":6479},[6124,21305,21306,21308,21310,21312,21314,21316,21318,21320],{"class":6126,"line":8146},[6124,21307,9668],{"class":9667},[6124,21309,5787],{"class":6479},[6124,21311,9701],{"class":9578},[6124,21313,9704],{"class":6479},[6124,21315,9707],{"class":9667},[6124,21317,5787],{"class":6479},[6124,21319,12464],{"class":9667},[6124,21321,9647],{"class":6479},[6124,21323,21324,21326,21328,21330,21332,21334,21336,21338,21340,21342,21344,21346,21348,21350],{"class":6126,"line":10209},[6124,21325,9668],{"class":9667},[6124,21327,5787],{"class":6479},[6124,21329,9701],{"class":9578},[6124,21331,9704],{"class":6479},[6124,21333,9707],{"class":9667},[6124,21335,5787],{"class":6479},[6124,21337,12520],{"class":9578},[6124,21339,9704],{"class":6479},[6124,21341,12525],{"class":6490},[6124,21343,12528],{"class":6479},[6124,21345,11641],{"class":9667},[6124,21347,5787],{"class":6479},[6124,21349,12535],{"class":9667},[6124,21351,10015],{"class":6479},[6124,21353,21354],{"class":6126,"line":10242},[6124,21355,6149],{"emptyLinePlaceholder":6148},[6124,21357,21358],{"class":6126,"line":10274},[6124,21359,21360],{"class":9691},"    \u002F\u002F Реєстрація маршрутів\n",[6124,21362,21363,21365,21367,21369,21371,21373,21375,21377],{"class":6126,"line":10279},[6124,21364,9668],{"class":9667},[6124,21366,5787],{"class":6479},[6124,21368,9751],{"class":9578},[6124,21370,9704],{"class":6479},[6124,21372,9776],{"class":6503},[6124,21374,5259],{"class":6479},[6124,21376,9781],{"class":9667},[6124,21378,9647],{"class":6479},[6124,21380,21381,21383,21385,21387,21389,21391,21393,21395,21397,21399,21401,21403,21405],{"class":6126,"line":10284},[6124,21382,9668],{"class":9667},[6124,21384,5787],{"class":6479},[6124,21386,9792],{"class":9578},[6124,21388,9704],{"class":6479},[6124,21390,9797],{"class":6503},[6124,21392,5259],{"class":6479},[6124,21394,9656],{"class":6483},[6124,21396,9704],{"class":6479},[6124,21398,9806],{"class":9667},[6124,21400,9809],{"class":9605},[6124,21402,5787],{"class":6479},[6124,21404,9814],{"class":9605},[6124,21406,9817],{"class":6479},[6124,21408,21409,21412,21414,21416,21418,21420],{"class":6126,"line":10289},[6124,21410,21411],{"class":9667},"        orderHandler",[6124,21413,5787],{"class":6479},[6124,21415,20258],{"class":9578},[6124,21417,9704],{"class":6479},[6124,21419,9806],{"class":9667},[6124,21421,9647],{"class":6479},[6124,21423,21424],{"class":6126,"line":10321},[6124,21425,9922],{"class":6479},[6124,21427,21428],{"class":6126,"line":10327},[6124,21429,6149],{"emptyLinePlaceholder":6148},[6124,21431,21432],{"class":6126,"line":10353},[6124,21433,21434],{"class":9691},"    \u002F\u002F Налаштування сервера з Graceful Shutdown\n",[6124,21436,21437,21439,21441,21443,21445,21447],{"class":6126,"line":10359},[6124,21438,15642],{"class":9667},[6124,21440,15645],{"class":6479},[6124,21442,6469],{"class":9605},[6124,21444,5787],{"class":6479},[6124,21446,15652],{"class":9605},[6124,21448,6543],{"class":6479},[6124,21450,21451,21453,21455,21457],{"class":6126,"line":10365},[6124,21452,15659],{"class":9667},[6124,21454,15662],{"class":6479},[6124,21456,9941],{"class":6503},[6124,21458,6558],{"class":6479},[6124,21460,21461,21463,21465,21467],{"class":6126,"line":10388},[6124,21462,15671],{"class":9667},[6124,21464,10754],{"class":6479},[6124,21466,9806],{"class":9667},[6124,21468,6558],{"class":6479},[6124,21470,21471,21473,21475,21477,21479,21481,21483,21485],{"class":6126,"line":10419},[6124,21472,15682],{"class":9667},[6124,21474,10783],{"class":6479},[6124,21476,15687],{"class":6490},[6124,21478,12528],{"class":6479},[6124,21480,11641],{"class":9667},[6124,21482,5787],{"class":6479},[6124,21484,12535],{"class":9667},[6124,21486,6558],{"class":6479},[6124,21488,21489,21491,21493,21495,21497,21499,21501,21503],{"class":6126,"line":10433},[6124,21490,15702],{"class":9667},[6124,21492,6552],{"class":6479},[6124,21494,15687],{"class":6490},[6124,21496,12528],{"class":6479},[6124,21498,11641],{"class":9667},[6124,21500,5787],{"class":6479},[6124,21502,12535],{"class":9667},[6124,21504,6558],{"class":6479},[6124,21506,21507,21509,21511,21513,21515,21517,21519,21521],{"class":6126,"line":10445},[6124,21508,15721],{"class":9667},[6124,21510,10783],{"class":6479},[6124,21512,12525],{"class":6490},[6124,21514,12528],{"class":6479},[6124,21516,11641],{"class":9667},[6124,21518,5787],{"class":6479},[6124,21520,12535],{"class":9667},[6124,21522,6558],{"class":6479},[6124,21524,21525],{"class":6126,"line":10457},[6124,21526,10545],{"class":6479},[6124,21528,21529],{"class":6126,"line":10462},[6124,21530,6149],{"emptyLinePlaceholder":6148},[6124,21532,21533],{"class":6126,"line":10467},[6124,21534,21535],{"class":9691},"    \u002F\u002F Запуск сервера у горутині\n",[6124,21537,21538,21540,21542],{"class":6126,"line":10472},[6124,21539,15748],{"class":6476},[6124,21541,15751],{"class":6483},[6124,21543,9662],{"class":6479},[6124,21545,21546,21548,21550,21552,21554,21556,21558,21560,21562,21564,21566,21568],{"class":6126,"line":10504},[6124,21547,11713],{"class":9667},[6124,21549,5787],{"class":6479},[6124,21551,11718],{"class":9578},[6124,21553,9704],{"class":6479},[6124,21555,15766],{"class":6503},[6124,21557,11179],{"class":9667},[6124,21559,11182],{"class":6503},[6124,21561,5259],{"class":6479},[6124,21563,15775],{"class":9667},[6124,21565,5787],{"class":6479},[6124,21567,15780],{"class":9667},[6124,21569,9647],{"class":6479},[6124,21571,21572,21574,21576,21578,21580,21582,21584,21586,21588,21590,21592,21594,21596,21598,21600,21602,21604],{"class":6126,"line":10519},[6124,21573,11955],{"class":6476},[6124,21575,10554],{"class":9667},[6124,21577,9671],{"class":6479},[6124,21579,15775],{"class":9667},[6124,21581,5787],{"class":6479},[6124,21583,9936],{"class":9578},[6124,21585,15799],{"class":6479},[6124,21587,10590],{"class":9667},[6124,21589,10593],{"class":6479},[6124,21591,10596],{"class":6483},[6124,21593,15808],{"class":6479},[6124,21595,10590],{"class":9667},[6124,21597,10593],{"class":6479},[6124,21599,6469],{"class":9667},[6124,21601,5787],{"class":6479},[6124,21603,15819],{"class":9667},[6124,21605,10516],{"class":6479},[6124,21607,21608,21610,21612,21614,21616,21619,21621,21623,21625,21627],{"class":6126,"line":10531},[6124,21609,15826],{"class":9667},[6124,21611,5787],{"class":6479},[6124,21613,15831],{"class":9578},[6124,21615,9704],{"class":6479},[6124,21617,21618],{"class":6503},"\"Server failed: ",[6124,21620,15839],{"class":9667},[6124,21622,11182],{"class":6503},[6124,21624,5259],{"class":6479},[6124,21626,10590],{"class":9667},[6124,21628,9647],{"class":6479},[6124,21630,21631],{"class":6126,"line":10542},[6124,21632,12002],{"class":6479},[6124,21634,21635],{"class":6126,"line":10548},[6124,21636,15856],{"class":6479},[6124,21638,21639],{"class":6126,"line":10601},[6124,21640,6149],{"emptyLinePlaceholder":6148},[6124,21642,21643],{"class":6126,"line":10632},[6124,21644,21645],{"class":9691},"    \u002F\u002F Очікування сигналу завершення\n",[6124,21647,21648,21650,21652,21654,21656,21658,21660,21662,21664,21666,21668],{"class":6126,"line":10638},[6124,21649,15870],{"class":9667},[6124,21651,9671],{"class":6479},[6124,21653,15875],{"class":9578},[6124,21655,9704],{"class":6479},[6124,21657,15880],{"class":6483},[6124,21659,15883],{"class":9605},[6124,21661,5787],{"class":6479},[6124,21663,15888],{"class":9605},[6124,21665,5259],{"class":6479},[6124,21667,8576],{"class":6490},[6124,21669,9647],{"class":6479},[6124,21671,21672,21674,21676,21678,21680,21682,21684,21686,21688,21690,21692,21694,21696,21698],{"class":6126,"line":10643},[6124,21673,15899],{"class":9667},[6124,21675,5787],{"class":6479},[6124,21677,15904],{"class":9578},[6124,21679,9704],{"class":6479},[6124,21681,15909],{"class":9667},[6124,21683,5259],{"class":6479},[6124,21685,15914],{"class":9667},[6124,21687,5787],{"class":6479},[6124,21689,15919],{"class":9667},[6124,21691,5259],{"class":6479},[6124,21693,15914],{"class":9667},[6124,21695,5787],{"class":6479},[6124,21697,15928],{"class":9667},[6124,21699,9647],{"class":6479},[6124,21701,21702,21704],{"class":6126,"line":10663},[6124,21703,15935],{"class":6479},[6124,21705,15938],{"class":9667},[6124,21707,21708],{"class":6126,"line":10668},[6124,21709,6149],{"emptyLinePlaceholder":6148},[6124,21711,21712,21714,21716,21718,21720,21722],{"class":6126,"line":10674},[6124,21713,12806],{"class":9667},[6124,21715,5787],{"class":6479},[6124,21717,15951],{"class":9578},[6124,21719,9704],{"class":6479},[6124,21721,15956],{"class":6503},[6124,21723,9647],{"class":6479},[6124,21725,21726],{"class":6126,"line":10695},[6124,21727,6149],{"emptyLinePlaceholder":6148},[6124,21729,21730],{"class":6126,"line":10718},[6124,21731,21732],{"class":9691},"    \u002F\u002F Graceful Shutdown з таймаутом 30 секунд\n",[6124,21734,21735,21737,21739,21741,21743,21745,21747,21749,21751,21753,21755,21757,21759,21761,21763,21765,21767,21769],{"class":6126,"line":10749},[6124,21736,15963],{"class":9667},[6124,21738,5259],{"class":6479},[6124,21740,15968],{"class":9667},[6124,21742,9671],{"class":6479},[6124,21744,5349],{"class":9667},[6124,21746,5787],{"class":6479},[6124,21748,15977],{"class":9578},[6124,21750,9704],{"class":6479},[6124,21752,5349],{"class":9667},[6124,21754,5787],{"class":6479},[6124,21756,15986],{"class":9578},[6124,21758,12294],{"class":6479},[6124,21760,13056],{"class":6490},[6124,21762,15993],{"class":6479},[6124,21764,11641],{"class":9667},[6124,21766,5787],{"class":6479},[6124,21768,12535],{"class":9667},[6124,21770,9647],{"class":6479},[6124,21772,21773,21775,21777],{"class":6126,"line":10761},[6124,21774,10646],{"class":6476},[6124,21776,16008],{"class":9578},[6124,21778,9682],{"class":6479},[6124,21780,21781],{"class":6126,"line":10778},[6124,21782,6149],{"emptyLinePlaceholder":6148},[6124,21784,21785,21787,21789,21791,21793,21795,21797,21799,21801,21803,21805,21807,21809],{"class":6126,"line":10795},[6124,21786,10551],{"class":6476},[6124,21788,10554],{"class":9667},[6124,21790,9671],{"class":6479},[6124,21792,15775],{"class":9667},[6124,21794,5787],{"class":6479},[6124,21796,16029],{"class":9578},[6124,21798,9704],{"class":6479},[6124,21800,12329],{"class":9667},[6124,21802,10587],{"class":6479},[6124,21804,10590],{"class":9667},[6124,21806,10593],{"class":6479},[6124,21808,10596],{"class":6483},[6124,21810,10516],{"class":6479},[6124,21812,21813,21815,21817,21819,21821,21823,21825,21827,21829,21831],{"class":6126,"line":10806},[6124,21814,11713],{"class":9667},[6124,21816,5787],{"class":6479},[6124,21818,15831],{"class":9578},[6124,21820,9704],{"class":6479},[6124,21822,16056],{"class":6503},[6124,21824,15839],{"class":9667},[6124,21826,11182],{"class":6503},[6124,21828,5259],{"class":6479},[6124,21830,10590],{"class":9667},[6124,21832,9647],{"class":6479},[6124,21834,21835],{"class":6126,"line":10811},[6124,21836,10545],{"class":6479},[6124,21838,21839],{"class":6126,"line":10816},[6124,21840,6149],{"emptyLinePlaceholder":6148},[6124,21842,21843,21845,21847,21849,21851,21853],{"class":6126,"line":10821},[6124,21844,12806],{"class":9667},[6124,21846,5787],{"class":6479},[6124,21848,15951],{"class":9578},[6124,21850,9704],{"class":6479},[6124,21852,16087],{"class":6503},[6124,21854,9647],{"class":6479},[6124,21856,21857],{"class":6126,"line":10853},[6124,21858,6167],{"class":6479},[6124,21860,21861],{"class":6126,"line":10876},[6124,21862,6149],{"emptyLinePlaceholder":6148},[6124,21864,21865,21867,21869,21871,21873,21875,21877,21879,21881,21883,21885,21887,21889,21891],{"class":6126,"line":10882},[6124,21866,9656],{"class":6483},[6124,21868,10030],{"class":9578},[6124,21870,9704],{"class":6479},[6124,21872,9967],{"class":9667},[6124,21874,9970],{"class":9605},[6124,21876,5787],{"class":6479},[6124,21878,9975],{"class":9605},[6124,21880,5259],{"class":6479},[6124,21882,9806],{"class":9667},[6124,21884,9982],{"class":6479},[6124,21886,6469],{"class":9605},[6124,21888,5787],{"class":6479},[6124,21890,9989],{"class":9605},[6124,21892,9817],{"class":6479},[6124,21894,21895,21897,21899,21901,21903,21905,21907,21909,21911,21913],{"class":6126,"line":10902},[6124,21896,9996],{"class":9667},[6124,21898,5787],{"class":6479},[6124,21900,10189],{"class":9578},[6124,21902,10167],{"class":6479},[6124,21904,10194],{"class":9578},[6124,21906,9704],{"class":6479},[6124,21908,10199],{"class":6503},[6124,21910,5259],{"class":6479},[6124,21912,10204],{"class":6503},[6124,21914,9647],{"class":6479},[6124,21916,21917,21919,21921,21923,21925,21927,21929,21931],{"class":6126,"line":10950},[6124,21918,9996],{"class":9667},[6124,21920,5787],{"class":6479},[6124,21922,10681],{"class":9578},[6124,21924,9704],{"class":6479},[6124,21926,6469],{"class":9667},[6124,21928,5787],{"class":6479},[6124,21930,10897],{"class":9667},[6124,21932,9647],{"class":6479},[6124,21934,21935,21937,21939,21941,21943,21945,21947,21950,21953,21955,21957,21959,21961,21963,21965,21967,21969,21971,21974,21977],{"class":6126,"line":10955},[6124,21936,9996],{"class":9667},[6124,21938,5787],{"class":6479},[6124,21940,10001],{"class":9578},[6124,21942,10004],{"class":6479},[6124,21944,10007],{"class":9605},[6124,21946,9704],{"class":6479},[6124,21948,21949],{"class":6503},"`{\"status\":\"healthy\",\"timestamp\":\"`",[6124,21951,21952],{"class":6479}," + ",[6124,21954,11641],{"class":9667},[6124,21956,5787],{"class":6479},[6124,21958,11646],{"class":9578},[6124,21960,10167],{"class":6479},[6124,21962,15215],{"class":9578},[6124,21964,9704],{"class":6479},[6124,21966,11641],{"class":9667},[6124,21968,5787],{"class":6479},[6124,21970,15224],{"class":9667},[6124,21972,21973],{"class":6479},") + ",[6124,21975,21976],{"class":6503},"`\"}`",[6124,21978,10015],{"class":6479},[6124,21980,21981],{"class":6126,"line":10960},[6124,21982,6167],{"class":6479},[5409,21984,21985,21988,21989,5787],{},[5205,21986,21987],{},"Ручне впровадження залежностей (Manual DI):"," У Go прийнято використовувати ручне впровадження залежностей без фреймворків DI-контейнерів (на відміну від Java Spring або .NET). Це робить код більш явним та легшим для розуміння: ви бачите весь граф залежностей у функції ",[5288,21990,21991],{},"main()",[5366,21993],{},[5369,21995,21997],{"id":21996},"тестування-http-обробників-засобами-httptest","Тестування HTTP-обробників засобами httptest",[5379,21999,16694,22000,22002],{},[5288,22001,5358],{}," дозволяє тестувати HTTP-обробники без запуску реального сервера:",[5530,22004,22006],{"className":9594,"code":22005,"language":9579,"meta":5538,"style":5538},"\u002F\u002F internal\u002Fdelivery\u002Fhttp\u002Forder_handler_test.go\npackage http_test\n\nimport (\n    \"bytes\"\n    \"context\"\n    \"encoding\u002Fjson\"\n    \"net\u002Fhttp\"\n    \"net\u002Fhttp\u002Fhttptest\"\n    \"testing\"\n\n    \"myapp\u002Finternal\u002Fdelivery\u002Fhttp\u002Fhandler\"\n    \"myapp\u002Finternal\u002Fdomain\"\n    \"myapp\u002Finternal\u002Fusecase\"\n\n    \"github.com\u002Fgo-chi\u002Fchi\u002Fv5\"\n    \"github.com\u002Fstretchr\u002Ftestify\u002Fassert\"\n    \"github.com\u002Fstretchr\u002Ftestify\u002Fmock\"\n)\n\n\u002F\u002F Mock UseCase\ntype MockOrderUseCase struct {\n    mock.Mock\n}\n\nfunc (m *MockOrderUseCase) GetOrder(ctx context.Context, id string) (domain.Order, error) {\n    args := m.Called(ctx, id)\n    return args.Get(0).(domain.Order), args.Error(1)\n}\n\nfunc (m *MockOrderUseCase) CreateOrder(ctx context.Context, dto usecase.CreateOrderDTO) (domain.Order, error) {\n    args := m.Called(ctx, dto)\n    return args.Get(0).(domain.Order), args.Error(1)\n}\n\nfunc TestOrderHandler_Get(t *testing.T) {\n    \u002F\u002F Arrange\n    mockUseCase := new(MockOrderUseCase)\n    h := handler.NewOrderHandler(mockUseCase)\n\n    expectedOrder := domain.Order{\n        ID:     \"order_123\",\n        UserID: \"user_456\",\n        Recipe: \"espresso\",\n        Status: domain.OrderStatusCompleted,\n    }\n\n    mockUseCase.On(\"GetOrder\", mock.Anything, \"order_123\").Return(expectedOrder, nil)\n\n    \u002F\u002F Створюємо запит\n    req := httptest.NewRequest(http.MethodGet, \"\u002Forders\u002Forder_123\", nil)\n    rec := httptest.NewRecorder()\n\n    \u002F\u002F Налаштовуємо роутер з параметрами шляху\n    r := chi.NewRouter()\n    r.Get(\"\u002Forders\u002F{id}\", h.Get)\n\n    \u002F\u002F Act\n    r.ServeHTTP(rec, req)\n\n    \u002F\u002F Assert\n    assert.Equal(t, http.StatusOK, rec.Code)\n    \n    var response domain.Order\n    err := json.NewDecoder(rec.Body).Decode(&response)\n    assert.NoError(t, err)\n    assert.Equal(t, expectedOrder.ID, response.ID)\n    assert.Equal(t, expectedOrder.Recipe, response.Recipe)\n\n    mockUseCase.AssertExpectations(t)\n}\n\nfunc TestOrderHandler_Create(t *testing.T) {\n    \u002F\u002F Arrange\n    mockUseCase := new(MockOrderUseCase)\n    h := handler.NewOrderHandler(mockUseCase)\n\n    requestBody := map[string]string{\n        \"user_id\": \"user_456\",\n        \"recipe\":  \"cappuccino\",\n        \"volume\":  \"200ml\",\n    }\n    body, _ := json.Marshal(requestBody)\n\n    expectedOrder := domain.Order{\n        ID:     \"order_789\",\n        UserID: \"user_456\",\n        Recipe: \"cappuccino\",\n        Status: domain.OrderStatusPending,\n    }\n\n    mockUseCase.On(\"CreateOrder\", mock.Anything, mock.MatchedBy(func(dto usecase.CreateOrderDTO) bool {\n        return dto.UserID == \"user_456\" && dto.Recipe == \"cappuccino\"\n    })).Return(expectedOrder, nil)\n\n    req := httptest.NewRequest(http.MethodPost, \"\u002Forders\", bytes.NewReader(body))\n    req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n    rec := httptest.NewRecorder()\n\n    r := chi.NewRouter()\n    r.Post(\"\u002Forders\", h.Create)\n\n    \u002F\u002F Act\n    r.ServeHTTP(rec, req)\n\n    \u002F\u002F Assert\n    assert.Equal(t, http.StatusCreated, rec.Code)\n    \n    var response domain.Order\n    json.NewDecoder(rec.Body).Decode(&response)\n    assert.Equal(t, expectedOrder.ID, response.ID)\n\n    mockUseCase.AssertExpectations(t)\n}\n",[5288,22007,22008,22013,22020,22024,22030,22035,22039,22043,22047,22052,22057,22061,22065,22069,22073,22077,22081,22086,22091,22095,22099,22104,22115,22125,22129,22133,22181,22205,22244,22248,22252,22302,22324,22360,22364,22368,22392,22397,22413,22433,22437,22452,22462,22472,22482,22497,22501,22505,22549,22553,22558,22593,22609,22613,22618,22632,22654,22658,22663,22682,22686,22691,22724,22728,22741,22772,22791,22821,22851,22855,22870,22874,22878,22899,22903,22917,22935,22939,22958,22968,22978,22990,22994,23018,23022,23036,23046,23056,23066,23080,23084,23088,23138,23165,23182,23186,23227,23249,23263,23267,23281,23303,23307,23311,23329,23333,23337,23367,23371,23383,23409,23439,23443,23457],{"__ignoreMap":5538},[6124,22009,22010],{"class":6126,"line":6127},[6124,22011,22012],{"class":9691},"\u002F\u002F internal\u002Fdelivery\u002Fhttp\u002Forder_handler_test.go\n",[6124,22014,22015,22017],{"class":6126,"line":6133},[6124,22016,9602],{"class":6483},[6124,22018,22019],{"class":9605}," http_test\n",[6124,22021,22022],{"class":6126,"line":6139},[6124,22023,6149],{"emptyLinePlaceholder":6148},[6124,22025,22026,22028],{"class":6126,"line":6145},[6124,22027,9615],{"class":6476},[6124,22029,9618],{"class":6479},[6124,22031,22032],{"class":6126,"line":6152},[6124,22033,22034],{"class":6503},"    \"bytes\"\n",[6124,22036,22037],{"class":6126,"line":6158},[6124,22038,14897],{"class":6503},[6124,22040,22041],{"class":6126,"line":6164},[6124,22042,9623],{"class":6503},[6124,22044,22045],{"class":6126,"line":6170},[6124,22046,9628],{"class":6503},[6124,22048,22049],{"class":6126,"line":6175},[6124,22050,22051],{"class":6503},"    \"net\u002Fhttp\u002Fhttptest\"\n",[6124,22053,22054],{"class":6126,"line":6181},[6124,22055,22056],{"class":6503},"    \"testing\"\n",[6124,22058,22059],{"class":6126,"line":6187},[6124,22060,6149],{"emptyLinePlaceholder":6148},[6124,22062,22063],{"class":6126,"line":6193},[6124,22064,20981],{"class":6503},[6124,22066,22067],{"class":6126,"line":6199},[6124,22068,18650],{"class":6503},[6124,22070,22071],{"class":6126,"line":6204},[6124,22072,20145],{"class":6503},[6124,22074,22075],{"class":6126,"line":6209},[6124,22076,6149],{"emptyLinePlaceholder":6148},[6124,22078,22079],{"class":6126,"line":6215},[6124,22080,9637],{"class":6503},[6124,22082,22083],{"class":6126,"line":6221},[6124,22084,22085],{"class":6503},"    \"github.com\u002Fstretchr\u002Ftestify\u002Fassert\"\n",[6124,22087,22088],{"class":6126,"line":6227},[6124,22089,22090],{"class":6503},"    \"github.com\u002Fstretchr\u002Ftestify\u002Fmock\"\n",[6124,22092,22093],{"class":6126,"line":6232},[6124,22094,9647],{"class":6479},[6124,22096,22097],{"class":6126,"line":6237},[6124,22098,6149],{"emptyLinePlaceholder":6148},[6124,22100,22101],{"class":6126,"line":6243},[6124,22102,22103],{"class":9691},"\u002F\u002F Mock UseCase\n",[6124,22105,22106,22108,22111,22113],{"class":6126,"line":6249},[6124,22107,14614],{"class":6483},[6124,22109,22110],{"class":9605}," MockOrderUseCase",[6124,22112,10513],{"class":6483},[6124,22114,10516],{"class":6479},[6124,22116,22117,22120,22122],{"class":6126,"line":6255},[6124,22118,22119],{"class":9605},"    mock",[6124,22121,5787],{"class":6479},[6124,22123,22124],{"class":9605},"Mock\n",[6124,22126,22127],{"class":6126,"line":6261},[6124,22128,6167],{"class":6479},[6124,22130,22131],{"class":6126,"line":6267},[6124,22132,6149],{"emptyLinePlaceholder":6148},[6124,22134,22135,22137,22139,22142,22144,22147,22149,22151,22153,22155,22157,22159,22161,22163,22165,22167,22169,22171,22173,22175,22177,22179],{"class":6126,"line":6272},[6124,22136,9656],{"class":6483},[6124,22138,5222],{"class":6479},[6124,22140,22141],{"class":9667},"m ",[6124,22143,15993],{"class":6479},[6124,22145,22146],{"class":9605},"MockOrderUseCase",[6124,22148,7173],{"class":6479},[6124,22150,19737],{"class":9578},[6124,22152,9704],{"class":6479},[6124,22154,12329],{"class":9667},[6124,22156,18682],{"class":9605},[6124,22158,5787],{"class":6479},[6124,22160,12291],{"class":9605},[6124,22162,5259],{"class":6479},[6124,22164,11232],{"class":9667},[6124,22166,10525],{"class":9605},[6124,22168,18732],{"class":6479},[6124,22170,18698],{"class":9605},[6124,22172,5787],{"class":6479},[6124,22174,18560],{"class":9605},[6124,22176,5259],{"class":6479},[6124,22178,5762],{"class":9605},[6124,22180,9817],{"class":6479},[6124,22182,22183,22186,22188,22190,22192,22195,22197,22199,22201,22203],{"class":6126,"line":6278},[6124,22184,22185],{"class":9667},"    args",[6124,22187,9671],{"class":6479},[6124,22189,17481],{"class":9667},[6124,22191,5787],{"class":6479},[6124,22193,22194],{"class":9578},"Called",[6124,22196,9704],{"class":6479},[6124,22198,12329],{"class":9667},[6124,22200,5259],{"class":6479},[6124,22202,11232],{"class":9667},[6124,22204,9647],{"class":6479},[6124,22206,22207,22209,22212,22214,22216,22218,22220,22223,22225,22227,22229,22231,22234,22236,22238,22240,22242],{"class":6126,"line":6284},[6124,22208,11596],{"class":6476},[6124,22210,22211],{"class":9667}," args",[6124,22213,5787],{"class":6479},[6124,22215,9751],{"class":9578},[6124,22217,9704],{"class":6479},[6124,22219,9083],{"class":6490},[6124,22221,22222],{"class":6479},").(",[6124,22224,18698],{"class":9605},[6124,22226,5787],{"class":6479},[6124,22228,18560],{"class":9605},[6124,22230,5428],{"class":6479},[6124,22232,22233],{"class":9667},"args",[6124,22235,5787],{"class":6479},[6124,22237,10609],{"class":9578},[6124,22239,9704],{"class":6479},[6124,22241,8576],{"class":6490},[6124,22243,9647],{"class":6479},[6124,22245,22246],{"class":6126,"line":6290},[6124,22247,6167],{"class":6479},[6124,22249,22250],{"class":6126,"line":6296},[6124,22251,6149],{"emptyLinePlaceholder":6148},[6124,22253,22254,22256,22258,22260,22262,22264,22266,22268,22270,22272,22274,22276,22278,22280,22282,22284,22286,22288,22290,22292,22294,22296,22298,22300],{"class":6126,"line":6301},[6124,22255,9656],{"class":6483},[6124,22257,5222],{"class":6479},[6124,22259,22141],{"class":9667},[6124,22261,15993],{"class":6479},[6124,22263,22146],{"class":9605},[6124,22265,7173],{"class":6479},[6124,22267,19817],{"class":9578},[6124,22269,9704],{"class":6479},[6124,22271,12329],{"class":9667},[6124,22273,18682],{"class":9605},[6124,22275,5787],{"class":6479},[6124,22277,12291],{"class":9605},[6124,22279,5259],{"class":6479},[6124,22281,19574],{"class":9667},[6124,22283,20176],{"class":9605},[6124,22285,5787],{"class":6479},[6124,22287,20703],{"class":9605},[6124,22289,18732],{"class":6479},[6124,22291,18698],{"class":9605},[6124,22293,5787],{"class":6479},[6124,22295,18560],{"class":9605},[6124,22297,5259],{"class":6479},[6124,22299,5762],{"class":9605},[6124,22301,9817],{"class":6479},[6124,22303,22304,22306,22308,22310,22312,22314,22316,22318,22320,22322],{"class":6126,"line":6307},[6124,22305,22185],{"class":9667},[6124,22307,9671],{"class":6479},[6124,22309,17481],{"class":9667},[6124,22311,5787],{"class":6479},[6124,22313,22194],{"class":9578},[6124,22315,9704],{"class":6479},[6124,22317,12329],{"class":9667},[6124,22319,5259],{"class":6479},[6124,22321,19574],{"class":9667},[6124,22323,9647],{"class":6479},[6124,22325,22326,22328,22330,22332,22334,22336,22338,22340,22342,22344,22346,22348,22350,22352,22354,22356,22358],{"class":6126,"line":6313},[6124,22327,11596],{"class":6476},[6124,22329,22211],{"class":9667},[6124,22331,5787],{"class":6479},[6124,22333,9751],{"class":9578},[6124,22335,9704],{"class":6479},[6124,22337,9083],{"class":6490},[6124,22339,22222],{"class":6479},[6124,22341,18698],{"class":9605},[6124,22343,5787],{"class":6479},[6124,22345,18560],{"class":9605},[6124,22347,5428],{"class":6479},[6124,22349,22233],{"class":9667},[6124,22351,5787],{"class":6479},[6124,22353,10609],{"class":9578},[6124,22355,9704],{"class":6479},[6124,22357,8576],{"class":6490},[6124,22359,9647],{"class":6479},[6124,22361,22362],{"class":6126,"line":6319},[6124,22363,6167],{"class":6479},[6124,22365,22366],{"class":6126,"line":6324},[6124,22367,6149],{"emptyLinePlaceholder":6148},[6124,22369,22370,22372,22375,22377,22380,22382,22385,22387,22390],{"class":6126,"line":8100},[6124,22371,9656],{"class":6483},[6124,22373,22374],{"class":9578}," TestOrderHandler_Get",[6124,22376,9704],{"class":6479},[6124,22378,22379],{"class":9667},"t",[6124,22381,9982],{"class":6479},[6124,22383,22384],{"class":9605},"testing",[6124,22386,5787],{"class":6479},[6124,22388,22389],{"class":9605},"T",[6124,22391,9817],{"class":6479},[6124,22393,22394],{"class":6126,"line":8106},[6124,22395,22396],{"class":9691},"    \u002F\u002F Arrange\n",[6124,22398,22399,22402,22404,22407,22409,22411],{"class":6126,"line":8112},[6124,22400,22401],{"class":9667},"    mockUseCase",[6124,22403,9671],{"class":6479},[6124,22405,22406],{"class":9578},"new",[6124,22408,9704],{"class":6479},[6124,22410,22146],{"class":9605},[6124,22412,9647],{"class":6479},[6124,22414,22415,22418,22420,22422,22424,22426,22428,22431],{"class":6126,"line":8117},[6124,22416,22417],{"class":9667},"    h",[6124,22419,9671],{"class":6479},[6124,22421,21232],{"class":9667},[6124,22423,5787],{"class":6479},[6124,22425,21237],{"class":9578},[6124,22427,9704],{"class":6479},[6124,22429,22430],{"class":9667},"mockUseCase",[6124,22432,9647],{"class":6479},[6124,22434,22435],{"class":6126,"line":8123},[6124,22436,6149],{"emptyLinePlaceholder":6148},[6124,22438,22439,22442,22444,22446,22448,22450],{"class":6126,"line":8129},[6124,22440,22441],{"class":9667},"    expectedOrder",[6124,22443,9671],{"class":6479},[6124,22445,18698],{"class":9605},[6124,22447,5787],{"class":6479},[6124,22449,18560],{"class":9605},[6124,22451,6543],{"class":6479},[6124,22453,22454,22456,22458,22460],{"class":6126,"line":8135},[6124,22455,19912],{"class":9667},[6124,22457,10425],{"class":6479},[6124,22459,8897],{"class":6503},[6124,22461,6558],{"class":6479},[6124,22463,22464,22466,22468,22470],{"class":6126,"line":8141},[6124,22465,10522],{"class":9667},[6124,22467,6552],{"class":6479},[6124,22469,8908],{"class":6503},[6124,22471,6558],{"class":6479},[6124,22473,22474,22476,22478,22480],{"class":6126,"line":8146},[6124,22475,10534],{"class":9667},[6124,22477,6552],{"class":6479},[6124,22479,7624],{"class":6503},[6124,22481,6558],{"class":6479},[6124,22483,22484,22486,22488,22490,22492,22495],{"class":6126,"line":10209},[6124,22485,19979],{"class":9667},[6124,22487,6552],{"class":6479},[6124,22489,18698],{"class":9667},[6124,22491,5787],{"class":6479},[6124,22493,22494],{"class":9667},"OrderStatusCompleted",[6124,22496,6558],{"class":6479},[6124,22498,22499],{"class":6126,"line":10242},[6124,22500,10545],{"class":6479},[6124,22502,22503],{"class":6126,"line":10274},[6124,22504,6149],{"emptyLinePlaceholder":6148},[6124,22506,22507,22509,22511,22514,22516,22519,22521,22524,22526,22529,22531,22533,22535,22538,22540,22543,22545,22547],{"class":6126,"line":10279},[6124,22508,22401],{"class":9667},[6124,22510,5787],{"class":6479},[6124,22512,22513],{"class":9578},"On",[6124,22515,9704],{"class":6479},[6124,22517,22518],{"class":6503},"\"GetOrder\"",[6124,22520,5259],{"class":6479},[6124,22522,22523],{"class":9667},"mock",[6124,22525,5787],{"class":6479},[6124,22527,22528],{"class":9667},"Anything",[6124,22530,5259],{"class":6479},[6124,22532,8897],{"class":6503},[6124,22534,5407],{"class":6479},[6124,22536,22537],{"class":9578},"Return",[6124,22539,9704],{"class":6479},[6124,22541,22542],{"class":9667},"expectedOrder",[6124,22544,5259],{"class":6479},[6124,22546,10596],{"class":6483},[6124,22548,9647],{"class":6479},[6124,22550,22551],{"class":6126,"line":10284},[6124,22552,6149],{"emptyLinePlaceholder":6148},[6124,22554,22555],{"class":6126,"line":10289},[6124,22556,22557],{"class":9691},"    \u002F\u002F Створюємо запит\n",[6124,22559,22560,22563,22565,22568,22570,22573,22575,22577,22579,22582,22584,22587,22589,22591],{"class":6126,"line":10321},[6124,22561,22562],{"class":9667},"    req",[6124,22564,9671],{"class":6479},[6124,22566,22567],{"class":9667},"httptest",[6124,22569,5787],{"class":6479},[6124,22571,22572],{"class":9578},"NewRequest",[6124,22574,9704],{"class":6479},[6124,22576,6469],{"class":9667},[6124,22578,5787],{"class":6479},[6124,22580,22581],{"class":9667},"MethodGet",[6124,22583,5259],{"class":6479},[6124,22585,22586],{"class":6503},"\"\u002Forders\u002Forder_123\"",[6124,22588,5259],{"class":6479},[6124,22590,10596],{"class":6483},[6124,22592,9647],{"class":6479},[6124,22594,22595,22598,22600,22602,22604,22607],{"class":6126,"line":10327},[6124,22596,22597],{"class":9667},"    rec",[6124,22599,9671],{"class":6479},[6124,22601,22567],{"class":9667},[6124,22603,5787],{"class":6479},[6124,22605,22606],{"class":9578},"NewRecorder",[6124,22608,9682],{"class":6479},[6124,22610,22611],{"class":6126,"line":10353},[6124,22612,6149],{"emptyLinePlaceholder":6148},[6124,22614,22615],{"class":6126,"line":10359},[6124,22616,22617],{"class":9691},"    \u002F\u002F Налаштовуємо роутер з параметрами шляху\n",[6124,22619,22620,22622,22624,22626,22628,22630],{"class":6126,"line":10365},[6124,22621,9668],{"class":9667},[6124,22623,9671],{"class":6479},[6124,22625,9674],{"class":9667},[6124,22627,5787],{"class":6479},[6124,22629,9679],{"class":9578},[6124,22631,9682],{"class":6479},[6124,22633,22634,22636,22638,22640,22642,22644,22646,22648,22650,22652],{"class":6126,"line":10388},[6124,22635,9668],{"class":9667},[6124,22637,5787],{"class":6479},[6124,22639,9751],{"class":9578},[6124,22641,9704],{"class":6479},[6124,22643,20283],{"class":6503},[6124,22645,5259],{"class":6479},[6124,22647,20288],{"class":9667},[6124,22649,5787],{"class":6479},[6124,22651,9751],{"class":9667},[6124,22653,9647],{"class":6479},[6124,22655,22656],{"class":6126,"line":10419},[6124,22657,6149],{"emptyLinePlaceholder":6148},[6124,22659,22660],{"class":6126,"line":10433},[6124,22661,22662],{"class":9691},"    \u002F\u002F Act\n",[6124,22664,22665,22667,22669,22671,22673,22676,22678,22680],{"class":6126,"line":10445},[6124,22666,9668],{"class":9667},[6124,22668,5787],{"class":6479},[6124,22670,11668],{"class":9578},[6124,22672,9704],{"class":6479},[6124,22674,22675],{"class":9667},"rec",[6124,22677,5259],{"class":6479},[6124,22679,10584],{"class":9667},[6124,22681,9647],{"class":6479},[6124,22683,22684],{"class":6126,"line":10457},[6124,22685,6149],{"emptyLinePlaceholder":6148},[6124,22687,22688],{"class":6126,"line":10462},[6124,22689,22690],{"class":9691},"    \u002F\u002F Assert\n",[6124,22692,22693,22696,22698,22701,22703,22705,22707,22709,22711,22713,22715,22717,22719,22722],{"class":6126,"line":10467},[6124,22694,22695],{"class":9667},"    assert",[6124,22697,5787],{"class":6479},[6124,22699,22700],{"class":9578},"Equal",[6124,22702,9704],{"class":6479},[6124,22704,22379],{"class":9667},[6124,22706,5259],{"class":6479},[6124,22708,6469],{"class":9667},[6124,22710,5787],{"class":6479},[6124,22712,10897],{"class":9667},[6124,22714,5259],{"class":6479},[6124,22716,22675],{"class":9667},[6124,22718,5787],{"class":6479},[6124,22720,22721],{"class":9667},"Code",[6124,22723,9647],{"class":6479},[6124,22725,22726],{"class":6126,"line":10472},[6124,22727,10356],{"class":6479},[6124,22729,22730,22732,22735,22737,22739],{"class":6126,"line":10504},[6124,22731,10507],{"class":6483},[6124,22733,22734],{"class":9667}," response",[6124,22736,19035],{"class":9605},[6124,22738,5787],{"class":6479},[6124,22740,19040],{"class":9605},[6124,22742,22743,22745,22747,22749,22751,22753,22755,22757,22759,22761,22763,22765,22767,22770],{"class":6126,"line":10519},[6124,22744,19075],{"class":9667},[6124,22746,9671],{"class":6479},[6124,22748,10559],{"class":9667},[6124,22750,5787],{"class":6479},[6124,22752,10564],{"class":9578},[6124,22754,9704],{"class":6479},[6124,22756,22675],{"class":9667},[6124,22758,5787],{"class":6479},[6124,22760,10573],{"class":9667},[6124,22762,5407],{"class":6479},[6124,22764,10578],{"class":9578},[6124,22766,10581],{"class":6479},[6124,22768,22769],{"class":9667},"response",[6124,22771,9647],{"class":6479},[6124,22773,22774,22776,22778,22781,22783,22785,22787,22789],{"class":6126,"line":10531},[6124,22775,22695],{"class":9667},[6124,22777,5787],{"class":6479},[6124,22779,22780],{"class":9578},"NoError",[6124,22782,9704],{"class":6479},[6124,22784,22379],{"class":9667},[6124,22786,5259],{"class":6479},[6124,22788,10590],{"class":9667},[6124,22790,9647],{"class":6479},[6124,22792,22793,22795,22797,22799,22801,22803,22805,22807,22809,22811,22813,22815,22817,22819],{"class":6126,"line":10542},[6124,22794,22695],{"class":9667},[6124,22796,5787],{"class":6479},[6124,22798,22700],{"class":9578},[6124,22800,9704],{"class":6479},[6124,22802,22379],{"class":9667},[6124,22804,5259],{"class":6479},[6124,22806,22542],{"class":9667},[6124,22808,5787],{"class":6479},[6124,22810,14442],{"class":9667},[6124,22812,5259],{"class":6479},[6124,22814,22769],{"class":9667},[6124,22816,5787],{"class":6479},[6124,22818,14442],{"class":9667},[6124,22820,9647],{"class":6479},[6124,22822,22823,22825,22827,22829,22831,22833,22835,22837,22839,22841,22843,22845,22847,22849],{"class":6126,"line":10548},[6124,22824,22695],{"class":9667},[6124,22826,5787],{"class":6479},[6124,22828,22700],{"class":9578},[6124,22830,9704],{"class":6479},[6124,22832,22379],{"class":9667},[6124,22834,5259],{"class":6479},[6124,22836,22542],{"class":9667},[6124,22838,5787],{"class":6479},[6124,22840,10790],{"class":9667},[6124,22842,5259],{"class":6479},[6124,22844,22769],{"class":9667},[6124,22846,5787],{"class":6479},[6124,22848,10790],{"class":9667},[6124,22850,9647],{"class":6479},[6124,22852,22853],{"class":6126,"line":10601},[6124,22854,6149],{"emptyLinePlaceholder":6148},[6124,22856,22857,22859,22861,22864,22866,22868],{"class":6126,"line":10632},[6124,22858,22401],{"class":9667},[6124,22860,5787],{"class":6479},[6124,22862,22863],{"class":9578},"AssertExpectations",[6124,22865,9704],{"class":6479},[6124,22867,22379],{"class":9667},[6124,22869,9647],{"class":6479},[6124,22871,22872],{"class":6126,"line":10638},[6124,22873,6167],{"class":6479},[6124,22875,22876],{"class":6126,"line":10643},[6124,22877,6149],{"emptyLinePlaceholder":6148},[6124,22879,22880,22882,22885,22887,22889,22891,22893,22895,22897],{"class":6126,"line":10663},[6124,22881,9656],{"class":6483},[6124,22883,22884],{"class":9578}," TestOrderHandler_Create",[6124,22886,9704],{"class":6479},[6124,22888,22379],{"class":9667},[6124,22890,9982],{"class":6479},[6124,22892,22384],{"class":9605},[6124,22894,5787],{"class":6479},[6124,22896,22389],{"class":9605},[6124,22898,9817],{"class":6479},[6124,22900,22901],{"class":6126,"line":10668},[6124,22902,22396],{"class":9691},[6124,22904,22905,22907,22909,22911,22913,22915],{"class":6126,"line":10674},[6124,22906,22401],{"class":9667},[6124,22908,9671],{"class":6479},[6124,22910,22406],{"class":9578},[6124,22912,9704],{"class":6479},[6124,22914,22146],{"class":9605},[6124,22916,9647],{"class":6479},[6124,22918,22919,22921,22923,22925,22927,22929,22931,22933],{"class":6126,"line":10695},[6124,22920,22417],{"class":9667},[6124,22922,9671],{"class":6479},[6124,22924,21232],{"class":9667},[6124,22926,5787],{"class":6479},[6124,22928,21237],{"class":9578},[6124,22930,9704],{"class":6479},[6124,22932,22430],{"class":9667},[6124,22934,9647],{"class":6479},[6124,22936,22937],{"class":6126,"line":10718},[6124,22938,6149],{"emptyLinePlaceholder":6148},[6124,22940,22941,22944,22946,22948,22950,22952,22954,22956],{"class":6126,"line":10749},[6124,22942,22943],{"class":9667},"    requestBody",[6124,22945,9671],{"class":6479},[6124,22947,10078],{"class":6483},[6124,22949,10081],{"class":6479},[6124,22951,10084],{"class":9605},[6124,22953,10087],{"class":6479},[6124,22955,10084],{"class":9605},[6124,22957,6543],{"class":6479},[6124,22959,22960,22962,22964,22966],{"class":6126,"line":10761},[6124,22961,10764],{"class":6503},[6124,22963,6552],{"class":6479},[6124,22965,8908],{"class":6503},[6124,22967,6558],{"class":6479},[6124,22969,22970,22972,22974,22976],{"class":6126,"line":10778},[6124,22971,10436],{"class":6503},[6124,22973,10783],{"class":6479},[6124,22975,7656],{"class":6503},[6124,22977,6558],{"class":6479},[6124,22979,22980,22983,22985,22988],{"class":6126,"line":10795},[6124,22981,22982],{"class":6503},"        \"volume\"",[6124,22984,10783],{"class":6479},[6124,22986,22987],{"class":6503},"\"200ml\"",[6124,22989,6558],{"class":6479},[6124,22991,22992],{"class":6126,"line":10806},[6124,22993,10545],{"class":6479},[6124,22995,22996,22999,23001,23003,23005,23007,23009,23011,23013,23016],{"class":6126,"line":10811},[6124,22997,22998],{"class":9667},"    body",[6124,23000,5259],{"class":6479},[6124,23002,17445],{"class":9667},[6124,23004,9671],{"class":6479},[6124,23006,10559],{"class":9667},[6124,23008,5787],{"class":6479},[6124,23010,17454],{"class":9578},[6124,23012,9704],{"class":6479},[6124,23014,23015],{"class":9667},"requestBody",[6124,23017,9647],{"class":6479},[6124,23019,23020],{"class":6126,"line":10816},[6124,23021,6149],{"emptyLinePlaceholder":6148},[6124,23023,23024,23026,23028,23030,23032,23034],{"class":6126,"line":10821},[6124,23025,22441],{"class":9667},[6124,23027,9671],{"class":6479},[6124,23029,18698],{"class":9605},[6124,23031,5787],{"class":6479},[6124,23033,18560],{"class":9605},[6124,23035,6543],{"class":6479},[6124,23037,23038,23040,23042,23044],{"class":6126,"line":10853},[6124,23039,19912],{"class":9667},[6124,23041,10425],{"class":6479},[6124,23043,7638],{"class":6503},[6124,23045,6558],{"class":6479},[6124,23047,23048,23050,23052,23054],{"class":6126,"line":10876},[6124,23049,10522],{"class":9667},[6124,23051,6552],{"class":6479},[6124,23053,8908],{"class":6503},[6124,23055,6558],{"class":6479},[6124,23057,23058,23060,23062,23064],{"class":6126,"line":10882},[6124,23059,10534],{"class":9667},[6124,23061,6552],{"class":6479},[6124,23063,7656],{"class":6503},[6124,23065,6558],{"class":6479},[6124,23067,23068,23070,23072,23074,23076,23078],{"class":6126,"line":10902},[6124,23069,19979],{"class":9667},[6124,23071,6552],{"class":6479},[6124,23073,18698],{"class":9667},[6124,23075,5787],{"class":6479},[6124,23077,18588],{"class":9667},[6124,23079,6558],{"class":6479},[6124,23081,23082],{"class":6126,"line":10950},[6124,23083,10545],{"class":6479},[6124,23085,23086],{"class":6126,"line":10955},[6124,23087,6149],{"emptyLinePlaceholder":6148},[6124,23089,23090,23092,23094,23096,23098,23101,23103,23105,23107,23109,23111,23113,23115,23118,23120,23122,23124,23126,23128,23130,23132,23134,23136],{"class":6126,"line":10960},[6124,23091,22401],{"class":9667},[6124,23093,5787],{"class":6479},[6124,23095,22513],{"class":9578},[6124,23097,9704],{"class":6479},[6124,23099,23100],{"class":6503},"\"CreateOrder\"",[6124,23102,5259],{"class":6479},[6124,23104,22523],{"class":9667},[6124,23106,5787],{"class":6479},[6124,23108,22528],{"class":9667},[6124,23110,5259],{"class":6479},[6124,23112,22523],{"class":9667},[6124,23114,5787],{"class":6479},[6124,23116,23117],{"class":9578},"MatchedBy",[6124,23119,9704],{"class":6479},[6124,23121,9656],{"class":6483},[6124,23123,9704],{"class":6479},[6124,23125,19574],{"class":9667},[6124,23127,20176],{"class":9605},[6124,23129,5787],{"class":6479},[6124,23131,20703],{"class":9605},[6124,23133,7173],{"class":6479},[6124,23135,18570],{"class":9605},[6124,23137,10516],{"class":6479},[6124,23139,23140,23142,23144,23146,23148,23150,23152,23154,23156,23158,23160,23162],{"class":6126,"line":10992},[6124,23141,19218],{"class":6476},[6124,23143,19859],{"class":9667},[6124,23145,5787],{"class":6479},[6124,23147,10773],{"class":9667},[6124,23149,11964],{"class":6479},[6124,23151,8908],{"class":6503},[6124,23153,15808],{"class":6479},[6124,23155,19574],{"class":9667},[6124,23157,5787],{"class":6479},[6124,23159,10790],{"class":9667},[6124,23161,11964],{"class":6479},[6124,23163,23164],{"class":6503},"\"cappuccino\"\n",[6124,23166,23167,23170,23172,23174,23176,23178,23180],{"class":6126,"line":11015},[6124,23168,23169],{"class":6479},"    })).",[6124,23171,22537],{"class":9578},[6124,23173,9704],{"class":6479},[6124,23175,22542],{"class":9667},[6124,23177,5259],{"class":6479},[6124,23179,10596],{"class":6483},[6124,23181,9647],{"class":6479},[6124,23183,23184],{"class":6126,"line":11021},[6124,23185,6149],{"emptyLinePlaceholder":6148},[6124,23187,23188,23190,23192,23194,23196,23198,23200,23202,23204,23207,23209,23211,23213,23216,23218,23221,23223,23225],{"class":6126,"line":11041},[6124,23189,22562],{"class":9667},[6124,23191,9671],{"class":6479},[6124,23193,22567],{"class":9667},[6124,23195,5787],{"class":6479},[6124,23197,22572],{"class":9578},[6124,23199,9704],{"class":6479},[6124,23201,6469],{"class":9667},[6124,23203,5787],{"class":6479},[6124,23205,23206],{"class":9667},"MethodPost",[6124,23208,5259],{"class":6479},[6124,23210,9831],{"class":6503},[6124,23212,5259],{"class":6479},[6124,23214,23215],{"class":9667},"bytes",[6124,23217,5787],{"class":6479},[6124,23219,23220],{"class":9578},"NewReader",[6124,23222,9704],{"class":6479},[6124,23224,6460],{"class":9667},[6124,23226,10015],{"class":6479},[6124,23228,23229,23231,23233,23235,23237,23239,23241,23243,23245,23247],{"class":6126,"line":16092},[6124,23230,22562],{"class":9667},[6124,23232,5787],{"class":6479},[6124,23234,10189],{"class":9667},[6124,23236,5787],{"class":6479},[6124,23238,10194],{"class":9578},[6124,23240,9704],{"class":6479},[6124,23242,10199],{"class":6503},[6124,23244,5259],{"class":6479},[6124,23246,10204],{"class":6503},[6124,23248,9647],{"class":6479},[6124,23250,23251,23253,23255,23257,23259,23261],{"class":6126,"line":16097},[6124,23252,22597],{"class":9667},[6124,23254,9671],{"class":6479},[6124,23256,22567],{"class":9667},[6124,23258,5787],{"class":6479},[6124,23260,22606],{"class":9578},[6124,23262,9682],{"class":6479},[6124,23264,23265],{"class":6126,"line":16102},[6124,23266,6149],{"emptyLinePlaceholder":6148},[6124,23268,23269,23271,23273,23275,23277,23279],{"class":6126,"line":16108},[6124,23270,9668],{"class":9667},[6124,23272,9671],{"class":6479},[6124,23274,9674],{"class":9667},[6124,23276,5787],{"class":6479},[6124,23278,9679],{"class":9578},[6124,23280,9682],{"class":6479},[6124,23282,23283,23285,23287,23289,23291,23293,23295,23297,23299,23301],{"class":6126,"line":16147},[6124,23284,9668],{"class":9667},[6124,23286,5787],{"class":6479},[6124,23288,9847],{"class":9578},[6124,23290,9704],{"class":6479},[6124,23292,9831],{"class":6503},[6124,23294,5259],{"class":6479},[6124,23296,20288],{"class":9667},[6124,23298,5787],{"class":6479},[6124,23300,8394],{"class":9667},[6124,23302,9647],{"class":6479},[6124,23304,23305],{"class":6126,"line":16183},[6124,23306,6149],{"emptyLinePlaceholder":6148},[6124,23308,23309],{"class":6126,"line":16218},[6124,23310,22662],{"class":9691},[6124,23312,23313,23315,23317,23319,23321,23323,23325,23327],{"class":6126,"line":16253},[6124,23314,9668],{"class":9667},[6124,23316,5787],{"class":6479},[6124,23318,11668],{"class":9578},[6124,23320,9704],{"class":6479},[6124,23322,22675],{"class":9667},[6124,23324,5259],{"class":6479},[6124,23326,10584],{"class":9667},[6124,23328,9647],{"class":6479},[6124,23330,23331],{"class":6126,"line":16288},[6124,23332,6149],{"emptyLinePlaceholder":6148},[6124,23334,23335],{"class":6126,"line":16323},[6124,23336,22690],{"class":9691},[6124,23338,23339,23341,23343,23345,23347,23349,23351,23353,23355,23357,23359,23361,23363,23365],{"class":6126,"line":16358},[6124,23340,22695],{"class":9667},[6124,23342,5787],{"class":6479},[6124,23344,22700],{"class":9578},[6124,23346,9704],{"class":6479},[6124,23348,22379],{"class":9667},[6124,23350,5259],{"class":6479},[6124,23352,6469],{"class":9667},[6124,23354,5787],{"class":6479},[6124,23356,10690],{"class":9667},[6124,23358,5259],{"class":6479},[6124,23360,22675],{"class":9667},[6124,23362,5787],{"class":6479},[6124,23364,22721],{"class":9667},[6124,23366,9647],{"class":6479},[6124,23368,23369],{"class":6126,"line":16363},[6124,23370,10356],{"class":6479},[6124,23372,23373,23375,23377,23379,23381],{"class":6126,"line":16395},[6124,23374,10507],{"class":6483},[6124,23376,22734],{"class":9667},[6124,23378,19035],{"class":9605},[6124,23380,5787],{"class":6479},[6124,23382,19040],{"class":9605},[6124,23384,23385,23387,23389,23391,23393,23395,23397,23399,23401,23403,23405,23407],{"class":6126,"line":16418},[6124,23386,10059],{"class":9667},[6124,23388,5787],{"class":6479},[6124,23390,10564],{"class":9578},[6124,23392,9704],{"class":6479},[6124,23394,22675],{"class":9667},[6124,23396,5787],{"class":6479},[6124,23398,10573],{"class":9667},[6124,23400,5407],{"class":6479},[6124,23402,10578],{"class":9578},[6124,23404,10581],{"class":6479},[6124,23406,22769],{"class":9667},[6124,23408,9647],{"class":6479},[6124,23410,23411,23413,23415,23417,23419,23421,23423,23425,23427,23429,23431,23433,23435,23437],{"class":6126,"line":16437},[6124,23412,22695],{"class":9667},[6124,23414,5787],{"class":6479},[6124,23416,22700],{"class":9578},[6124,23418,9704],{"class":6479},[6124,23420,22379],{"class":9667},[6124,23422,5259],{"class":6479},[6124,23424,22542],{"class":9667},[6124,23426,5787],{"class":6479},[6124,23428,14442],{"class":9667},[6124,23430,5259],{"class":6479},[6124,23432,22769],{"class":9667},[6124,23434,5787],{"class":6479},[6124,23436,14442],{"class":9667},[6124,23438,9647],{"class":6479},[6124,23440,23441],{"class":6126,"line":16468},[6124,23442,6149],{"emptyLinePlaceholder":6148},[6124,23444,23445,23447,23449,23451,23453,23455],{"class":6126,"line":16479},[6124,23446,22401],{"class":9667},[6124,23448,5787],{"class":6479},[6124,23450,22863],{"class":9578},[6124,23452,9704],{"class":6479},[6124,23454,22379],{"class":9667},[6124,23456,9647],{"class":6479},[6124,23458,23459],{"class":6126,"line":16498},[6124,23460,6167],{"class":6479},[5366,23462],{},[5369,23464,23466],{"id":23465},"інтеграція-з-гетерогенними-клієнтами","Інтеграція з гетерогенними клієнтами",[5374,23468,23470],{"id":23469},"десктопний-клієнт-на-javafx-java","Десктопний клієнт на JavaFX (Java)",[5530,23472,23476],{"className":23473,"code":23474,"language":23475,"meta":5538,"style":5538},"language-java shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F OrderService.java\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport com.google.gson.Gson;\n\npublic class OrderService {\n    private final HttpClient client = HttpClient.newHttpClient();\n    private final Gson gson = new Gson();\n    private final String baseUrl = \"http:\u002F\u002Flocalhost:8080\u002Fv1\";\n\n    public Order getOrder(String orderId) throws Exception {\n        HttpRequest request = HttpRequest.newBuilder()\n            .uri(URI.create(baseUrl + \"\u002Forders\u002F\" + orderId))\n            .header(\"Accept\", \"application\u002Fjson\")\n            .GET()\n            .build();\n\n        HttpResponse\u003CString> response = client.send(request, \n            HttpResponse.BodyHandlers.ofString());\n\n        if (response.statusCode() == 200) {\n            return gson.fromJson(response.body(), Order.class);\n        } else {\n            throw new RuntimeException(\"Order not found\");\n        }\n    }\n\n    public Order createOrder(CreateOrderRequest req) throws Exception {\n        String json = gson.toJson(req);\n        \n        HttpRequest request = HttpRequest.newBuilder()\n            .uri(URI.create(baseUrl + \"\u002Forders\"))\n            .header(\"Content-Type\", \"application\u002Fjson\")\n            .POST(HttpRequest.BodyPublishers.ofString(json))\n            .build();\n\n        HttpResponse\u003CString> response = client.send(request, \n            HttpResponse.BodyHandlers.ofString());\n\n        return gson.fromJson(response.body(), Order.class);\n    }\n}\n","java",[5288,23477,23478,23483,23490,23497,23504,23511,23518,23522,23535,23562,23582,23602,23606,23633,23653,23680,23698,23706,23715,23719,23747,23765,23769,23789,23821,23831,23848,23852,23856,23860,23884,23904,23908,23924,23944,23960,23982,23990,23994,24016,24030,24034,24062,24066],{"__ignoreMap":5538},[6124,23479,23480],{"class":6126,"line":6127},[6124,23481,23482],{"class":9691},"\u002F\u002F OrderService.java\n",[6124,23484,23485,23487],{"class":6126,"line":6133},[6124,23486,9615],{"class":6483},[6124,23488,23489],{"class":6479}," java.net.URI;\n",[6124,23491,23492,23494],{"class":6126,"line":6139},[6124,23493,9615],{"class":6483},[6124,23495,23496],{"class":6479}," java.net.http.HttpClient;\n",[6124,23498,23499,23501],{"class":6126,"line":6145},[6124,23500,9615],{"class":6483},[6124,23502,23503],{"class":6479}," java.net.http.HttpRequest;\n",[6124,23505,23506,23508],{"class":6126,"line":6152},[6124,23507,9615],{"class":6483},[6124,23509,23510],{"class":6479}," java.net.http.HttpResponse;\n",[6124,23512,23513,23515],{"class":6126,"line":6158},[6124,23514,9615],{"class":6483},[6124,23516,23517],{"class":6479}," com.google.gson.Gson;\n",[6124,23519,23520],{"class":6126,"line":6164},[6124,23521,6149],{"emptyLinePlaceholder":6148},[6124,23523,23524,23527,23530,23533],{"class":6126,"line":6170},[6124,23525,23526],{"class":6483},"public",[6124,23528,23529],{"class":6483}," class",[6124,23531,23532],{"class":9605}," OrderService",[6124,23534,10516],{"class":6479},[6124,23536,23537,23540,23543,23546,23549,23551,23554,23556,23559],{"class":6126,"line":6175},[6124,23538,23539],{"class":6483},"    private",[6124,23541,23542],{"class":6483}," final",[6124,23544,23545],{"class":9605}," HttpClient",[6124,23547,23548],{"class":9667}," client",[6124,23550,14638],{"class":6479},[6124,23552,23553],{"class":9667},"HttpClient",[6124,23555,5787],{"class":6479},[6124,23557,23558],{"class":9578},"newHttpClient",[6124,23560,23561],{"class":6479},"();\n",[6124,23563,23564,23566,23568,23571,23574,23576,23578,23580],{"class":6126,"line":6181},[6124,23565,23539],{"class":6483},[6124,23567,23542],{"class":6483},[6124,23569,23570],{"class":9605}," Gson",[6124,23572,23573],{"class":9667}," gson",[6124,23575,14638],{"class":6479},[6124,23577,22406],{"class":6476},[6124,23579,23570],{"class":9578},[6124,23581,23561],{"class":6479},[6124,23583,23584,23586,23588,23591,23594,23596,23599],{"class":6126,"line":6187},[6124,23585,23539],{"class":6483},[6124,23587,23542],{"class":6483},[6124,23589,23590],{"class":9605}," String",[6124,23592,23593],{"class":9667}," baseUrl",[6124,23595,14638],{"class":6479},[6124,23597,23598],{"class":6503},"\"http:\u002F\u002Flocalhost:8080\u002Fv1\"",[6124,23600,23601],{"class":6479},";\n",[6124,23603,23604],{"class":6126,"line":6193},[6124,23605,6149],{"emptyLinePlaceholder":6148},[6124,23607,23608,23611,23613,23616,23618,23620,23623,23625,23628,23631],{"class":6126,"line":6199},[6124,23609,23610],{"class":6483},"    public",[6124,23612,17131],{"class":9605},[6124,23614,23615],{"class":9578}," getOrder",[6124,23617,9704],{"class":6479},[6124,23619,19928],{"class":9605},[6124,23621,23622],{"class":9667}," orderId",[6124,23624,7173],{"class":6479},[6124,23626,23627],{"class":6483},"throws",[6124,23629,23630],{"class":9605}," Exception",[6124,23632,10516],{"class":6479},[6124,23634,23635,23638,23641,23643,23646,23648,23651],{"class":6126,"line":6204},[6124,23636,23637],{"class":9605},"        HttpRequest",[6124,23639,23640],{"class":9667}," request",[6124,23642,14638],{"class":6479},[6124,23644,23645],{"class":9667},"HttpRequest",[6124,23647,5787],{"class":6479},[6124,23649,23650],{"class":9578},"newBuilder",[6124,23652,9682],{"class":6479},[6124,23654,23655,23658,23661,23663,23666,23668,23671,23674,23677],{"class":6126,"line":6209},[6124,23656,23657],{"class":6479},"            .",[6124,23659,23660],{"class":9578},"uri",[6124,23662,9704],{"class":6479},[6124,23664,23665],{"class":9667},"URI",[6124,23667,5787],{"class":6479},[6124,23669,23670],{"class":9578},"create",[6124,23672,23673],{"class":6479},"(baseUrl + ",[6124,23675,23676],{"class":6503},"\"\u002Forders\u002F\"",[6124,23678,23679],{"class":6479}," + orderId))\n",[6124,23681,23682,23684,23687,23689,23692,23694,23696],{"class":6126,"line":6215},[6124,23683,23657],{"class":6479},[6124,23685,23686],{"class":9578},"header",[6124,23688,9704],{"class":6479},[6124,23690,23691],{"class":6503},"\"Accept\"",[6124,23693,5259],{"class":6479},[6124,23695,10204],{"class":6503},[6124,23697,9647],{"class":6479},[6124,23699,23700,23702,23704],{"class":6126,"line":6221},[6124,23701,23657],{"class":6479},[6124,23703,5258],{"class":9578},[6124,23705,9682],{"class":6479},[6124,23707,23708,23710,23713],{"class":6126,"line":6227},[6124,23709,23657],{"class":6479},[6124,23711,23712],{"class":9578},"build",[6124,23714,23561],{"class":6479},[6124,23716,23717],{"class":6126,"line":6232},[6124,23718,6149],{"emptyLinePlaceholder":6148},[6124,23720,23721,23724,23727,23729,23732,23734,23736,23739,23741,23744],{"class":6126,"line":6237},[6124,23722,23723],{"class":9605},"        HttpResponse",[6124,23725,23726],{"class":6479},"\u003C",[6124,23728,19928],{"class":9605},[6124,23730,23731],{"class":6479},"> ",[6124,23733,22769],{"class":9667},[6124,23735,14638],{"class":6479},[6124,23737,23738],{"class":9667},"client",[6124,23740,5787],{"class":6479},[6124,23742,23743],{"class":9578},"send",[6124,23745,23746],{"class":6479},"(request, \n",[6124,23748,23749,23752,23754,23757,23759,23762],{"class":6126,"line":6243},[6124,23750,23751],{"class":9667},"            HttpResponse",[6124,23753,5787],{"class":6479},[6124,23755,23756],{"class":9667},"BodyHandlers",[6124,23758,5787],{"class":6479},[6124,23760,23761],{"class":9578},"ofString",[6124,23763,23764],{"class":6479},"());\n",[6124,23766,23767],{"class":6126,"line":6249},[6124,23768,6149],{"emptyLinePlaceholder":6148},[6124,23770,23771,23773,23775,23777,23779,23782,23785,23787],{"class":6126,"line":6255},[6124,23772,11955],{"class":6476},[6124,23774,5222],{"class":6479},[6124,23776,22769],{"class":9667},[6124,23778,5787],{"class":6479},[6124,23780,23781],{"class":9578},"statusCode",[6124,23783,23784],{"class":6479},"() == ",[6124,23786,8836],{"class":6490},[6124,23788,9817],{"class":6479},[6124,23790,23791,23794,23796,23798,23801,23803,23805,23807,23809,23811,23813,23815,23818],{"class":6126,"line":6261},[6124,23792,23793],{"class":6476},"            return",[6124,23795,23573],{"class":9667},[6124,23797,5787],{"class":6479},[6124,23799,23800],{"class":9578},"fromJson",[6124,23802,9704],{"class":6479},[6124,23804,22769],{"class":9667},[6124,23806,5787],{"class":6479},[6124,23808,6460],{"class":9578},[6124,23810,12294],{"class":6479},[6124,23812,18560],{"class":9667},[6124,23814,5787],{"class":6479},[6124,23816,23817],{"class":9667},"class",[6124,23819,23820],{"class":6479},");\n",[6124,23822,23823,23826,23829],{"class":6126,"line":6267},[6124,23824,23825],{"class":6479},"        } ",[6124,23827,23828],{"class":6476},"else",[6124,23830,10516],{"class":6479},[6124,23832,23833,23836,23839,23842,23844,23846],{"class":6126,"line":6272},[6124,23834,23835],{"class":6476},"            throw",[6124,23837,23838],{"class":6476}," new",[6124,23840,23841],{"class":9578}," RuntimeException",[6124,23843,9704],{"class":6479},[6124,23845,20454],{"class":6503},[6124,23847,23820],{"class":6479},[6124,23849,23850],{"class":6126,"line":6278},[6124,23851,12002],{"class":6479},[6124,23853,23854],{"class":6126,"line":6284},[6124,23855,10545],{"class":6479},[6124,23857,23858],{"class":6126,"line":6290},[6124,23859,6149],{"emptyLinePlaceholder":6148},[6124,23861,23862,23864,23866,23869,23871,23874,23876,23878,23880,23882],{"class":6126,"line":6296},[6124,23863,23610],{"class":6483},[6124,23865,17131],{"class":9605},[6124,23867,23868],{"class":9578}," createOrder",[6124,23870,9704],{"class":6479},[6124,23872,23873],{"class":9605},"CreateOrderRequest",[6124,23875,10510],{"class":9667},[6124,23877,7173],{"class":6479},[6124,23879,23627],{"class":6483},[6124,23881,23630],{"class":9605},[6124,23883,10516],{"class":6479},[6124,23885,23886,23889,23891,23893,23896,23898,23901],{"class":6126,"line":6301},[6124,23887,23888],{"class":9605},"        String",[6124,23890,17546],{"class":9667},[6124,23892,14638],{"class":6479},[6124,23894,23895],{"class":9667},"gson",[6124,23897,5787],{"class":6479},[6124,23899,23900],{"class":9578},"toJson",[6124,23902,23903],{"class":6479},"(req);\n",[6124,23905,23906],{"class":6126,"line":6307},[6124,23907,11653],{"class":6479},[6124,23909,23910,23912,23914,23916,23918,23920,23922],{"class":6126,"line":6313},[6124,23911,23637],{"class":9605},[6124,23913,23640],{"class":9667},[6124,23915,14638],{"class":6479},[6124,23917,23645],{"class":9667},[6124,23919,5787],{"class":6479},[6124,23921,23650],{"class":9578},[6124,23923,9682],{"class":6479},[6124,23925,23926,23928,23930,23932,23934,23936,23938,23940,23942],{"class":6126,"line":6319},[6124,23927,23657],{"class":6479},[6124,23929,23660],{"class":9578},[6124,23931,9704],{"class":6479},[6124,23933,23665],{"class":9667},[6124,23935,5787],{"class":6479},[6124,23937,23670],{"class":9578},[6124,23939,23673],{"class":6479},[6124,23941,9831],{"class":6503},[6124,23943,10015],{"class":6479},[6124,23945,23946,23948,23950,23952,23954,23956,23958],{"class":6126,"line":6324},[6124,23947,23657],{"class":6479},[6124,23949,23686],{"class":9578},[6124,23951,9704],{"class":6479},[6124,23953,10199],{"class":6503},[6124,23955,5259],{"class":6479},[6124,23957,10204],{"class":6503},[6124,23959,9647],{"class":6479},[6124,23961,23962,23964,23966,23968,23970,23972,23975,23977,23979],{"class":6126,"line":8100},[6124,23963,23657],{"class":6479},[6124,23965,5262],{"class":9578},[6124,23967,9704],{"class":6479},[6124,23969,23645],{"class":9667},[6124,23971,5787],{"class":6479},[6124,23973,23974],{"class":9667},"BodyPublishers",[6124,23976,5787],{"class":6479},[6124,23978,23761],{"class":9578},[6124,23980,23981],{"class":6479},"(json))\n",[6124,23983,23984,23986,23988],{"class":6126,"line":8106},[6124,23985,23657],{"class":6479},[6124,23987,23712],{"class":9578},[6124,23989,23561],{"class":6479},[6124,23991,23992],{"class":6126,"line":8112},[6124,23993,6149],{"emptyLinePlaceholder":6148},[6124,23995,23996,23998,24000,24002,24004,24006,24008,24010,24012,24014],{"class":6126,"line":8117},[6124,23997,23723],{"class":9605},[6124,23999,23726],{"class":6479},[6124,24001,19928],{"class":9605},[6124,24003,23731],{"class":6479},[6124,24005,22769],{"class":9667},[6124,24007,14638],{"class":6479},[6124,24009,23738],{"class":9667},[6124,24011,5787],{"class":6479},[6124,24013,23743],{"class":9578},[6124,24015,23746],{"class":6479},[6124,24017,24018,24020,24022,24024,24026,24028],{"class":6126,"line":8123},[6124,24019,23751],{"class":9667},[6124,24021,5787],{"class":6479},[6124,24023,23756],{"class":9667},[6124,24025,5787],{"class":6479},[6124,24027,23761],{"class":9578},[6124,24029,23764],{"class":6479},[6124,24031,24032],{"class":6126,"line":8129},[6124,24033,6149],{"emptyLinePlaceholder":6148},[6124,24035,24036,24038,24040,24042,24044,24046,24048,24050,24052,24054,24056,24058,24060],{"class":6126,"line":8135},[6124,24037,19218],{"class":6476},[6124,24039,23573],{"class":9667},[6124,24041,5787],{"class":6479},[6124,24043,23800],{"class":9578},[6124,24045,9704],{"class":6479},[6124,24047,22769],{"class":9667},[6124,24049,5787],{"class":6479},[6124,24051,6460],{"class":9578},[6124,24053,12294],{"class":6479},[6124,24055,18560],{"class":9667},[6124,24057,5787],{"class":6479},[6124,24059,23817],{"class":9667},[6124,24061,23820],{"class":6479},[6124,24063,24064],{"class":6126,"line":8141},[6124,24065,10545],{"class":6479},[6124,24067,24068],{"class":6126,"line":8146},[6124,24069,6167],{"class":6479},[5374,24071,24073],{"id":24072},"мобільний-клієнт-на-react-native-javascript","Мобільний клієнт на React Native (JavaScript)",[5530,24075,24079],{"className":24076,"code":24077,"language":24078,"meta":5538,"style":5538},"language-javascript shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F orderService.js\nconst API_BASE_URL = 'http:\u002F\u002Flocalhost:8080\u002Fv1';\n\nexport const orderService = {\n  async getOrder(orderId) {\n    const response = await fetch(`${API_BASE_URL}\u002Forders\u002F${orderId}`, {\n      method: 'GET',\n      headers: {\n        'Accept': 'application\u002Fjson',\n      },\n    });\n\n    if (!response.ok) {\n      throw new Error('Order not found');\n    }\n\n    return await response.json();\n  },\n\n  async createOrder(orderData) {\n    const response = await fetch(`${API_BASE_URL}\u002Forders`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application\u002Fjson',\n      },\n      body: JSON.stringify(orderData),\n    });\n\n    if (!response.ok) {\n      const error = await response.json();\n      throw new Error(error.detail || 'Failed to create order');\n    }\n\n    return await response.json();\n  },\n\n  async listOrders(userId) {\n    const response = await fetch(\n      `${API_BASE_URL}\u002Forders?user_id=${userId}`,\n      {\n        method: 'GET',\n        headers: {\n          'Accept': 'application\u002Fjson',\n        },\n      }\n    );\n\n    return await response.json();\n  },\n};\n","javascript",[5288,24080,24081,24086,24100,24104,24117,24131,24174,24184,24191,24203,24208,24213,24217,24232,24249,24253,24257,24272,24276,24280,24293,24320,24329,24335,24346,24350,24369,24373,24377,24391,24411,24435,24439,24443,24457,24461,24465,24479,24493,24517,24522,24531,24538,24549,24554,24559,24564,24568,24582,24586],{"__ignoreMap":5538},[6124,24082,24083],{"class":6126,"line":6127},[6124,24084,24085],{"class":9691},"\u002F\u002F orderService.js\n",[6124,24087,24088,24090,24093,24095,24098],{"class":6126,"line":6133},[6124,24089,14629],{"class":6483},[6124,24091,24092],{"class":14632}," API_BASE_URL",[6124,24094,14638],{"class":6479},[6124,24096,24097],{"class":6503},"'http:\u002F\u002Flocalhost:8080\u002Fv1'",[6124,24099,23601],{"class":6479},[6124,24101,24102],{"class":6126,"line":6139},[6124,24103,6149],{"emptyLinePlaceholder":6148},[6124,24105,24106,24109,24112,24114],{"class":6126,"line":6145},[6124,24107,24108],{"class":6476},"export",[6124,24110,24111],{"class":6483}," const",[6124,24113,19642],{"class":14632},[6124,24115,24116],{"class":6479}," = {\n",[6124,24118,24119,24122,24124,24126,24129],{"class":6126,"line":6152},[6124,24120,24121],{"class":6483},"  async",[6124,24123,23615],{"class":9578},[6124,24125,9704],{"class":6479},[6124,24127,24128],{"class":9667},"orderId",[6124,24130,9817],{"class":6479},[6124,24132,24133,24136,24138,24140,24143,24146,24148,24151,24154,24157,24160,24163,24165,24167,24169,24171],{"class":6126,"line":6158},[6124,24134,24135],{"class":6483},"    const",[6124,24137,22734],{"class":14632},[6124,24139,14638],{"class":6479},[6124,24141,24142],{"class":6476},"await",[6124,24144,24145],{"class":9578}," fetch",[6124,24147,9704],{"class":6479},[6124,24149,24150],{"class":6503},"`",[6124,24152,24153],{"class":6483},"${",[6124,24155,24156],{"class":14632},"API_BASE_URL",[6124,24158,24159],{"class":6483},"}",[6124,24161,24162],{"class":6503},"\u002Forders\u002F",[6124,24164,24153],{"class":6483},[6124,24166,24128],{"class":9667},[6124,24168,24159],{"class":6483},[6124,24170,24150],{"class":6503},[6124,24172,24173],{"class":6479},", {\n",[6124,24175,24176,24179,24182],{"class":6126,"line":6164},[6124,24177,24178],{"class":9667},"      method:",[6124,24180,24181],{"class":6503}," 'GET'",[6124,24183,6558],{"class":6479},[6124,24185,24186,24189],{"class":6126,"line":6170},[6124,24187,24188],{"class":9667},"      headers:",[6124,24190,10516],{"class":6479},[6124,24192,24193,24196,24198,24201],{"class":6126,"line":6175},[6124,24194,24195],{"class":6503},"        'Accept'",[6124,24197,6500],{"class":9667},[6124,24199,24200],{"class":6503}," 'application\u002Fjson'",[6124,24202,6558],{"class":6479},[6124,24204,24205],{"class":6126,"line":6181},[6124,24206,24207],{"class":6479},"      },\n",[6124,24209,24210],{"class":6126,"line":6187},[6124,24211,24212],{"class":6479},"    });\n",[6124,24214,24215],{"class":6126,"line":6193},[6124,24216,6149],{"emptyLinePlaceholder":6148},[6124,24218,24219,24221,24224,24226,24228,24230],{"class":6126,"line":6199},[6124,24220,10551],{"class":6476},[6124,24222,24223],{"class":6479}," (!",[6124,24225,22769],{"class":9667},[6124,24227,5787],{"class":6479},[6124,24229,14699],{"class":9667},[6124,24231,9817],{"class":6479},[6124,24233,24234,24237,24239,24242,24244,24247],{"class":6126,"line":6204},[6124,24235,24236],{"class":6476},"      throw",[6124,24238,23838],{"class":6483},[6124,24240,24241],{"class":9578}," Error",[6124,24243,9704],{"class":6479},[6124,24245,24246],{"class":6503},"'Order not found'",[6124,24248,23820],{"class":6479},[6124,24250,24251],{"class":6126,"line":6209},[6124,24252,10545],{"class":6479},[6124,24254,24255],{"class":6126,"line":6215},[6124,24256,6149],{"emptyLinePlaceholder":6148},[6124,24258,24259,24261,24264,24266,24268,24270],{"class":6126,"line":6221},[6124,24260,11596],{"class":6476},[6124,24262,24263],{"class":6476}," await",[6124,24265,22734],{"class":9667},[6124,24267,5787],{"class":6479},[6124,24269,10559],{"class":9578},[6124,24271,23561],{"class":6479},[6124,24273,24274],{"class":6126,"line":6227},[6124,24275,7583],{"class":6479},[6124,24277,24278],{"class":6126,"line":6232},[6124,24279,6149],{"emptyLinePlaceholder":6148},[6124,24281,24282,24284,24286,24288,24291],{"class":6126,"line":6237},[6124,24283,24121],{"class":6483},[6124,24285,23868],{"class":9578},[6124,24287,9704],{"class":6479},[6124,24289,24290],{"class":9667},"orderData",[6124,24292,9817],{"class":6479},[6124,24294,24295,24297,24299,24301,24303,24305,24307,24309,24311,24313,24315,24318],{"class":6126,"line":6243},[6124,24296,24135],{"class":6483},[6124,24298,22734],{"class":14632},[6124,24300,14638],{"class":6479},[6124,24302,24142],{"class":6476},[6124,24304,24145],{"class":9578},[6124,24306,9704],{"class":6479},[6124,24308,24150],{"class":6503},[6124,24310,24153],{"class":6483},[6124,24312,24156],{"class":14632},[6124,24314,24159],{"class":6483},[6124,24316,24317],{"class":6503},"\u002Forders`",[6124,24319,24173],{"class":6479},[6124,24321,24322,24324,24327],{"class":6126,"line":6249},[6124,24323,24178],{"class":9667},[6124,24325,24326],{"class":6503}," 'POST'",[6124,24328,6558],{"class":6479},[6124,24330,24331,24333],{"class":6126,"line":6255},[6124,24332,24188],{"class":9667},[6124,24334,10516],{"class":6479},[6124,24336,24337,24340,24342,24344],{"class":6126,"line":6261},[6124,24338,24339],{"class":6503},"        'Content-Type'",[6124,24341,6500],{"class":9667},[6124,24343,24200],{"class":6503},[6124,24345,6558],{"class":6479},[6124,24347,24348],{"class":6126,"line":6267},[6124,24349,24207],{"class":6479},[6124,24351,24352,24355,24358,24360,24363,24365,24367],{"class":6126,"line":6272},[6124,24353,24354],{"class":9667},"      body:",[6124,24356,24357],{"class":14632}," JSON",[6124,24359,5787],{"class":6479},[6124,24361,24362],{"class":9578},"stringify",[6124,24364,9704],{"class":6479},[6124,24366,24290],{"class":9667},[6124,24368,14052],{"class":6479},[6124,24370,24371],{"class":6126,"line":6278},[6124,24372,24212],{"class":6479},[6124,24374,24375],{"class":6126,"line":6284},[6124,24376,6149],{"emptyLinePlaceholder":6148},[6124,24378,24379,24381,24383,24385,24387,24389],{"class":6126,"line":6290},[6124,24380,10551],{"class":6476},[6124,24382,24223],{"class":6479},[6124,24384,22769],{"class":9667},[6124,24386,5787],{"class":6479},[6124,24388,14699],{"class":9667},[6124,24390,9817],{"class":6479},[6124,24392,24393,24396,24399,24401,24403,24405,24407,24409],{"class":6126,"line":6296},[6124,24394,24395],{"class":6483},"      const",[6124,24397,24398],{"class":14632}," error",[6124,24400,14638],{"class":6479},[6124,24402,24142],{"class":6476},[6124,24404,22734],{"class":9667},[6124,24406,5787],{"class":6479},[6124,24408,10559],{"class":9578},[6124,24410,23561],{"class":6479},[6124,24412,24413,24415,24417,24419,24421,24423,24425,24428,24430,24433],{"class":6126,"line":6301},[6124,24414,24236],{"class":6476},[6124,24416,23838],{"class":6483},[6124,24418,24241],{"class":9578},[6124,24420,9704],{"class":6479},[6124,24422,5762],{"class":9667},[6124,24424,5787],{"class":6479},[6124,24426,24427],{"class":9667},"detail",[6124,24429,16928],{"class":6479},[6124,24431,24432],{"class":6503},"'Failed to create order'",[6124,24434,23820],{"class":6479},[6124,24436,24437],{"class":6126,"line":6307},[6124,24438,10545],{"class":6479},[6124,24440,24441],{"class":6126,"line":6313},[6124,24442,6149],{"emptyLinePlaceholder":6148},[6124,24444,24445,24447,24449,24451,24453,24455],{"class":6126,"line":6319},[6124,24446,11596],{"class":6476},[6124,24448,24263],{"class":6476},[6124,24450,22734],{"class":9667},[6124,24452,5787],{"class":6479},[6124,24454,10559],{"class":9578},[6124,24456,23561],{"class":6479},[6124,24458,24459],{"class":6126,"line":6324},[6124,24460,7583],{"class":6479},[6124,24462,24463],{"class":6126,"line":8100},[6124,24464,6149],{"emptyLinePlaceholder":6148},[6124,24466,24467,24469,24472,24474,24477],{"class":6126,"line":8106},[6124,24468,24121],{"class":6483},[6124,24470,24471],{"class":9578}," listOrders",[6124,24473,9704],{"class":6479},[6124,24475,24476],{"class":9667},"userId",[6124,24478,9817],{"class":6479},[6124,24480,24481,24483,24485,24487,24489,24491],{"class":6126,"line":8112},[6124,24482,24135],{"class":6483},[6124,24484,22734],{"class":14632},[6124,24486,14638],{"class":6479},[6124,24488,24142],{"class":6476},[6124,24490,24145],{"class":9578},[6124,24492,19108],{"class":6479},[6124,24494,24495,24498,24500,24502,24504,24507,24509,24511,24513,24515],{"class":6126,"line":8117},[6124,24496,24497],{"class":6503},"      `",[6124,24499,24153],{"class":6483},[6124,24501,24156],{"class":14632},[6124,24503,24159],{"class":6483},[6124,24505,24506],{"class":6503},"\u002Forders?user_id=",[6124,24508,24153],{"class":6483},[6124,24510,24476],{"class":9667},[6124,24512,24159],{"class":6483},[6124,24514,24150],{"class":6503},[6124,24516,6558],{"class":6479},[6124,24518,24519],{"class":6126,"line":8123},[6124,24520,24521],{"class":6479},"      {\n",[6124,24523,24524,24527,24529],{"class":6126,"line":8129},[6124,24525,24526],{"class":9667},"        method:",[6124,24528,24181],{"class":6503},[6124,24530,6558],{"class":6479},[6124,24532,24533,24536],{"class":6126,"line":8135},[6124,24534,24535],{"class":9667},"        headers:",[6124,24537,10516],{"class":6479},[6124,24539,24540,24543,24545,24547],{"class":6126,"line":8141},[6124,24541,24542],{"class":6503},"          'Accept'",[6124,24544,6500],{"class":9667},[6124,24546,24200],{"class":6503},[6124,24548,6558],{"class":6479},[6124,24550,24551],{"class":6126,"line":8146},[6124,24552,24553],{"class":6479},"        },\n",[6124,24555,24556],{"class":6126,"line":10209},[6124,24557,24558],{"class":6479},"      }\n",[6124,24560,24561],{"class":6126,"line":10242},[6124,24562,24563],{"class":6479},"    );\n",[6124,24565,24566],{"class":6126,"line":10274},[6124,24567,6149],{"emptyLinePlaceholder":6148},[6124,24569,24570,24572,24574,24576,24578,24580],{"class":6126,"line":10279},[6124,24571,11596],{"class":6476},[6124,24573,24263],{"class":6476},[6124,24575,22734],{"class":9667},[6124,24577,5787],{"class":6479},[6124,24579,10559],{"class":9578},[6124,24581,23561],{"class":6479},[6124,24583,24584],{"class":6126,"line":10284},[6124,24585,7583],{"class":6479},[6124,24587,24588],{"class":6126,"line":10289},[6124,24589,24590],{"class":6479},"};\n",[5374,24592,24594],{"id":24593},"cli-утиліта-на-go","CLI-утиліта на Go",[5530,24596,24598],{"className":9594,"code":24597,"language":9579,"meta":5538,"style":5538},"\u002F\u002F cmd\u002Fcli\u002Fmain.go\npackage main\n\nimport (\n    \"bytes\"\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"io\"\n    \"net\u002Fhttp\"\n    \"os\"\n)\n\nconst baseURL = \"http:\u002F\u002Flocalhost:8080\u002Fv1\"\n\ntype Order struct {\n    ID     string `json:\"id\"`\n    UserID string `json:\"user_id\"`\n    Recipe string `json:\"recipe\"`\n    Status string `json:\"status\"`\n}\n\nfunc main() {\n    if len(os.Args) \u003C 2 {\n        fmt.Println(\"Usage: cli [get|create|list] [args...]\")\n        os.Exit(1)\n    }\n\n    command := os.Args[1]\n\n    switch command {\n    case \"get\":\n        if len(os.Args) \u003C 3 {\n            fmt.Println(\"Usage: cli get \u003Corder_id>\")\n            os.Exit(1)\n        }\n        getOrder(os.Args[2])\n    case \"create\":\n        createOrder()\n    case \"list\":\n        if len(os.Args) \u003C 3 {\n            fmt.Println(\"Usage: cli list \u003Cuser_id>\")\n            os.Exit(1)\n        }\n        listOrders(os.Args[2])\n    default:\n        fmt.Println(\"Unknown command:\", command)\n    }\n}\n\nfunc getOrder(orderID string) {\n    resp, err := http.Get(fmt.Sprintf(\"%s\u002Forders\u002F%s\", baseURL, orderID))\n    if err != nil {\n        fmt.Println(\"Error:\", err)\n        return\n    }\n    defer resp.Body.Close()\n\n    if resp.StatusCode != http.StatusOK {\n        fmt.Println(\"Order not found\")\n        return\n    }\n\n    var order Order\n    json.NewDecoder(resp.Body).Decode(&order)\n    fmt.Printf(\"Order: %+v\\n\", order)\n}\n\nfunc createOrder() {\n    reqBody := map[string]string{\n        \"user_id\": \"user_123\",\n        \"recipe\":  \"latte\",\n        \"volume\":  \"300ml\",\n    }\n    body, _ := json.Marshal(reqBody)\n\n    resp, err := http.Post(\n        fmt.Sprintf(\"%s\u002Forders\", baseURL),\n        \"application\u002Fjson\",\n        bytes.NewReader(body),\n    )\n    if err != nil {\n        fmt.Println(\"Error:\", err)\n        return\n    }\n    defer resp.Body.Close()\n\n    var order Order\n    json.NewDecoder(resp.Body).Decode(&order)\n    fmt.Printf(\"Created order: %+v\\n\", order)\n}\n\nfunc listOrders(userID string) {\n    resp, err := http.Get(fmt.Sprintf(\"%s\u002Forders?user_id=%s\", baseURL, userID))\n    if err != nil {\n        fmt.Println(\"Error:\", err)\n        return\n    }\n    defer resp.Body.Close()\n\n    var orders []Order\n    json.NewDecoder(resp.Body).Decode(&orders)\n    for _, order := range orders {\n        fmt.Printf(\"- %s: %s (%s)\\n\", order.ID, order.Recipe, order.Status)\n    }\n}\n",[5288,24599,24600,24605,24611,24615,24621,24625,24629,24634,24639,24643,24647,24651,24655,24667,24671,24681,24690,24698,24706,24715,24719,24723,24731,24755,24771,24787,24791,24795,24814,24818,24828,24838,24859,24875,24890,24894,24914,24923,24930,24939,24959,24974,24988,24992,25011,25018,25038,25042,25046,25050,25064,25112,25124,25143,25147,25151,25168,25172,25193,25207,25211,25215,25219,25228,25255,25283,25287,25291,25299,25318,25328,25338,25348,25352,25375,25379,25397,25420,25427,25442,25446,25458,25476,25480,25484,25500,25504,25512,25538,25563,25567,25571,25585,25631,25643,25661,25665,25669,25685,25689,25701,25727,25746,25802,25806],{"__ignoreMap":5538},[6124,24601,24602],{"class":6126,"line":6127},[6124,24603,24604],{"class":9691},"\u002F\u002F cmd\u002Fcli\u002Fmain.go\n",[6124,24606,24607,24609],{"class":6126,"line":6133},[6124,24608,9602],{"class":6483},[6124,24610,9606],{"class":9605},[6124,24612,24613],{"class":6126,"line":6139},[6124,24614,6149],{"emptyLinePlaceholder":6148},[6124,24616,24617,24619],{"class":6126,"line":6145},[6124,24618,9615],{"class":6476},[6124,24620,9618],{"class":6479},[6124,24622,24623],{"class":6126,"line":6152},[6124,24624,22034],{"class":6503},[6124,24626,24627],{"class":6126,"line":6158},[6124,24628,9623],{"class":6503},[6124,24630,24631],{"class":6126,"line":6164},[6124,24632,24633],{"class":6503},"    \"fmt\"\n",[6124,24635,24636],{"class":6126,"line":6170},[6124,24637,24638],{"class":6503},"    \"io\"\n",[6124,24640,24641],{"class":6126,"line":6175},[6124,24642,9628],{"class":6503},[6124,24644,24645],{"class":6126,"line":6181},[6124,24646,14915],{"class":6503},[6124,24648,24649],{"class":6126,"line":6187},[6124,24650,9647],{"class":6479},[6124,24652,24653],{"class":6126,"line":6193},[6124,24654,6149],{"emptyLinePlaceholder":6148},[6124,24656,24657,24659,24662,24664],{"class":6126,"line":6199},[6124,24658,14629],{"class":6483},[6124,24660,24661],{"class":14632}," baseURL",[6124,24663,14638],{"class":6479},[6124,24665,24666],{"class":6503},"\"http:\u002F\u002Flocalhost:8080\u002Fv1\"\n",[6124,24668,24669],{"class":6126,"line":6204},[6124,24670,6149],{"emptyLinePlaceholder":6148},[6124,24672,24673,24675,24677,24679],{"class":6126,"line":6209},[6124,24674,14614],{"class":6483},[6124,24676,17131],{"class":9605},[6124,24678,10513],{"class":6483},[6124,24680,10516],{"class":6479},[6124,24682,24683,24685,24687],{"class":6126,"line":6215},[6124,24684,17140],{"class":9667},[6124,24686,17278],{"class":9605},[6124,24688,24689],{"class":6503}," `json:\"id\"`\n",[6124,24691,24692,24694,24696],{"class":6126,"line":6221},[6124,24693,16723],{"class":9667},[6124,24695,10525],{"class":9605},[6124,24697,10528],{"class":6503},[6124,24699,24700,24702,24704],{"class":6126,"line":6227},[6124,24701,16732],{"class":9667},[6124,24703,10525],{"class":9605},[6124,24705,10539],{"class":6503},[6124,24707,24708,24710,24712],{"class":6126,"line":6232},[6124,24709,17182],{"class":9667},[6124,24711,10525],{"class":9605},[6124,24713,24714],{"class":6503}," `json:\"status\"`\n",[6124,24716,24717],{"class":6126,"line":6237},[6124,24718,6167],{"class":6479},[6124,24720,24721],{"class":6126,"line":6243},[6124,24722,6149],{"emptyLinePlaceholder":6148},[6124,24724,24725,24727,24729],{"class":6126,"line":6249},[6124,24726,9656],{"class":6483},[6124,24728,9659],{"class":9578},[6124,24730,9662],{"class":6479},[6124,24732,24733,24735,24738,24740,24742,24744,24747,24750,24753],{"class":6126,"line":6255},[6124,24734,10551],{"class":6476},[6124,24736,24737],{"class":9578}," len",[6124,24739,9704],{"class":6479},[6124,24741,21037],{"class":9667},[6124,24743,5787],{"class":6479},[6124,24745,24746],{"class":9667},"Args",[6124,24748,24749],{"class":6479},") \u003C ",[6124,24751,24752],{"class":6490},"2",[6124,24754,10516],{"class":6479},[6124,24756,24757,24760,24762,24764,24766,24769],{"class":6126,"line":6261},[6124,24758,24759],{"class":9667},"        fmt",[6124,24761,5787],{"class":6479},[6124,24763,15951],{"class":9578},[6124,24765,9704],{"class":6479},[6124,24767,24768],{"class":6503},"\"Usage: cli [get|create|list] [args...]\"",[6124,24770,9647],{"class":6479},[6124,24772,24773,24776,24778,24781,24783,24785],{"class":6126,"line":6267},[6124,24774,24775],{"class":9667},"        os",[6124,24777,5787],{"class":6479},[6124,24779,24780],{"class":9578},"Exit",[6124,24782,9704],{"class":6479},[6124,24784,8576],{"class":6490},[6124,24786,9647],{"class":6479},[6124,24788,24789],{"class":6126,"line":6272},[6124,24790,10545],{"class":6479},[6124,24792,24793],{"class":6126,"line":6278},[6124,24794,6149],{"emptyLinePlaceholder":6148},[6124,24796,24797,24800,24802,24804,24806,24808,24810,24812],{"class":6126,"line":6284},[6124,24798,24799],{"class":9667},"    command",[6124,24801,9671],{"class":6479},[6124,24803,21037],{"class":9667},[6124,24805,5787],{"class":6479},[6124,24807,24746],{"class":9667},[6124,24809,10081],{"class":6479},[6124,24811,8576],{"class":6490},[6124,24813,7926],{"class":6479},[6124,24815,24816],{"class":6126,"line":6290},[6124,24817,6149],{"emptyLinePlaceholder":6148},[6124,24819,24820,24823,24826],{"class":6126,"line":6296},[6124,24821,24822],{"class":6476},"    switch",[6124,24824,24825],{"class":9667}," command",[6124,24827,10516],{"class":6479},[6124,24829,24830,24832,24835],{"class":6126,"line":6301},[6124,24831,13118],{"class":6476},[6124,24833,24834],{"class":6503}," \"get\"",[6124,24836,24837],{"class":6479},":\n",[6124,24839,24840,24842,24844,24846,24848,24850,24852,24854,24857],{"class":6126,"line":6307},[6124,24841,11955],{"class":6476},[6124,24843,24737],{"class":9578},[6124,24845,9704],{"class":6479},[6124,24847,21037],{"class":9667},[6124,24849,5787],{"class":6479},[6124,24851,24746],{"class":9667},[6124,24853,24749],{"class":6479},[6124,24855,24856],{"class":6490},"3",[6124,24858,10516],{"class":6479},[6124,24860,24861,24864,24866,24868,24870,24873],{"class":6126,"line":6313},[6124,24862,24863],{"class":9667},"            fmt",[6124,24865,5787],{"class":6479},[6124,24867,15951],{"class":9578},[6124,24869,9704],{"class":6479},[6124,24871,24872],{"class":6503},"\"Usage: cli get \u003Corder_id>\"",[6124,24874,9647],{"class":6479},[6124,24876,24877,24880,24882,24884,24886,24888],{"class":6126,"line":6319},[6124,24878,24879],{"class":9667},"            os",[6124,24881,5787],{"class":6479},[6124,24883,24780],{"class":9578},[6124,24885,9704],{"class":6479},[6124,24887,8576],{"class":6490},[6124,24889,9647],{"class":6479},[6124,24891,24892],{"class":6126,"line":6324},[6124,24893,12002],{"class":6479},[6124,24895,24896,24899,24901,24903,24905,24907,24909,24911],{"class":6126,"line":8100},[6124,24897,24898],{"class":9578},"        getOrder",[6124,24900,9704],{"class":6479},[6124,24902,21037],{"class":9667},[6124,24904,5787],{"class":6479},[6124,24906,24746],{"class":9667},[6124,24908,10081],{"class":6479},[6124,24910,24752],{"class":6490},[6124,24912,24913],{"class":6479},"])\n",[6124,24915,24916,24918,24921],{"class":6126,"line":8106},[6124,24917,13118],{"class":6476},[6124,24919,24920],{"class":6503}," \"create\"",[6124,24922,24837],{"class":6479},[6124,24924,24925,24928],{"class":6126,"line":8112},[6124,24926,24927],{"class":9578},"        createOrder",[6124,24929,9682],{"class":6479},[6124,24931,24932,24934,24937],{"class":6126,"line":8117},[6124,24933,13118],{"class":6476},[6124,24935,24936],{"class":6503}," \"list\"",[6124,24938,24837],{"class":6479},[6124,24940,24941,24943,24945,24947,24949,24951,24953,24955,24957],{"class":6126,"line":8123},[6124,24942,11955],{"class":6476},[6124,24944,24737],{"class":9578},[6124,24946,9704],{"class":6479},[6124,24948,21037],{"class":9667},[6124,24950,5787],{"class":6479},[6124,24952,24746],{"class":9667},[6124,24954,24749],{"class":6479},[6124,24956,24856],{"class":6490},[6124,24958,10516],{"class":6479},[6124,24960,24961,24963,24965,24967,24969,24972],{"class":6126,"line":8129},[6124,24962,24863],{"class":9667},[6124,24964,5787],{"class":6479},[6124,24966,15951],{"class":9578},[6124,24968,9704],{"class":6479},[6124,24970,24971],{"class":6503},"\"Usage: cli list \u003Cuser_id>\"",[6124,24973,9647],{"class":6479},[6124,24975,24976,24978,24980,24982,24984,24986],{"class":6126,"line":8135},[6124,24977,24879],{"class":9667},[6124,24979,5787],{"class":6479},[6124,24981,24780],{"class":9578},[6124,24983,9704],{"class":6479},[6124,24985,8576],{"class":6490},[6124,24987,9647],{"class":6479},[6124,24989,24990],{"class":6126,"line":8141},[6124,24991,12002],{"class":6479},[6124,24993,24994,24997,24999,25001,25003,25005,25007,25009],{"class":6126,"line":8146},[6124,24995,24996],{"class":9578},"        listOrders",[6124,24998,9704],{"class":6479},[6124,25000,21037],{"class":9667},[6124,25002,5787],{"class":6479},[6124,25004,24746],{"class":9667},[6124,25006,10081],{"class":6479},[6124,25008,24752],{"class":6490},[6124,25010,24913],{"class":6479},[6124,25012,25013,25016],{"class":6126,"line":10209},[6124,25014,25015],{"class":6476},"    default",[6124,25017,24837],{"class":6479},[6124,25019,25020,25022,25024,25026,25028,25031,25033,25036],{"class":6126,"line":10242},[6124,25021,24759],{"class":9667},[6124,25023,5787],{"class":6479},[6124,25025,15951],{"class":9578},[6124,25027,9704],{"class":6479},[6124,25029,25030],{"class":6503},"\"Unknown command:\"",[6124,25032,5259],{"class":6479},[6124,25034,25035],{"class":9667},"command",[6124,25037,9647],{"class":6479},[6124,25039,25040],{"class":6126,"line":10274},[6124,25041,10545],{"class":6479},[6124,25043,25044],{"class":6126,"line":10279},[6124,25045,6167],{"class":6479},[6124,25047,25048],{"class":6126,"line":10284},[6124,25049,6149],{"emptyLinePlaceholder":6148},[6124,25051,25052,25054,25056,25058,25060,25062],{"class":6126,"line":10289},[6124,25053,9656],{"class":6483},[6124,25055,23615],{"class":9578},[6124,25057,9704],{"class":6479},[6124,25059,10428],{"class":9667},[6124,25061,10525],{"class":9605},[6124,25063,9817],{"class":6479},[6124,25065,25066,25069,25071,25073,25075,25077,25079,25081,25083,25085,25087,25089,25091,25093,25095,25097,25099,25101,25103,25106,25108,25110],{"class":6126,"line":10321},[6124,25067,25068],{"class":9667},"    resp",[6124,25070,5259],{"class":6479},[6124,25072,10590],{"class":9667},[6124,25074,9671],{"class":6479},[6124,25076,6469],{"class":9667},[6124,25078,5787],{"class":6479},[6124,25080,9751],{"class":9578},[6124,25082,9704],{"class":6479},[6124,25084,14010],{"class":9667},[6124,25086,5787],{"class":6479},[6124,25088,14015],{"class":9578},[6124,25090,9704],{"class":6479},[6124,25092,11182],{"class":6503},[6124,25094,11179],{"class":9667},[6124,25096,24162],{"class":6503},[6124,25098,11179],{"class":9667},[6124,25100,11182],{"class":6503},[6124,25102,5259],{"class":6479},[6124,25104,25105],{"class":9667},"baseURL",[6124,25107,5259],{"class":6479},[6124,25109,10428],{"class":9667},[6124,25111,10015],{"class":6479},[6124,25113,25114,25116,25118,25120,25122],{"class":6126,"line":10327},[6124,25115,10551],{"class":6476},[6124,25117,10554],{"class":9667},[6124,25119,10593],{"class":6479},[6124,25121,10596],{"class":6483},[6124,25123,10516],{"class":6479},[6124,25125,25126,25128,25130,25132,25134,25137,25139,25141],{"class":6126,"line":10353},[6124,25127,24759],{"class":9667},[6124,25129,5787],{"class":6479},[6124,25131,15951],{"class":9578},[6124,25133,9704],{"class":6479},[6124,25135,25136],{"class":6503},"\"Error:\"",[6124,25138,5259],{"class":6479},[6124,25140,10590],{"class":9667},[6124,25142,9647],{"class":6479},[6124,25144,25145],{"class":6126,"line":10359},[6124,25146,10635],{"class":6476},[6124,25148,25149],{"class":6126,"line":10365},[6124,25150,10545],{"class":6479},[6124,25152,25153,25155,25158,25160,25162,25164,25166],{"class":6126,"line":10388},[6124,25154,10646],{"class":6476},[6124,25156,25157],{"class":9667}," resp",[6124,25159,5787],{"class":6479},[6124,25161,10573],{"class":9667},[6124,25163,5787],{"class":6479},[6124,25165,10658],{"class":9578},[6124,25167,9682],{"class":6479},[6124,25169,25170],{"class":6126,"line":10419},[6124,25171,6149],{"emptyLinePlaceholder":6148},[6124,25173,25174,25176,25178,25180,25183,25185,25187,25189,25191],{"class":6126,"line":10433},[6124,25175,10551],{"class":6476},[6124,25177,25157],{"class":9667},[6124,25179,5787],{"class":6479},[6124,25181,25182],{"class":9667},"StatusCode",[6124,25184,10593],{"class":6479},[6124,25186,6469],{"class":9667},[6124,25188,5787],{"class":6479},[6124,25190,10897],{"class":9667},[6124,25192,10516],{"class":6479},[6124,25194,25195,25197,25199,25201,25203,25205],{"class":6126,"line":10445},[6124,25196,24759],{"class":9667},[6124,25198,5787],{"class":6479},[6124,25200,15951],{"class":9578},[6124,25202,9704],{"class":6479},[6124,25204,20454],{"class":6503},[6124,25206,9647],{"class":6479},[6124,25208,25209],{"class":6126,"line":10457},[6124,25210,10635],{"class":6476},[6124,25212,25213],{"class":6126,"line":10462},[6124,25214,10545],{"class":6479},[6124,25216,25217],{"class":6126,"line":10467},[6124,25218,6149],{"emptyLinePlaceholder":6148},[6124,25220,25221,25223,25225],{"class":6126,"line":10472},[6124,25222,10507],{"class":6483},[6124,25224,19032],{"class":9667},[6124,25226,25227],{"class":9605}," Order\n",[6124,25229,25230,25232,25234,25236,25238,25241,25243,25245,25247,25249,25251,25253],{"class":6126,"line":10504},[6124,25231,10059],{"class":9667},[6124,25233,5787],{"class":6479},[6124,25235,10564],{"class":9578},[6124,25237,9704],{"class":6479},[6124,25239,25240],{"class":9667},"resp",[6124,25242,5787],{"class":6479},[6124,25244,10573],{"class":9667},[6124,25246,5407],{"class":6479},[6124,25248,10578],{"class":9578},[6124,25250,10581],{"class":6479},[6124,25252,18764],{"class":9667},[6124,25254,9647],{"class":6479},[6124,25256,25257,25259,25261,25263,25265,25268,25271,25275,25277,25279,25281],{"class":6126,"line":10519},[6124,25258,11162],{"class":9667},[6124,25260,5787],{"class":6479},[6124,25262,11718],{"class":9578},[6124,25264,9704],{"class":6479},[6124,25266,25267],{"class":6503},"\"Order: ",[6124,25269,25270],{"class":9667},"%+v",[6124,25272,25274],{"class":25273},"sjcCO","\\n",[6124,25276,11182],{"class":6503},[6124,25278,5259],{"class":6479},[6124,25280,18764],{"class":9667},[6124,25282,9647],{"class":6479},[6124,25284,25285],{"class":6126,"line":10531},[6124,25286,6167],{"class":6479},[6124,25288,25289],{"class":6126,"line":10542},[6124,25290,6149],{"emptyLinePlaceholder":6148},[6124,25292,25293,25295,25297],{"class":6126,"line":10548},[6124,25294,9656],{"class":6483},[6124,25296,23868],{"class":9578},[6124,25298,9662],{"class":6479},[6124,25300,25301,25304,25306,25308,25310,25312,25314,25316],{"class":6126,"line":10601},[6124,25302,25303],{"class":9667},"    reqBody",[6124,25305,9671],{"class":6479},[6124,25307,10078],{"class":6483},[6124,25309,10081],{"class":6479},[6124,25311,10084],{"class":9605},[6124,25313,10087],{"class":6479},[6124,25315,10084],{"class":9605},[6124,25317,6543],{"class":6479},[6124,25319,25320,25322,25324,25326],{"class":6126,"line":10632},[6124,25321,10764],{"class":6503},[6124,25323,6552],{"class":6479},[6124,25325,7554],{"class":6503},[6124,25327,6558],{"class":6479},[6124,25329,25330,25332,25334,25336],{"class":6126,"line":10638},[6124,25331,10436],{"class":6503},[6124,25333,10783],{"class":6479},[6124,25335,9162],{"class":6503},[6124,25337,6558],{"class":6479},[6124,25339,25340,25342,25344,25346],{"class":6126,"line":10643},[6124,25341,22982],{"class":6503},[6124,25343,10783],{"class":6479},[6124,25345,9173],{"class":6503},[6124,25347,6558],{"class":6479},[6124,25349,25350],{"class":6126,"line":10663},[6124,25351,10545],{"class":6479},[6124,25353,25354,25356,25358,25360,25362,25364,25366,25368,25370,25373],{"class":6126,"line":10668},[6124,25355,22998],{"class":9667},[6124,25357,5259],{"class":6479},[6124,25359,17445],{"class":9667},[6124,25361,9671],{"class":6479},[6124,25363,10559],{"class":9667},[6124,25365,5787],{"class":6479},[6124,25367,17454],{"class":9578},[6124,25369,9704],{"class":6479},[6124,25371,25372],{"class":9667},"reqBody",[6124,25374,9647],{"class":6479},[6124,25376,25377],{"class":6126,"line":10674},[6124,25378,6149],{"emptyLinePlaceholder":6148},[6124,25380,25381,25383,25385,25387,25389,25391,25393,25395],{"class":6126,"line":10695},[6124,25382,25068],{"class":9667},[6124,25384,5259],{"class":6479},[6124,25386,10590],{"class":9667},[6124,25388,9671],{"class":6479},[6124,25390,6469],{"class":9667},[6124,25392,5787],{"class":6479},[6124,25394,9847],{"class":9578},[6124,25396,19108],{"class":6479},[6124,25398,25399,25401,25403,25405,25407,25409,25411,25414,25416,25418],{"class":6126,"line":10718},[6124,25400,24759],{"class":9667},[6124,25402,5787],{"class":6479},[6124,25404,14015],{"class":9578},[6124,25406,9704],{"class":6479},[6124,25408,11182],{"class":6503},[6124,25410,11179],{"class":9667},[6124,25412,25413],{"class":6503},"\u002Forders\"",[6124,25415,5259],{"class":6479},[6124,25417,25105],{"class":9667},[6124,25419,14052],{"class":6479},[6124,25421,25422,25425],{"class":6126,"line":10749},[6124,25423,25424],{"class":6503},"        \"application\u002Fjson\"",[6124,25426,6558],{"class":6479},[6124,25428,25429,25432,25434,25436,25438,25440],{"class":6126,"line":10761},[6124,25430,25431],{"class":9667},"        bytes",[6124,25433,5787],{"class":6479},[6124,25435,23220],{"class":9578},[6124,25437,9704],{"class":6479},[6124,25439,6460],{"class":9667},[6124,25441,14052],{"class":6479},[6124,25443,25444],{"class":6126,"line":10778},[6124,25445,19201],{"class":6479},[6124,25447,25448,25450,25452,25454,25456],{"class":6126,"line":10795},[6124,25449,10551],{"class":6476},[6124,25451,10554],{"class":9667},[6124,25453,10593],{"class":6479},[6124,25455,10596],{"class":6483},[6124,25457,10516],{"class":6479},[6124,25459,25460,25462,25464,25466,25468,25470,25472,25474],{"class":6126,"line":10806},[6124,25461,24759],{"class":9667},[6124,25463,5787],{"class":6479},[6124,25465,15951],{"class":9578},[6124,25467,9704],{"class":6479},[6124,25469,25136],{"class":6503},[6124,25471,5259],{"class":6479},[6124,25473,10590],{"class":9667},[6124,25475,9647],{"class":6479},[6124,25477,25478],{"class":6126,"line":10811},[6124,25479,10635],{"class":6476},[6124,25481,25482],{"class":6126,"line":10816},[6124,25483,10545],{"class":6479},[6124,25485,25486,25488,25490,25492,25494,25496,25498],{"class":6126,"line":10821},[6124,25487,10646],{"class":6476},[6124,25489,25157],{"class":9667},[6124,25491,5787],{"class":6479},[6124,25493,10573],{"class":9667},[6124,25495,5787],{"class":6479},[6124,25497,10658],{"class":9578},[6124,25499,9682],{"class":6479},[6124,25501,25502],{"class":6126,"line":10853},[6124,25503,6149],{"emptyLinePlaceholder":6148},[6124,25505,25506,25508,25510],{"class":6126,"line":10876},[6124,25507,10507],{"class":6483},[6124,25509,19032],{"class":9667},[6124,25511,25227],{"class":9605},[6124,25513,25514,25516,25518,25520,25522,25524,25526,25528,25530,25532,25534,25536],{"class":6126,"line":10882},[6124,25515,10059],{"class":9667},[6124,25517,5787],{"class":6479},[6124,25519,10564],{"class":9578},[6124,25521,9704],{"class":6479},[6124,25523,25240],{"class":9667},[6124,25525,5787],{"class":6479},[6124,25527,10573],{"class":9667},[6124,25529,5407],{"class":6479},[6124,25531,10578],{"class":9578},[6124,25533,10581],{"class":6479},[6124,25535,18764],{"class":9667},[6124,25537,9647],{"class":6479},[6124,25539,25540,25542,25544,25546,25548,25551,25553,25555,25557,25559,25561],{"class":6126,"line":10902},[6124,25541,11162],{"class":9667},[6124,25543,5787],{"class":6479},[6124,25545,11718],{"class":9578},[6124,25547,9704],{"class":6479},[6124,25549,25550],{"class":6503},"\"Created order: ",[6124,25552,25270],{"class":9667},[6124,25554,25274],{"class":25273},[6124,25556,11182],{"class":6503},[6124,25558,5259],{"class":6479},[6124,25560,18764],{"class":9667},[6124,25562,9647],{"class":6479},[6124,25564,25565],{"class":6126,"line":10950},[6124,25566,6167],{"class":6479},[6124,25568,25569],{"class":6126,"line":10955},[6124,25570,6149],{"emptyLinePlaceholder":6148},[6124,25572,25573,25575,25577,25579,25581,25583],{"class":6126,"line":10960},[6124,25574,9656],{"class":6483},[6124,25576,24471],{"class":9578},[6124,25578,9704],{"class":6479},[6124,25580,10261],{"class":9667},[6124,25582,10525],{"class":9605},[6124,25584,9817],{"class":6479},[6124,25586,25587,25589,25591,25593,25595,25597,25599,25601,25603,25605,25607,25609,25611,25613,25615,25617,25619,25621,25623,25625,25627,25629],{"class":6126,"line":10992},[6124,25588,25068],{"class":9667},[6124,25590,5259],{"class":6479},[6124,25592,10590],{"class":9667},[6124,25594,9671],{"class":6479},[6124,25596,6469],{"class":9667},[6124,25598,5787],{"class":6479},[6124,25600,9751],{"class":9578},[6124,25602,9704],{"class":6479},[6124,25604,14010],{"class":9667},[6124,25606,5787],{"class":6479},[6124,25608,14015],{"class":9578},[6124,25610,9704],{"class":6479},[6124,25612,11182],{"class":6503},[6124,25614,11179],{"class":9667},[6124,25616,24506],{"class":6503},[6124,25618,11179],{"class":9667},[6124,25620,11182],{"class":6503},[6124,25622,5259],{"class":6479},[6124,25624,25105],{"class":9667},[6124,25626,5259],{"class":6479},[6124,25628,10261],{"class":9667},[6124,25630,10015],{"class":6479},[6124,25632,25633,25635,25637,25639,25641],{"class":6126,"line":11015},[6124,25634,10551],{"class":6476},[6124,25636,10554],{"class":9667},[6124,25638,10593],{"class":6479},[6124,25640,10596],{"class":6483},[6124,25642,10516],{"class":6479},[6124,25644,25645,25647,25649,25651,25653,25655,25657,25659],{"class":6126,"line":11021},[6124,25646,24759],{"class":9667},[6124,25648,5787],{"class":6479},[6124,25650,15951],{"class":9578},[6124,25652,9704],{"class":6479},[6124,25654,25136],{"class":6503},[6124,25656,5259],{"class":6479},[6124,25658,10590],{"class":9667},[6124,25660,9647],{"class":6479},[6124,25662,25663],{"class":6126,"line":11041},[6124,25664,10635],{"class":6476},[6124,25666,25667],{"class":6126,"line":16092},[6124,25668,10545],{"class":6479},[6124,25670,25671,25673,25675,25677,25679,25681,25683],{"class":6126,"line":16097},[6124,25672,10646],{"class":6476},[6124,25674,25157],{"class":9667},[6124,25676,5787],{"class":6479},[6124,25678,10573],{"class":9667},[6124,25680,5787],{"class":6479},[6124,25682,10658],{"class":9578},[6124,25684,9682],{"class":6479},[6124,25686,25687],{"class":6126,"line":16102},[6124,25688,6149],{"emptyLinePlaceholder":6148},[6124,25690,25691,25693,25696,25699],{"class":6126,"line":16108},[6124,25692,10507],{"class":6483},[6124,25694,25695],{"class":9667}," orders",[6124,25697,25698],{"class":6479}," []",[6124,25700,19040],{"class":9605},[6124,25702,25703,25705,25707,25709,25711,25713,25715,25717,25719,25721,25723,25725],{"class":6126,"line":16147},[6124,25704,10059],{"class":9667},[6124,25706,5787],{"class":6479},[6124,25708,10564],{"class":9578},[6124,25710,9704],{"class":6479},[6124,25712,25240],{"class":9667},[6124,25714,5787],{"class":6479},[6124,25716,10573],{"class":9667},[6124,25718,5407],{"class":6479},[6124,25720,10578],{"class":9578},[6124,25722,10581],{"class":6479},[6124,25724,14491],{"class":9667},[6124,25726,9647],{"class":6479},[6124,25728,25729,25731,25734,25736,25738,25740,25742,25744],{"class":6126,"line":16183},[6124,25730,17492],{"class":6476},[6124,25732,25733],{"class":9667}," _",[6124,25735,5259],{"class":6479},[6124,25737,18764],{"class":9667},[6124,25739,9671],{"class":6479},[6124,25741,17505],{"class":6476},[6124,25743,25695],{"class":9667},[6124,25745,10516],{"class":6479},[6124,25747,25748,25750,25752,25754,25756,25759,25761,25763,25765,25767,25769,25772,25774,25776,25778,25780,25782,25784,25786,25788,25790,25792,25794,25796,25798,25800],{"class":6126,"line":16218},[6124,25749,24759],{"class":9667},[6124,25751,5787],{"class":6479},[6124,25753,11718],{"class":9578},[6124,25755,9704],{"class":6479},[6124,25757,25758],{"class":6503},"\"- ",[6124,25760,11179],{"class":9667},[6124,25762,6552],{"class":6503},[6124,25764,11179],{"class":9667},[6124,25766,5222],{"class":6503},[6124,25768,11179],{"class":9667},[6124,25770,25771],{"class":6503},")",[6124,25773,25274],{"class":25273},[6124,25775,11182],{"class":6503},[6124,25777,5259],{"class":6479},[6124,25779,18764],{"class":9667},[6124,25781,5787],{"class":6479},[6124,25783,14442],{"class":9667},[6124,25785,5259],{"class":6479},[6124,25787,18764],{"class":9667},[6124,25789,5787],{"class":6479},[6124,25791,10790],{"class":9667},[6124,25793,5259],{"class":6479},[6124,25795,18764],{"class":9667},[6124,25797,5787],{"class":6479},[6124,25799,17630],{"class":9667},[6124,25801,9647],{"class":6479},[6124,25803,25804],{"class":6126,"line":16253},[6124,25805,10545],{"class":6479},[6124,25807,25808],{"class":6126,"line":16288},[6124,25809,6167],{"class":6479},[25811,25812,25814,25828,25837,25840,25850,25857,25860,25870,25874],"terminal-preview",{":cursor":8823,"title":25813},"Використання CLI-утиліти",[25815,25816,25818,5333,25823],"div",{"className":25817},[6126],[6124,25819,25822],{"className":25820},[25821],"opacity-40","$",[5205,25824,25827],{"className":25825},[25826],"font-bold","go run cmd\u002Fcli\u002Fmain.go create",[25815,25829,25831,25836],{"className":25830},[6126],[6124,25832,25835],{"className":25833},[25834,25826],"text-green-400","Created order:"," {ID:order_789 UserID:user_123 Recipe:latte Status:pending}",[25815,25838],{"className":25839},[6126],[25815,25841,25843,5333,25846],{"className":25842},[6126],[6124,25844,25822],{"className":25845},[25821],[5205,25847,25849],{"className":25848},[25826],"go run cmd\u002Fcli\u002Fmain.go get order_789",[25815,25851,25853,25836],{"className":25852},[6126],[6124,25854,25856],{"className":25855},[25834,25826],"Order:",[25815,25858],{"className":25859},[6126],[25815,25861,25863,5333,25866],{"className":25862},[6126],[6124,25864,25822],{"className":25865},[25821],[5205,25867,25869],{"className":25868},[25826],"go run cmd\u002Fcli\u002Fmain.go list user_123",[25815,25871,25873],{"className":25872},[6126],"- order_789: latte (pending)",[25815,25875,25877],{"className":25876},[6126],"- order_456: espresso (completed)",[5366,25879],{},[5369,25881,25883],{"id":25882},"підсумки-та-ключові-висновки","Підсумки та ключові висновки",[5190,25885,25886,25934],{},[5193,25887,25890],{"icon":25888,"title":25889},"i-lucide-check-circle","✅ Що ми вивчили",[5198,25891,25892,25898,25904,25910,25916,25922,25928],{},[5201,25893,25894,25897],{},[5205,25895,25896],{},"Еволюцію від RPC до HTTP API:"," Зрозуміли, чому HTTP став універсальною мовою інтернету та як REST-принципи допомагають будувати масштабовані системи.",[5201,25899,25900,25903],{},[5205,25901,25902],{},"Архітектурний стиль REST:"," Розібралися з дисертацією Філдінга, міфологією REST та практичним визначенням JSON-over-HTTP API.",[5201,25905,25906,25909],{},[5205,25907,25908],{},"Складові HTTP:"," Детально вивчили URL, заголовки, HTTP-методи, статус-коди та їхню семантику.",[5201,25911,25912,25915],{},[5205,25913,25914],{},"Проєктування номенклатури URL:"," Навчилися організовувати ієрархію ресурсів, дотримуватися конвенцій найменування та реалізовувати CRUD-операції.",[5201,25917,25918,25921],{},[5205,25919,25920],{},"Маршрутизатор Chi:"," Опанували параметри шляху, групування маршрутів, middleware та чисту інтеграцію зі стандартною бібліотекою.",[5201,25923,25924,25927],{},[5205,25925,25926],{},"Clean Architecture:"," Побачили розділення на шари Domain, Repository, UseCase, Delivery та ручне впровадження залежностей.",[5201,25929,25930,25933],{},[5205,25931,25932],{},"Інтеграцію з клієнтами:"," Навчилися взаємодіяти з гетерогенними клієнтами (Desktop, Mobile, CLI).",[5193,25935,25938],{"icon":25936,"title":25937},"i-lucide-target","🎯 Практичні навички",[5198,25939,25940,25943,25946,25949,25952,25958],{},[5201,25941,25942],{},"Проєктування RESTful API з дотриманням принципів ідемпотентності та stateless-дизайну.",[5201,25944,25945],{},"Використання маршрутизатора Chi для організації складних маршрутів із middleware.",[5201,25947,25948],{},"Серіалізація\u002Fдесеріалізація JSON та формування стандартизованих відповідей про помилки (RFC 7807).",[5201,25950,25951],{},"Організація коду за принципами Clean Architecture для підтримки масштабованості.",[5201,25953,25954,25955,25957],{},"Тестування HTTP-обробників засобами ",[5288,25956,22567],{}," та мокування залежностей.",[5201,25959,25960],{},"Забезпечення інтероперабельності API з різними платформами клієнтів.",[5713,25962,25963,25976,25994,26020],{},[5716,25964,25966,25967,25969,25970,25972,25973,25975],{"icon":5718,"label":25965},"❓ Чому варто використовувати Chi замість стандартного ServeMux?","Стандартний ",[5288,25968,9529],{}," має обмежену функціональність: немає параметрів шляху (",[5288,25971,9541],{},"), немає middleware, складно організувати групування маршрутів. Chi вирішує всі ці проблеми, залишаючись сумісним з ",[5288,25974,9562],{}," та не додаючи надлишкової «магії».",[5716,25977,25979,25981,25982,25984,25985,5333,25987,25990,25991,25993],{"icon":5718,"label":25978},"❓ Чому POST не є ідемпотентним, а PUT є?",[5288,25980,5262],{}," обробляє запит «відповідно до внутрішньої семантики ресурсу». Це означає, що повторний виклик ",[5288,25983,7158],{}," може створити два різні замовлення. Натомість ",[5288,25986,7140],{},[5205,25988,25989],{},"замінює"," ресурс з фіксованим ID ",[5288,25992,6555],{}," — повторний виклик залишає ресурс у тому самому стані.",[5716,25995,25997,26017],{"icon":5718,"label":25996},"❓ Коли використовувати PUT, а коли PATCH?",[5198,25998,25999,26009],{},[5201,26000,26001,26004,26005,26008],{},[5205,26002,26003],{},"PUT:"," Коли ви хочете ",[5205,26006,26007],{},"повністю замінити"," ресурс. Усі поля, не передані у запиті, мають бути скинуті до значень за замовчуванням.",[5201,26010,26011,26004,26014,9395],{},[5205,26012,26013],{},"PATCH:",[5205,26015,26016],{},"частково оновити",[5379,26018,26019],{},"На практиці PATCH використовується частіше, оскільки клієнту зручніше відправляти тільки змінені поля.",[5716,26021,26023,26028,26037],{"icon":5718,"label":26022},"❓ Чому версія API розміщується у шляху, а не у заголовку?",[5379,26024,26025,26026,8342],{},"Розміщення версії у шляху (",[5288,26027,8317],{},[5444,26029,26030,26032,26035],{},[5201,26031,8347],{},[5201,26033,26034],{},"Різні версії API можуть бути легко проксовані на різні сервери.",[5201,26036,8353],{},[5379,26038,26039,26040,26042,26043,26045],{},"Альтернативи (заголовок ",[5288,26041,8330],{}," або параметр запиту ",[5288,26044,8326],{},") менш інтуїтивні та гірше підтримуються інструментами.",[5366,26047],{},[5379,26049,26050,26053],{},[5205,26051,26052],{},"Наступна лекція:"," Шарувата архітектура та конвеєри обробки запитів (Middleware Pipeline, Clean Architecture, Dependency Injection, тестування HTTP-шару).",[5366,26055],{},[5369,26057,26059],{"id":26058},"робота-з-помилками-у-http-api-стандартизовані-підходи","Робота з помилками у HTTP API: стандартизовані підходи",[5374,26061,26063],{"id":26062},"проблема-обробки-помилок","Проблема обробки помилок",[5379,26065,26066],{},"Розглянемо типовий запит створення замовлення:",[5530,26068,26070],{"className":6467,"code":26069,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Forders?user_id=user_123 HTTP\u002F1.1\nAuthorization: Bearer \u003Ctoken>\nIf-Match: \u003Crevision>\n\n{ \"recipe\": \"espresso\", \"volume\": \"50ml\" }\n",[5288,26071,26072,26084,26092,26102,26106],{"__ignoreMap":5538},[6124,26073,26074,26076,26078,26080,26082],{"class":6126,"line":6127},[6124,26075,5262],{"class":6476},[6124,26077,7826],{"class":6479},[6124,26079,6484],{"class":6483},[6124,26081,6487],{"class":6479},[6124,26083,6491],{"class":6490},[6124,26085,26086,26088,26090],{"class":6126,"line":6133},[6124,26087,6519],{"class":6496},[6124,26089,6500],{"class":6483},[6124,26091,7524],{"class":6503},[6124,26093,26094,26097,26099],{"class":6126,"line":6139},[6124,26095,26096],{"class":6496},"If-Match",[6124,26098,6500],{"class":6483},[6124,26100,26101],{"class":6503}," \u003Crevision>\n",[6124,26103,26104],{"class":6126,"line":6145},[6124,26105,6149],{"emptyLinePlaceholder":6148},[6124,26107,26108,26111,26113,26115,26117,26119,26122,26124,26126],{"class":6126,"line":6152},[6124,26109,26110],{"class":6479},"{ ",[6124,26112,7619],{"class":6548},[6124,26114,6552],{"class":6479},[6124,26116,7624],{"class":6503},[6124,26118,5259],{"class":6479},[6124,26120,26121],{"class":6548},"\"volume\"",[6124,26123,6552],{"class":6479},[6124,26125,9373],{"class":6503},[6124,26127,16144],{"class":6479},[5379,26129,26130],{},"Які потенційні помилки можуть виникнути?",[5444,26132,26133,26136,26139,26142,26145,26148,26151,26154,26157,26160,26163,26166],{},[5201,26134,26135],{},"Запит не може бути прочитаний (некоректний JSON, порушення синтаксису).",[5201,26137,26138],{},"Токен авторизації відсутній.",[5201,26140,26141],{},"Токен авторизації невалідний або прострочений.",[5201,26143,26144],{},"Токен валідний, але користувач не має прав створювати замовлення.",[5201,26146,26147],{},"Користувач видалений або деактивований.",[5201,26149,26150],{},"Ідентифікатор користувача неправильний (не існує).",[5201,26152,26153],{},"Ревізія не передана або не збігається з актуальною.",[5201,26155,26156],{},"У тілі запиту відсутні обов'язкові поля.",[5201,26158,26159],{},"Якесь поле має недопустиме значення.",[5201,26161,26162],{},"Перевищено ліміти на кількість запитів (Rate Limit).",[5201,26164,26165],{},"Сервер перевантажений і не може відповісти зараз.",[5201,26167,26168],{},"Невідома серверна помилка (критичний збій).",[5379,26170,26171,26172,26175],{},"Спокуса призначити кожній помилці свій статус-код здається очевидною, але перш ніж це робити, треба відповісти на питання: ",[5205,26173,26174],{},"з якою метою"," ми хочемо призначити той чи інший код?",[5374,26177,26179],{"id":26178},"три-актори-системи-та-їхні-потреби","Три актори системи та їхні потреби",[5379,26181,26182,26183,5259,26186,6374,26189,26192],{},"У системі присутні три актори: ",[5205,26184,26185],{},"користувач застосунку",[5205,26187,26188],{},"клієнтський застосунок",[5205,26190,26191],{},"сервер",". Кожному з них потрібно розуміти чотири аспекти помилки:",[5444,26194,26195,26201,26207,26213],{},[5201,26196,26197,26200],{},[5205,26198,26199],{},"Хто допустив помилку?"," Користувач, розробник клієнта, розробник сервера чи проміжний агент (наприклад, проксі)?",[5201,26202,26203,26206],{},[5205,26204,26205],{},"Чи можна виправити помилку простим повторенням запиту?"," Якщо так, через який час?",[5201,26208,26209,26212],{},[5205,26210,26211],{},"Чи можна виправити помилку переформулюванням запиту?"," Які саме зміни потрібні?",[5201,26214,26215,26218],{},[5205,26216,26217],{},"Якщо помилку неможливо виправити, що робити?"," Як інформувати користувача?",[5379,26220,26221,26222,26224,26225,26227,26228,26231],{},"HTTP частково допомагає відповісти на перше питання через першу цифру статус-коду (",[5288,26223,7300],{}," — клієнтська помилка, ",[5288,26226,7317],{}," — серверна). Для регулювання часу повторного запиту можна використовувати заголовок ",[5288,26229,26230],{},"Retry-After"," та параметри кешування. Але з іншими питаннями ситуація складніша.",[5374,26233,26235],{"id":26234},"клієнтські-помилки-4xx-недостатність-стандартних-кодів","Клієнтські помилки (4xx): недостатність стандартних кодів",[5379,26237,26238,26239,26241,26242,26245,26246,26248],{},"Статус-коди ",[5288,26240,7300],{}," індикують, що помилка допущена користувачем або клієнтом. ",[5205,26243,26244],{},"Зазвичай"," отриману ",[5288,26247,7300],{}," повторювати безглуздо — без додаткових дій для зміни стану сервісу цей запит ніколи не буде виконано успішно.",[5379,26250,26251,5333,26254,26257,26258,26260],{},[5205,26252,26253],{},"Виняток:",[5288,26255,26256],{},"429 Too Many Requests"," (варто повторити через деякий час) та ",[5288,26259,6340],{}," (може бути «станом невизначеності» — сервер може не розкривати причину помилки).",[5379,26262,26263,26265,26266,26269],{},[5205,26264,8636],{}," Номенклатура HTTP-кодів ",[5205,26267,26268],{},"недостатня для опису помилок бізнес-логіки",". Наприклад:",[5198,26271,26272,26281,26289,26298,26303,26308],{},[5201,26273,26274,26276,26277,26280],{},[5288,26275,7304],{}," використовується для ",[5205,26278,26279],{},"будь-яких"," помилок валідації (некоректний JSON, відсутні поля, недопустимі значення).",[5201,26282,26283,26285,26286,26288],{},[5288,26284,7416],{}," для ",[5205,26287,26279],{}," проблем авторизації.",[5201,26290,26291,26293,26294,26297],{},[5288,26292,6340],{}," коли ресурс не знайдено ",[5205,26295,26296],{},"або"," коли сервер не хоче розкривати причину.",[5201,26299,26300,26302],{},[5288,26301,7427],{}," при порушенні цілісності даних.",[5201,26304,26305,26307],{},[5288,26306,7312],{}," коли запит синтаксично коректний, але семантично помилковий.",[5201,26309,26310,26312,26313,26316],{},[5288,26311,26256],{}," при перевищенні лімітів (але немає стандартного способу вказати, ",[5205,26314,26315],{},"який саме"," ліміт перевищено).",[5480,26318,26319,26322,26323,26326],{},[5205,26320,26321],{},"Обмеженість стандартних кодів:"," Фактично, велика кількість різних помилок у логіці застосунку повертається під дуже малим набором статус-кодів. Це означає, що ",[5205,26324,26325],{},"потрібна додаткова метаінформація"," про підтип помилки у заголовках або тілі відповіді.",[6994,26328,26330],{"id":26329},"проблема-ідентифікації-типу-помилки","Проблема ідентифікації типу помилки",[5379,26332,26333],{},"HTTP надає спеціалізовані коди для проблем із самим протоколом:",[5198,26335,26336,26342,26351,26359,26365],{},[5201,26337,26338,26341],{},[5288,26339,26340],{},"405 Method Not Allowed"," — даний метод не застосовний до вказаного ресурсу.",[5201,26343,26344,26347,26348,26350],{},[5288,26345,26346],{},"406 Not Acceptable"," — сервер не може повернути відповідь згідно з ",[5288,26349,6897],{},"-заголовками.",[5201,26352,26353,26356,26357,5787],{},[5288,26354,26355],{},"411 Length Required"," — відсутній заголовок ",[5288,26358,6529],{},[5201,26360,26361,26364],{},[5288,26362,26363],{},"414 URI Too Long"," — URL занадто довгий.",[5201,26366,26367,26370,26371,5787],{},[5288,26368,26369],{},"415 Unsupported Media Type"," — непідтримуваний ",[5288,26372,6509],{},[5379,26374,26375,26376,26379,26380,26382],{},"Але всі вони ",[5205,26377,26378],{},"погано застосовні до помилок бізнес-логіки",". Ми не можемо повернути ",[5288,26381,26256],{}," при перевищенні різних лімітів та розрізнити їх: чи це ліміт на кількість замовлень на день, чи ліміт на кількість запитів на хвилину, чи ліміт на розмір замовлення.",[6994,26384,26386],{"id":26385},"de-facto-стандарти-vs-формальна-специфікація","De-facto стандарти vs формальна специфікація",[5379,26388,26389,26390,26392,26393,5946,26396,26399,26400,26403,26404,26407,26408,26411],{},"Сьогодні де-факто стандартом є повернення коду ",[5288,26391,7307],{}," при ",[5205,26394,26395],{},"відсутності заголовків авторизації",[5205,26397,26398],{},"невалідному токені"," (отримання цього коду є сигналом для застосунку запропонувати користувачу залогінитися). Це ",[5205,26401,26402],{},"суперечить формальній специфікації",", яка вимагає при поверненні ",[5288,26405,26406],{},"401"," обов'язково вказувати заголовок ",[5288,26409,26410],{},"WWW-Authenticate"," з описом способу автентифікації користувача.",[5409,26413,26414,26417,26418,26420,26421,26423,26424,26426],{},[5205,26415,26416],{},"Практика vs стандарт:"," Нам невідомі реальні публічні API, які виконують вимогу щодо ",[5288,26419,26410],{}," при поверненні ",[5288,26422,26406],{},". Розробники API використовують ",[5288,26425,26406],{}," для індикації «потрібна автентифікація», а не «потрібна автентифікація за конкретною схемою».",[5374,26428,26430],{"id":26429},"розширений-формат-опису-помилок-rfc-7807-та-практичні-розширення","Розширений формат опису помилок: RFC 7807 та практичні розширення",[5379,26432,26433,26436,26437,26440,26441,5787],{},[5205,26434,26435],{},"Рішення:"," Використовувати статус-код згідно з його семантикою для індикації ",[5205,26438,26439],{},"роду"," помилки та вкладені метадані\u002Fтіло у спеціально розробленому форматі для ",[5205,26442,26443],{},"деталізації",[5379,26445,26446],{},"Розробники стандарту HTTP усвідомлюють цю проблему та рекомендують передавати у метаданих або тілі відповіді додаткові дані для опису помилки:",[26448,26449,26450],"blockquote",{},[5379,26451,26452],{},"\"The server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition.\"",[5379,26454,26455,26456,26459],{},"Стандарт RFC 7807 (",[5224,26457,26458],{},"Problem Details for HTTP APIs",") запропонував формат JSON-опису HTTP-помилок, але він покриває лише базовий сценарій:",[5198,26461,26462,26465,26468],{},[5201,26463,26464],{},"Підтип помилки не передається у метаінформації.",[5201,26466,26467],{},"Немає розділення на повідомлення для користувача та повідомлення для розробника.",[5201,26469,26470],{},"Конкретний машино-читабельний формат опису помилок залишається на розсуд розробника.",[6994,26472,26474],{"id":26473},"детальний-приклад-складна-валідаційна-помилка","Детальний приклад: складна валідаційна помилка",[5379,26476,26477],{},"Розглянемо реалістичний приклад пошуку кавоварок із множинними помилками валідації:",[5530,26479,26481],{"className":6467,"code":26480,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Fcoffee-machines\u002Fsearch HTTP\u002F1.1\n\n{\n  \"recipes\": [\"lngo\"],\n  \"position\": {\n    \"latitude\": 110,\n    \"longitude\": 55\n  }\n}\n\n→ HTTP\u002F1.1 400 Bad Request\nX-CoffeeAPI-Error-Kind: validation_failed\nContent-Type: application\u002Fproblem+json\n\n{\n  \"type\": \"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Fvalidation-failed\",\n  \"title\": \"Validation Failed\",\n  \"status\": 400,\n  \"detail\": \"Request contains invalid field values\",\n  \"instance\": \"\u002Fv1\u002Fcoffee-machines\u002Fsearch\",\n  \"errors\": [\n    {\n      \"field\": \"recipes[0]\",\n      \"error_type\": \"unknown_value\",\n      \"message\": \"Value 'lngo' is unknown. Did you mean 'lungo'?\",\n      \"hint\": \"lungo\"\n    },\n    {\n      \"field\": \"position.latitude\",\n      \"error_type\": \"constraint_violation\",\n      \"message\": \"Latitude must be between -90 and 90\",\n      \"constraints\": {\n        \"min\": -90,\n        \"max\": 90\n      }\n    }\n  ]\n}\n",[5288,26482,26483,26496,26500,26504,26516,26523,26535,26545,26549,26553,26557,26569,26574,26579,26583,26587,26598,26609,26620,26631,26642,26649,26654,26666,26678,26690,26700,26705,26709,26720,26731,26742,26749,26761,26771,26775,26779,26783],{"__ignoreMap":5538},[6124,26484,26485,26487,26490,26492,26494],{"class":6126,"line":6127},[6124,26486,5262],{"class":6476},[6124,26488,26489],{"class":6479}," \u002Fv1\u002Fcoffee-machines\u002Fsearch ",[6124,26491,6484],{"class":6483},[6124,26493,6487],{"class":6479},[6124,26495,6491],{"class":6490},[6124,26497,26498],{"class":6126,"line":6133},[6124,26499,6149],{"emptyLinePlaceholder":6148},[6124,26501,26502],{"class":6126,"line":6139},[6124,26503,6543],{"class":6479},[6124,26505,26506,26509,26511,26514],{"class":6126,"line":6145},[6124,26507,26508],{"class":6548},"  \"recipes\"",[6124,26510,8990],{"class":6479},[6124,26512,26513],{"class":6503},"\"lngo\"",[6124,26515,8999],{"class":6479},[6124,26517,26518,26521],{"class":6126,"line":6152},[6124,26519,26520],{"class":6548},"  \"position\"",[6124,26522,6590],{"class":6479},[6124,26524,26525,26528,26530,26533],{"class":6126,"line":6158},[6124,26526,26527],{"class":6548},"    \"latitude\"",[6124,26529,6552],{"class":6479},[6124,26531,26532],{"class":6490},"110",[6124,26534,6558],{"class":6479},[6124,26536,26537,26540,26542],{"class":6126,"line":6164},[6124,26538,26539],{"class":6548},"    \"longitude\"",[6124,26541,6552],{"class":6479},[6124,26543,26544],{"class":6490},"55\n",[6124,26546,26547],{"class":6126,"line":6170},[6124,26548,6617],{"class":6479},[6124,26550,26551],{"class":6126,"line":6175},[6124,26552,6167],{"class":6479},[6124,26554,26555],{"class":6126,"line":6181},[6124,26556,6149],{"emptyLinePlaceholder":6148},[6124,26558,26559,26561,26563,26566],{"class":6126,"line":6187},[6124,26560,8559],{"class":6479},[6124,26562,8562],{"class":6490},[6124,26564,26565],{"class":6490}," 400",[6124,26567,26568],{"class":6479}," Bad Request\n",[6124,26570,26571],{"class":6126,"line":6193},[6124,26572,26573],{"class":6479},"X-CoffeeAPI-Error-Kind: validation_failed\n",[6124,26575,26576],{"class":6126,"line":6199},[6124,26577,26578],{"class":6479},"Content-Type: application\u002Fproblem+json\n",[6124,26580,26581],{"class":6126,"line":6204},[6124,26582,6149],{"emptyLinePlaceholder":6148},[6124,26584,26585],{"class":6126,"line":6209},[6124,26586,6543],{"class":6479},[6124,26588,26589,26591,26593,26596],{"class":6126,"line":6215},[6124,26590,17887],{"class":6548},[6124,26592,6552],{"class":6479},[6124,26594,26595],{"class":6503},"\"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Fvalidation-failed\"",[6124,26597,6558],{"class":6479},[6124,26599,26600,26602,26604,26607],{"class":6126,"line":6221},[6124,26601,17898],{"class":6548},[6124,26603,6552],{"class":6479},[6124,26605,26606],{"class":6503},"\"Validation Failed\"",[6124,26608,6558],{"class":6479},[6124,26610,26611,26613,26615,26618],{"class":6126,"line":6227},[6124,26612,8622],{"class":6548},[6124,26614,6552],{"class":6479},[6124,26616,26617],{"class":6490},"400",[6124,26619,6558],{"class":6479},[6124,26621,26622,26624,26626,26629],{"class":6126,"line":6232},[6124,26623,17919],{"class":6548},[6124,26625,6552],{"class":6479},[6124,26627,26628],{"class":6503},"\"Request contains invalid field values\"",[6124,26630,6558],{"class":6479},[6124,26632,26633,26635,26637,26640],{"class":6126,"line":6237},[6124,26634,17931],{"class":6548},[6124,26636,6552],{"class":6479},[6124,26638,26639],{"class":6503},"\"\u002Fv1\u002Fcoffee-machines\u002Fsearch\"",[6124,26641,6558],{"class":6479},[6124,26643,26644,26647],{"class":6126,"line":6243},[6124,26645,26646],{"class":6548},"  \"errors\"",[6124,26648,7591],{"class":6479},[6124,26650,26651],{"class":6126,"line":6249},[6124,26652,26653],{"class":6479},"    {\n",[6124,26655,26656,26659,26661,26664],{"class":6126,"line":6255},[6124,26657,26658],{"class":6548},"      \"field\"",[6124,26660,6552],{"class":6479},[6124,26662,26663],{"class":6503},"\"recipes[0]\"",[6124,26665,6558],{"class":6479},[6124,26667,26668,26671,26673,26676],{"class":6126,"line":6261},[6124,26669,26670],{"class":6548},"      \"error_type\"",[6124,26672,6552],{"class":6479},[6124,26674,26675],{"class":6503},"\"unknown_value\"",[6124,26677,6558],{"class":6479},[6124,26679,26680,26683,26685,26688],{"class":6126,"line":6267},[6124,26681,26682],{"class":6548},"      \"message\"",[6124,26684,6552],{"class":6479},[6124,26686,26687],{"class":6503},"\"Value 'lngo' is unknown. Did you mean 'lungo'?\"",[6124,26689,6558],{"class":6479},[6124,26691,26692,26695,26697],{"class":6126,"line":6272},[6124,26693,26694],{"class":6548},"      \"hint\"",[6124,26696,6552],{"class":6479},[6124,26698,26699],{"class":6503},"\"lungo\"\n",[6124,26701,26702],{"class":6126,"line":6278},[6124,26703,26704],{"class":6479},"    },\n",[6124,26706,26707],{"class":6126,"line":6284},[6124,26708,26653],{"class":6479},[6124,26710,26711,26713,26715,26718],{"class":6126,"line":6290},[6124,26712,26658],{"class":6548},[6124,26714,6552],{"class":6479},[6124,26716,26717],{"class":6503},"\"position.latitude\"",[6124,26719,6558],{"class":6479},[6124,26721,26722,26724,26726,26729],{"class":6126,"line":6296},[6124,26723,26670],{"class":6548},[6124,26725,6552],{"class":6479},[6124,26727,26728],{"class":6503},"\"constraint_violation\"",[6124,26730,6558],{"class":6479},[6124,26732,26733,26735,26737,26740],{"class":6126,"line":6301},[6124,26734,26682],{"class":6548},[6124,26736,6552],{"class":6479},[6124,26738,26739],{"class":6503},"\"Latitude must be between -90 and 90\"",[6124,26741,6558],{"class":6479},[6124,26743,26744,26747],{"class":6126,"line":6307},[6124,26745,26746],{"class":6548},"      \"constraints\"",[6124,26748,6590],{"class":6479},[6124,26750,26751,26754,26756,26759],{"class":6126,"line":6313},[6124,26752,26753],{"class":6548},"        \"min\"",[6124,26755,6552],{"class":6479},[6124,26757,26758],{"class":6490},"-90",[6124,26760,6558],{"class":6479},[6124,26762,26763,26766,26768],{"class":6126,"line":6319},[6124,26764,26765],{"class":6548},"        \"max\"",[6124,26767,6552],{"class":6479},[6124,26769,26770],{"class":6490},"90\n",[6124,26772,26773],{"class":6126,"line":6324},[6124,26774,24558],{"class":6479},[6124,26776,26777],{"class":6126,"line":8100},[6124,26778,10545],{"class":6479},[6124,26780,26781],{"class":6126,"line":8106},[6124,26782,7663],{"class":6479},[6124,26784,26785],{"class":6126,"line":8112},[6124,26786,6167],{"class":6479},[5379,26788,26789],{},[5205,26790,26791],{},"Переваги такого підходу:",[5444,26793,26794,26800,26805,26811],{},[5201,26795,26796,26799],{},[5205,26797,26798],{},"Машино-читабельність:"," Клієнт може програмно обробити кожну помилку валідації окремо.",[5201,26801,26802,26804],{},[5205,26803,6006],{}," Розробник одразу бачить усі проблеми у читабельному форматі.",[5201,26806,26807,26810],{},[5205,26808,26809],{},"Відновлюваність:"," Клієнт знає, які саме поля виправити.",[5201,26812,26813,26816],{},[5205,26814,26815],{},"Розширюваність:"," Можна додавати нові типи помилок без зміни базового формату.",[5374,26818,26820],{"id":26819},"серверні-помилки-5xx-мінімалістичний-підхід","Серверні помилки (5xx): мінімалістичний підхід",[5379,26822,26823,26824,26826,26827,26830],{},"Помилки ",[5288,26825,7317],{}," індикують, що клієнт виконав запит правильно, але ",[5205,26828,26829],{},"проблема на стороні сервера",". Для клієнта важливо лише:",[5444,26832,26833,26836],{},[5201,26834,26835],{},"Чи має сенс повторювати запит?",[5201,26837,26838],{},"Якщо так, через який час?",[5379,26840,26841,26844,26845,26848],{},[5205,26842,26843],{},"Для публічних API"," причини серверних помилок зазвичай ",[5205,26846,26847],{},"не розкриваються",". Достатньо двох кодів:",[5198,26850,26851,26856],{},[5201,26852,26853,26855],{},[5288,26854,7321],{}," — загальна серверна помилка.",[5201,26857,26858,26860],{},[5288,26859,7327],{}," — сервіс тимчасово недоступний, можна повторити запит через деякий час.",[5379,26862,26863,26866,26867,26870],{},[5205,26864,26865],{},"Для внутрішніх систем"," серверні помилки повинні містити ",[5205,26868,26869],{},"підтип помилки"," у машино-читабельному вигляді для побудови правильних моніторингів та систем оповіщення.",[5379,26872,26873],{},[5205,26874,26875],{},"Приклад для внутрішнього API:",[5530,26877,26879],{"className":6467,"code":26878,"language":6469,"meta":5538,"style":5538},"POST \u002Fv1\u002Forders?user_id=user_123 HTTP\u002F1.1\nIf-Match: \u003Crevision>\n\n→ HTTP\u002F1.1 500 Internal Server Error\nX-CoffeeAPI-Error-Kind: database_timeout\nRetry-After: 5\n\n{\n  \"type\": \"https:\u002F\u002Finternal.coffeeshop.dev\u002Ferrors\u002Fdatabase-timeout\",\n  \"title\": \"Database Timeout\",\n  \"status\": 500,\n  \"detail\": \"Database query exceeded 5s timeout\",\n  \"instance\": \"\u002Fv1\u002Forders\",\n  \"database_host\": \"postgres-primary-01.internal\"\n}\n",[5288,26880,26881,26893,26901,26905,26910,26920,26929,26933,26937,26948,26959,26970,26981,26992,27002],{"__ignoreMap":5538},[6124,26882,26883,26885,26887,26889,26891],{"class":6126,"line":6127},[6124,26884,5262],{"class":6476},[6124,26886,7826],{"class":6479},[6124,26888,6484],{"class":6483},[6124,26890,6487],{"class":6479},[6124,26892,6491],{"class":6490},[6124,26894,26895,26897,26899],{"class":6126,"line":6133},[6124,26896,26096],{"class":6496},[6124,26898,6500],{"class":6483},[6124,26900,26101],{"class":6503},[6124,26902,26903],{"class":6126,"line":6139},[6124,26904,6149],{"emptyLinePlaceholder":6148},[6124,26906,26907],{"class":6126,"line":6145},[6124,26908,26909],{"class":6479},"→ HTTP\u002F1.1 500 Internal Server Error\n",[6124,26911,26912,26915,26917],{"class":6126,"line":6152},[6124,26913,26914],{"class":6496},"X-CoffeeAPI-Error-Kind",[6124,26916,6500],{"class":6483},[6124,26918,26919],{"class":6503}," database_timeout\n",[6124,26921,26922,26924,26926],{"class":6126,"line":6158},[6124,26923,26230],{"class":6496},[6124,26925,6500],{"class":6483},[6124,26927,26928],{"class":6503}," 5\n",[6124,26930,26931],{"class":6126,"line":6164},[6124,26932,6149],{"emptyLinePlaceholder":6148},[6124,26934,26935],{"class":6126,"line":6170},[6124,26936,6543],{"class":6479},[6124,26938,26939,26941,26943,26946],{"class":6126,"line":6175},[6124,26940,17887],{"class":6548},[6124,26942,6552],{"class":6479},[6124,26944,26945],{"class":6503},"\"https:\u002F\u002Finternal.coffeeshop.dev\u002Ferrors\u002Fdatabase-timeout\"",[6124,26947,6558],{"class":6479},[6124,26949,26950,26952,26954,26957],{"class":6126,"line":6181},[6124,26951,17898],{"class":6548},[6124,26953,6552],{"class":6479},[6124,26955,26956],{"class":6503},"\"Database Timeout\"",[6124,26958,6558],{"class":6479},[6124,26960,26961,26963,26965,26968],{"class":6126,"line":6187},[6124,26962,8622],{"class":6548},[6124,26964,6552],{"class":6479},[6124,26966,26967],{"class":6490},"500",[6124,26969,6558],{"class":6479},[6124,26971,26972,26974,26976,26979],{"class":6126,"line":6193},[6124,26973,17919],{"class":6548},[6124,26975,6552],{"class":6479},[6124,26977,26978],{"class":6503},"\"Database query exceeded 5s timeout\"",[6124,26980,6558],{"class":6479},[6124,26982,26983,26985,26987,26990],{"class":6126,"line":6199},[6124,26984,17931],{"class":6548},[6124,26986,6552],{"class":6479},[6124,26988,26989],{"class":6503},"\"\u002Fv1\u002Forders\"",[6124,26991,6558],{"class":6479},[6124,26993,26994,26997,26999],{"class":6126,"line":6204},[6124,26995,26996],{"class":6548},"  \"database_host\"",[6124,26998,6552],{"class":6479},[6124,27000,27001],{"class":6503},"\"postgres-primary-01.internal\"\n",[6124,27003,27004],{"class":6126,"line":6209},[6124,27005,6167],{"class":6479},[5379,27007,27008],{},[5205,27009,27010],{},"Приклад для публічного API (після обробки шлюзом):",[5530,27012,27014],{"className":6467,"code":27013,"language":6469,"meta":5538,"style":5538},"→ HTTP\u002F1.1 500 Internal Server Error\nRetry-After: 5\nContent-Type: application\u002Fproblem+json\n\n{\n  \"type\": \"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Finternal-error\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"An unexpected error occurred. Please try again later.\",\n  \"instance\": \"\u002Fv1\u002Forders\",\n  \"can_retry\": true,\n  \"localized_message\": \"Не вдалося отримати відповідь від сервера. Спробуйте повторити операцію через кілька секунд.\"\n}\n",[5288,27015,27016,27020,27028,27037,27041,27045,27056,27067,27077,27088,27098,27109,27119],{"__ignoreMap":5538},[6124,27017,27018],{"class":6126,"line":6127},[6124,27019,26909],{"class":6479},[6124,27021,27022,27024,27026],{"class":6126,"line":6133},[6124,27023,26230],{"class":6496},[6124,27025,6500],{"class":6483},[6124,27027,26928],{"class":6503},[6124,27029,27030,27032,27034],{"class":6126,"line":6139},[6124,27031,6509],{"class":6496},[6124,27033,6500],{"class":6483},[6124,27035,27036],{"class":6503}," application\u002Fproblem+json\n",[6124,27038,27039],{"class":6126,"line":6145},[6124,27040,6149],{"emptyLinePlaceholder":6148},[6124,27042,27043],{"class":6126,"line":6152},[6124,27044,6543],{"class":6479},[6124,27046,27047,27049,27051,27054],{"class":6126,"line":6158},[6124,27048,17887],{"class":6548},[6124,27050,6552],{"class":6479},[6124,27052,27053],{"class":6503},"\"https:\u002F\u002Fapi.coffeeshop.dev\u002Ferrors\u002Finternal-error\"",[6124,27055,6558],{"class":6479},[6124,27057,27058,27060,27062,27065],{"class":6126,"line":6164},[6124,27059,17898],{"class":6548},[6124,27061,6552],{"class":6479},[6124,27063,27064],{"class":6503},"\"Internal Server Error\"",[6124,27066,6558],{"class":6479},[6124,27068,27069,27071,27073,27075],{"class":6126,"line":6170},[6124,27070,8622],{"class":6548},[6124,27072,6552],{"class":6479},[6124,27074,26967],{"class":6490},[6124,27076,6558],{"class":6479},[6124,27078,27079,27081,27083,27086],{"class":6126,"line":6175},[6124,27080,17919],{"class":6548},[6124,27082,6552],{"class":6479},[6124,27084,27085],{"class":6503},"\"An unexpected error occurred. Please try again later.\"",[6124,27087,6558],{"class":6479},[6124,27089,27090,27092,27094,27096],{"class":6126,"line":6181},[6124,27091,17931],{"class":6548},[6124,27093,6552],{"class":6479},[6124,27095,26989],{"class":6503},[6124,27097,6558],{"class":6479},[6124,27099,27100,27103,27105,27107],{"class":6126,"line":6187},[6124,27101,27102],{"class":6548},"  \"can_retry\"",[6124,27104,6552],{"class":6479},[6124,27106,8823],{"class":6483},[6124,27108,6558],{"class":6479},[6124,27110,27111,27114,27116],{"class":6126,"line":6193},[6124,27112,27113],{"class":6548},"  \"localized_message\"",[6124,27115,6552],{"class":6479},[6124,27117,27118],{"class":6503},"\"Не вдалося отримати відповідь від сервера. Спробуйте повторити операцію через кілька секунд.\"\n",[6124,27120,27121],{"class":6126,"line":6199},[6124,27122,6167],{"class":6479},[5409,27124,27125,27128],{},[5205,27126,27127],{},"Видалення чутливих деталей:"," API-шлюз видаляє внутрішні деталі помилки (назву хоста бази даних, stack traces) перед поверненням відповіді клієнту, залишаючи лише загальну інструкцію для користувача.",[5374,27130,27132],{"id":27131},"три-стратегії-обробки-помилок-у-http-api","Три стратегії обробки помилок у HTTP API",[5444,27134,27135,27141,27167],{},[5201,27136,27137,27140],{},[5205,27138,27139],{},"Розширювальна трактовка статус-кодів:"," Використовувати новий код для кожного виду помилки (часто порушуючи стандарт).",[5201,27142,27143,27146,27147,27149,27150],{},[5205,27144,27145],{},"Відмова від статус-кодів:"," Завжди повертати ",[5288,27148,7274],{}," та вкладати опис помилки у тіло відповіді (підхід більшості RPC-фреймворків).",[5198,27151,27152],{},[5201,27153,27154,27157,27158,27160,27161,27163,27164,27166],{},[5205,27155,27156],{},"Варіант 2a:"," Використовувати тільки два коди (",[5288,27159,26617],{}," для клієнтських, ",[5288,27162,26967],{}," для серверних), опціонально три (+ ",[5288,27165,7471],{}," для стану невизначеності).",[5201,27168,27169,27172,27173,27175,27176,5787],{},[5205,27170,27171],{},"Змішаний підхід (рекомендований):"," Використовувати статус-код згідно з семантикою для індикації ",[5205,27174,26439],{}," помилки та вкладені метадані\u002Fтіло для ",[5205,27177,26443],{},[5587,27179,27180,27183],{},[5205,27181,27182],{},"Рекомендація:"," Підхід (3) найкраще відповідає стандарту HTTP та забезпечує баланс між машино-читабельністю, людино-читабельністю та прозорістю для проміжних проксі.",[5366,27185],{},[5369,27187,27189],{"id":27188},"практичні-рекомендації-та-best-practices","Практичні рекомендації та best practices",[5374,27191,27193],{"id":27192},"code-style-та-конвенції","Code Style та конвенції",[5379,27195,27196],{},[5205,27197,27198],{},"Чеклист розробки якісного HTTP API:",[5800,27200,27201,27205,27208,27212,27215,27219,27222,27226,27229,27233,27236,27240],{},[5374,27202,27204],{"id":27203},"крок-1-описати-happy-path","Крок 1: Описати Happy Path",[5379,27206,27207],{},"Створіть діаграму викликів для стандартного циклу роботи клієнтського застосунку. Визначте послідовність операцій, які користувач виконує найчастіше.",[5374,27209,27211],{"id":27210},"крок-2-визначити-ресурси-та-операції","Крок 2: Визначити ресурси та операції",[5379,27213,27214],{},"Визначте кожен виклик як операцію над певним ресурсом. Складіть номенклатуру URL та застосовних методів. Переконайтеся, що URL відображають ієрархію ресурсів.",[5374,27216,27218],{"id":27217},"крок-3-описати-сценарії-помилок","Крок 3: Описати сценарії помилок",[5379,27220,27221],{},"Зрозумійте, які помилки можливі при виконанні кожної операції та яким чином клієнт має відновлюватися. Складіть матрицю: помилка → дія клієнта → очікуваний результат.",[5374,27223,27225],{"id":27224},"крок-4-розподілити-функціональність","Крок 4: Розподілити функціональність",[5379,27227,27228],{},"Вирішіть, яка функціональність буде передана на рівень протоколу HTTP (використання стандартних можливостей протоколу) та в якому обсязі. Визначте, які інструменти розробки будуть використані для кожної можливості.",[5374,27230,27232],{"id":27231},"крок-5-розробити-специфікацію","Крок 5: Розробити специфікацію",[5379,27234,27235],{},"На основі рішень із кроків 1-4 розробіть конкретну специфікацію API у форматі OpenAPI 3.0 або аналогічному.",[5374,27237,27239],{"id":27238},"крок-6-перевірити-зручність","Крок 6: Перевірити зручність",[5379,27241,27242],{},"Пройдіть по пунктах 1-3, напишіть псевдокод бізнес-логіки клієнтського застосунку згідно з розробленою специфікацією. Оцініть, наскільки зручним, зрозумілим та читабельним виявився результат.",[6994,27244,27246],{"id":27245},"конвенції-найменування-та-форматування","Конвенції найменування та форматування",[5444,27248,27249,27281,27312,27341,27393,27444],{},[5201,27250,27251,27254],{},[5205,27252,27253],{},"Уніфікація слешів у кінці URL:",[5198,27255,27256,27264,27275],{},[5201,27257,27258,27259,6374,27261,27263],{},"Не розрізняйте ",[5288,27260,8257],{},[5288,27262,24162],{}," — вони мають вести на той самий ресурс.",[5201,27265,27266,27268,27269,27271,27272,5407],{},[5205,27267,27182],{}," завжди завершуйте шляхи на ",[5288,27270,6487],{}," (дозволяє розумно описати звернення до кореня домену як ",[5288,27273,27274],{},"GET \u002F",[5201,27276,27277,27278,27280],{},"При зверненні до неправильного варіанту повертайте редирект (",[5288,27279,7289],{},") або зрозумілу помилку.",[5201,27282,27283,27286,27306,27308,27311],{},[5205,27284,27285],{},"Завжди повертайте JSON-об'єкт як корінь:",[5198,27287,27288,27296],{},[5201,27289,16650,27290,5333,27293],{},[5205,27291,27292],{},"Правильно:",[5288,27294,27295],{},"{\"users\": [...], \"total\": 150, \"page\": 1}",[5201,27297,27298,27299,5333,27302,27305],{},"❌ ",[5205,27300,27301],{},"Неправильно:",[5288,27303,27304],{},"[...]"," (масив у корені)",[6781,27307],{},[5205,27309,27310],{},"Причина:"," До об'єкта можна додати нові поля (наприклад, метадані пагінації) без порушення зворотної сумісності. До масиву або примітиву додати поля неможливо.",[5201,27313,27314,27317,27335,27337,27340],{},[5205,27315,27316],{},"Порожній об'єкт замість порожнього тіла:",[5198,27318,27319,27330],{},[5201,27320,16650,27321,5333,27323,27326,27327,27329],{},[5205,27322,27292],{},[5288,27324,27325],{},"{}"," (валідний JSON) або ",[5288,27328,7280],{}," без тіла",[5201,27331,27298,27332,27334],{},[5205,27333,27301],{}," порожня стрічка (не є валідним JSON)",[6781,27336],{},[5205,27338,27339],{},"Примітка:"," Порожня стрічка не є валідним JSON-документом згідно зі специфікацією.",[5201,27342,27343,27346,27373,27375,27378,27379,27382,27383,27385,27386,27388,27389,5946,27391,5407],{},[5205,27344,27345],{},"Консистентність кейсингу:",[5198,27347,27348,27357,27365],{},[5201,27349,27350,27352,27353,5259,27355],{},[5288,27351,8286],{}," для частин шляху: ",[5288,27354,8290],{},[5288,27356,8293],{},[5201,27358,27359,27361,27362],{},[5288,27360,8298],{}," для query-параметрів: ",[5288,27363,27364],{},"?user_id=123&order_status=pending",[5201,27366,27367,5946,27369,27372],{},[5288,27368,8298],{},[5288,27370,27371],{},"camelCase"," для JSON-полів (обирайте один стиль та дотримуйтесь його)",[6781,27374],{},[5205,27376,27377],{},"Правило трансформації:"," Якщо параметр переміщується між різними секціями запиту (з path у query, з query у body), кейсинг може змінюватися відповідно до конвенцій секції, але ",[5205,27380,27381],{},"ім'я"," параметра залишається тим самим (",[5288,27384,8163],{}," завжди ",[5288,27387,8163],{},", а не ",[5288,27390,24476],{},[5288,27392,10773],{},[5201,27394,27395,27398,27421,27423,27425,27426,5259,27429,5259,27431,5259,27433,5259,27435,5259,27438,5259,27440,27443],{},[5205,27396,27397],{},"Не використовуйте спеціальні символи у path та домені:",[5198,27399,27400,27408],{},[5201,27401,27298,27402,5333,27404,27407],{},[5205,27403,27301],{},[5288,27405,27406],{},"\u002Forders\u002Fuser@example.com"," (потребує екранування)",[5201,27409,16650,27410,5333,27412,5946,27415,16654,27417,27420],{},[5205,27411,27292],{},[5288,27413,27414],{},"\u002Forders?user_email=user@example.com",[5288,27416,8257],{},[5288,27418,27419],{},"user_email"," у тілі",[6781,27422],{},[5205,27424,27310],{}," Символи, які потребують екранування (",[5288,27427,27428],{},",",[5288,27430,6487],{},[5288,27432,6699],{},[5288,27434,6702],{},[5288,27436,27437],{},"@",[5288,27439,6727],{},[5288,27441,27442],{},"=","), створюють проблеми при парсингу URL.",[5201,27445,27446,27449],{},[5205,27447,27448],{},"Не передавайте масиви та вкладені об'єкти через query-параметри:",[5198,27450,27451,27458],{},[5201,27452,27298,27453,5333,27455],{},[5205,27454,27301],{},[5288,27456,27457],{},"?filters[0][field]=name&filters[0][value]=espresso",[5201,27459,16650,27460,27462,27463,27465],{},[5205,27461,27292],{}," використайте ",[5288,27464,5262],{}," з тілом запиту або Base64-кодований JSON у одному параметрі (останнє — крайній захід).",[6994,27467,27469],{"id":27468},"обовязкові-http-заголовки","Обов'язкові HTTP-заголовки",[5379,27471,27472],{},[5205,27473,27474],{},"Завжди включайте у відповіді наступні стандартні заголовки:",[5444,27476,27477,27498,27519,27548,27570,27577],{},[5201,27478,27479,27483,27484],{},[5205,27480,27481],{},[5288,27482,6909],{}," — таймстемп створення відповіді для синхронізації годинників:",[5530,27485,27487],{"className":6467,"code":27486,"language":6469,"meta":5538,"style":5538},"Date: Tue, 01 Sep 2026 14:30:00 GMT\n",[5288,27488,27489],{"__ignoreMap":5538},[6124,27490,27491,27493,27495],{"class":6126,"line":6127},[6124,27492,6909],{"class":6496},[6124,27494,6500],{"class":6483},[6124,27496,27497],{"class":6503}," Tue, 01 Sep 2026 14:30:00 GMT\n",[5201,27499,27500,27504,27505],{},[5205,27501,27502],{},[5288,27503,6509],{}," — MIME-тип вмісту відповіді:",[5530,27506,27508],{"className":6467,"code":27507,"language":6469,"meta":5538,"style":5538},"Content-Type: application\u002Fjson; charset=utf-8\n",[5288,27509,27510],{"__ignoreMap":5538},[6124,27511,27512,27514,27516],{"class":6126,"line":6127},[6124,27513,6509],{"class":6496},[6124,27515,6500],{"class":6483},[6124,27517,27518],{"class":6503}," application\u002Fjson; charset=utf-8\n",[5201,27520,27521,27525,27526,27540,27542,27545,27546,5787],{},[5205,27522,27523],{},[5288,27524,6529],{}," — розмір тіла відповіді у байтах:",[5530,27527,27529],{"className":6467,"code":27528,"language":6469,"meta":5538,"style":5538},"Content-Length: 1247\n",[5288,27530,27531],{"__ignoreMap":5538},[6124,27532,27533,27535,27537],{"class":6126,"line":6127},[6124,27534,6529],{"class":6496},[6124,27536,6500],{"class":6483},[6124,27538,27539],{"class":6503}," 1247\n",[6781,27541],{},[5205,27543,27544],{},"Важливо:"," Деякі проксі взагалі не пропускають відповіді без ",[5288,27547,6529],{},[5201,27549,27550,27555,27556],{},[5205,27551,27552],{},[5288,27553,27554],{},"Content-Encoding"," — використане стиснення (якщо застосовується):",[5530,27557,27559],{"className":6467,"code":27558,"language":6469,"meta":5538,"style":5538},"Content-Encoding: gzip\n",[5288,27560,27561],{"__ignoreMap":5538},[6124,27562,27563,27565,27567],{"class":6126,"line":6127},[6124,27564,27554],{"class":6496},[6124,27566,6500],{"class":6483},[6124,27568,27569],{"class":6503}," gzip\n",[5201,27571,27572,27576],{},[5205,27573,27574],{},[5288,27575,7770],{}," — політика кешування для GET-запитів (детальніше нижче).",[5201,27578,27579,27583,27584,5259,27587,6500,27590],{},[5205,27580,27581],{},[5288,27582,26230],{}," — рекомендований час повторного запиту при помилках ",[5288,27585,27586],{},"429",[5288,27588,27589],{},"503",[5530,27591,27593],{"className":6467,"code":27592,"language":6469,"meta":5538,"style":5538},"Retry-After: 60\n",[5288,27594,27595],{"__ignoreMap":5538},[6124,27596,27597,27599,27601],{"class":6126,"line":6127},[6124,27598,26230],{"class":6496},[6124,27600,6500],{"class":6483},[6124,27602,27603],{"class":6503}," 60\n",[5480,27605,27606,27609],{},[5205,27607,27608],{},"Не покладайтеся на значення за замовчуванням:"," Навіть якщо протокол визначає значення за замовчуванням для деяких параметрів, завжди явно вказуйте їх у відповідях. Різні клієнти та проксі можуть інтерпретувати відсутні заголовки по-різному.",[6994,27611,27613],{"id":27612},"підтримка-cors-для-браузерних-клієнтів","Підтримка CORS для браузерних клієнтів",[5379,27615,27616,27617,5222,27620,27623],{},"Для публічних API, які мають використовуватися з браузерів, обов'язково реалізуйте підтримку ",[5205,27618,27619],{},"CORS",[5224,27621,27622],{},"Cross-Origin Resource Sharing","):",[5530,27625,27627],{"className":9594,"code":27626,"language":9579,"meta":5538,"style":5538},"func corsMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        origin := r.Header.Get(\"Origin\")\n        if origin != \"\" {\n            \u002F\u002F Для продакшену вказуйте конкретні домени замість \"*\"\n            w.Header().Set(\"Access-Control-Allow-Origin\", origin)\n            w.Header().Set(\"Access-Control-Allow-Methods\", \n                \"GET, POST, PUT, DELETE, PATCH, OPTIONS\")\n            w.Header().Set(\"Access-Control-Allow-Headers\", \n                \"Content-Type, Authorization, X-Request-ID\")\n            w.Header().Set(\"Access-Control-Allow-Credentials\", \"true\")\n            w.Header().Set(\"Access-Control-Max-Age\", \"86400\") \u002F\u002F 24 години\n        }\n\n        \u002F\u002F Обробка preflight-запитів\n        if r.Method == http.MethodOptions {\n            w.WriteHeader(http.StatusNoContent)\n            return\n        }\n\n        next.ServeHTTP(w, r)\n    })\n}\n",[5288,27628,27629,27655,27693,27717,27730,27735,27758,27777,27784,27802,27809,27833,27860,27864,27868,27872,27892,27910,27914,27918,27922,27940,27944],{"__ignoreMap":5538},[6124,27630,27631,27633,27635,27637,27639,27641,27643,27645,27647,27649,27651,27653],{"class":6126,"line":6127},[6124,27632,9656],{"class":6483},[6124,27634,11810],{"class":9578},[6124,27636,9704],{"class":6479},[6124,27638,11574],{"class":9667},[6124,27640,9970],{"class":9605},[6124,27642,5787],{"class":6479},[6124,27644,11581],{"class":9605},[6124,27646,7173],{"class":6479},[6124,27648,6469],{"class":9605},[6124,27650,5787],{"class":6479},[6124,27652,11581],{"class":9605},[6124,27654,10516],{"class":6479},[6124,27656,27657,27659,27661,27663,27665,27667,27669,27671,27673,27675,27677,27679,27681,27683,27685,27687,27689,27691],{"class":6126,"line":6133},[6124,27658,11596],{"class":6476},[6124,27660,9970],{"class":9667},[6124,27662,5787],{"class":6479},[6124,27664,11603],{"class":9578},[6124,27666,9704],{"class":6479},[6124,27668,9656],{"class":6483},[6124,27670,9704],{"class":6479},[6124,27672,9967],{"class":9667},[6124,27674,9970],{"class":9605},[6124,27676,5787],{"class":6479},[6124,27678,9975],{"class":9605},[6124,27680,5259],{"class":6479},[6124,27682,9806],{"class":9667},[6124,27684,9982],{"class":6479},[6124,27686,6469],{"class":9605},[6124,27688,5787],{"class":6479},[6124,27690,9989],{"class":9605},[6124,27692,9817],{"class":6479},[6124,27694,27695,27698,27700,27702,27704,27706,27708,27710,27712,27715],{"class":6126,"line":6139},[6124,27696,27697],{"class":9667},"        origin",[6124,27699,9671],{"class":6479},[6124,27701,9806],{"class":9667},[6124,27703,5787],{"class":6479},[6124,27705,10189],{"class":9667},[6124,27707,5787],{"class":6479},[6124,27709,9751],{"class":9578},[6124,27711,9704],{"class":6479},[6124,27713,27714],{"class":6503},"\"Origin\"",[6124,27716,9647],{"class":6479},[6124,27718,27719,27721,27724,27726,27728],{"class":6126,"line":6145},[6124,27720,11955],{"class":6476},[6124,27722,27723],{"class":9667}," origin",[6124,27725,10593],{"class":6479},[6124,27727,12143],{"class":6503},[6124,27729,10516],{"class":6479},[6124,27731,27732],{"class":6126,"line":6152},[6124,27733,27734],{"class":9691},"            \u002F\u002F Для продакшену вказуйте конкретні домени замість \"*\"\n",[6124,27736,27737,27739,27741,27743,27745,27747,27749,27751,27753,27756],{"class":6126,"line":6158},[6124,27738,11978],{"class":9667},[6124,27740,5787],{"class":6479},[6124,27742,10189],{"class":9578},[6124,27744,10167],{"class":6479},[6124,27746,10194],{"class":9578},[6124,27748,9704],{"class":6479},[6124,27750,11886],{"class":6503},[6124,27752,5259],{"class":6479},[6124,27754,27755],{"class":9667},"origin",[6124,27757,9647],{"class":6479},[6124,27759,27760,27762,27764,27766,27768,27770,27772,27774],{"class":6126,"line":6164},[6124,27761,11978],{"class":9667},[6124,27763,5787],{"class":6479},[6124,27765,10189],{"class":9578},[6124,27767,10167],{"class":6479},[6124,27769,10194],{"class":9578},[6124,27771,9704],{"class":6479},[6124,27773,11910],{"class":6503},[6124,27775,27776],{"class":6479},", \n",[6124,27778,27779,27782],{"class":6126,"line":6170},[6124,27780,27781],{"class":6503},"                \"GET, POST, PUT, DELETE, PATCH, OPTIONS\"",[6124,27783,9647],{"class":6479},[6124,27785,27786,27788,27790,27792,27794,27796,27798,27800],{"class":6126,"line":6175},[6124,27787,11978],{"class":9667},[6124,27789,5787],{"class":6479},[6124,27791,10189],{"class":9578},[6124,27793,10167],{"class":6479},[6124,27795,10194],{"class":9578},[6124,27797,9704],{"class":6479},[6124,27799,11934],{"class":6503},[6124,27801,27776],{"class":6479},[6124,27803,27804,27807],{"class":6126,"line":6181},[6124,27805,27806],{"class":6503},"                \"Content-Type, Authorization, X-Request-ID\"",[6124,27808,9647],{"class":6479},[6124,27810,27811,27813,27815,27817,27819,27821,27823,27826,27828,27831],{"class":6126,"line":6187},[6124,27812,11978],{"class":9667},[6124,27814,5787],{"class":6479},[6124,27816,10189],{"class":9578},[6124,27818,10167],{"class":6479},[6124,27820,10194],{"class":9578},[6124,27822,9704],{"class":6479},[6124,27824,27825],{"class":6503},"\"Access-Control-Allow-Credentials\"",[6124,27827,5259],{"class":6479},[6124,27829,27830],{"class":6503},"\"true\"",[6124,27832,9647],{"class":6479},[6124,27834,27835,27837,27839,27841,27843,27845,27847,27850,27852,27855,27857],{"class":6126,"line":6193},[6124,27836,11978],{"class":9667},[6124,27838,5787],{"class":6479},[6124,27840,10189],{"class":9578},[6124,27842,10167],{"class":6479},[6124,27844,10194],{"class":9578},[6124,27846,9704],{"class":6479},[6124,27848,27849],{"class":6503},"\"Access-Control-Max-Age\"",[6124,27851,5259],{"class":6479},[6124,27853,27854],{"class":6503},"\"86400\"",[6124,27856,7173],{"class":6479},[6124,27858,27859],{"class":9691},"\u002F\u002F 24 години\n",[6124,27861,27862],{"class":6126,"line":6199},[6124,27863,12002],{"class":6479},[6124,27865,27866],{"class":6126,"line":6204},[6124,27867,6149],{"emptyLinePlaceholder":6148},[6124,27869,27870],{"class":6126,"line":6209},[6124,27871,11950],{"class":9691},[6124,27873,27874,27876,27878,27880,27882,27884,27886,27888,27890],{"class":6126,"line":6215},[6124,27875,11955],{"class":6476},[6124,27877,10649],{"class":9667},[6124,27879,5787],{"class":6479},[6124,27881,11741],{"class":9667},[6124,27883,11964],{"class":6479},[6124,27885,6469],{"class":9667},[6124,27887,5787],{"class":6479},[6124,27889,11971],{"class":9667},[6124,27891,10516],{"class":6479},[6124,27893,27894,27896,27898,27900,27902,27904,27906,27908],{"class":6126,"line":6221},[6124,27895,11978],{"class":9667},[6124,27897,5787],{"class":6479},[6124,27899,10681],{"class":9578},[6124,27901,9704],{"class":6479},[6124,27903,6469],{"class":9667},[6124,27905,5787],{"class":6479},[6124,27907,11036],{"class":9667},[6124,27909,9647],{"class":6479},[6124,27911,27912],{"class":6126,"line":6227},[6124,27913,11997],{"class":6476},[6124,27915,27916],{"class":6126,"line":6232},[6124,27917,12002],{"class":6479},[6124,27919,27920],{"class":6126,"line":6237},[6124,27921,6149],{"emptyLinePlaceholder":6148},[6124,27923,27924,27926,27928,27930,27932,27934,27936,27938],{"class":6126,"line":6243},[6124,27925,11663],{"class":9667},[6124,27927,5787],{"class":6479},[6124,27929,11668],{"class":9578},[6124,27931,9704],{"class":6479},[6124,27933,9967],{"class":9667},[6124,27935,5259],{"class":6479},[6124,27937,9806],{"class":9667},[6124,27939,9647],{"class":6479},[6124,27941,27942],{"class":6126,"line":6249},[6124,27943,9922],{"class":6479},[6124,27945,27946],{"class":6126,"line":6255},[6124,27947,6167],{"class":6479},[5409,27949,27950,27953,27954,27957],{},[5205,27951,27952],{},"CORS (Cross-Origin Resource Sharing):"," Механізм безпеки браузерів, що дозволяє контролювати, які домени можуть звертатися до вашого API з JavaScript. Для публічних API без автентифікації можна використовувати ",[5288,27955,27956],{},"Access-Control-Allow-Origin: *",", але для API з автентифікацією краще вказувати конкретні домени.",[5379,27959,27960,27425,27962,5259,27964,5259,27966,5259,27968,5259,27970,5259,27972,5259,27974,27443],{},[5205,27961,27310],{},[5288,27963,27428],{},[5288,27965,6487],{},[5288,27967,6699],{},[5288,27969,6702],{},[5288,27971,27437],{},[5288,27973,6727],{},[5288,27975,27442],{},[5444,27977,27978,28027,28072,28098,28118],{"start":6158},[5201,27979,27980,27982],{},[5205,27981,27448],{},[5198,27983,27984,27990,27997,28002,28012,28017,28022],{},[5201,27985,27298,27986,5333,27988],{},[5205,27987,27301],{},[5288,27989,27457],{},[5201,27991,16650,27992,27462,27994,27996],{},[5205,27993,27292],{},[5288,27995,5262],{}," з тілом запиту або Base64-кодований JSON у одному параметрі (останнє — крайній захід).\nЗавжди включайте у відповіді:",[5201,27998,27999,28001],{},[5288,28000,6909],{}," — таймстемп відповіді для синхронізації годинників.",[5201,28003,28004,28006,28007,5259,28009,5407],{},[5288,28005,6509],{}," — тип вмісту (",[5288,28008,6876],{},[5288,28010,28011],{},"text\u002Fplain",[5201,28013,28014,28016],{},[5288,28015,6529],{}," — розмір тіла відповіді.",[5201,28018,28019,28021],{},[5288,28020,7770],{}," — політика кешування.",[5201,28023,28024,28026],{},[5288,28025,26230],{}," — рекомендований час повторного запиту при помилках.",[5201,28028,28029,28032,28033,28036,28037],{},[5205,28030,28031],{},"Підтримка CORS для браузерів:","\nРеалізуйте метод ",[5288,28034,28035],{},"OPTIONS"," для preflight-запитів та додайте заголовки:",[5530,28038,28040],{"className":6467,"code":28039,"language":6469,"meta":5538,"style":5538},"Access-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS\nAccess-Control-Allow-Headers: Content-Type, Authorization\n",[5288,28041,28042,28052,28062],{"__ignoreMap":5538},[6124,28043,28044,28047,28049],{"class":6126,"line":6127},[6124,28045,28046],{"class":6496},"Access-Control-Allow-Origin",[6124,28048,6500],{"class":6483},[6124,28050,28051],{"class":6503}," *\n",[6124,28053,28054,28057,28059],{"class":6126,"line":6133},[6124,28055,28056],{"class":6496},"Access-Control-Allow-Methods",[6124,28058,6500],{"class":6483},[6124,28060,28061],{"class":6503}," GET, POST, PUT, DELETE, PATCH, OPTIONS\n",[6124,28063,28064,28067,28069],{"class":6126,"line":6139},[6124,28065,28066],{"class":6496},"Access-Control-Allow-Headers",[6124,28068,6500],{"class":6483},[6124,28070,28071],{"class":6503}," Content-Type, Authorization\n",[5201,28073,28074,28076],{},[5205,28075,27345],{},[5198,28077,28078,28086,28095],{},[5201,28079,28080,8287,28082,5259,28084],{},[5288,28081,8286],{},[5288,28083,8290],{},[5288,28085,8293],{},[5201,28087,28088,28090,28091,5259,28093],{},[5288,28089,8298],{}," для query-параметрів та JSON-полів: ",[5288,28092,8302],{},[5288,28094,8305],{},[5201,28096,28097],{},"Дотримуйтесь обраного стилю в усьому API.",[5201,28099,28100,28102,28113,28115,28117],{},[5205,28101,27285],{},[5198,28103,28104,28109],{},[5201,28105,8227,28106],{},[5288,28107,28108],{},"{\"users\": [...]}",[5201,28110,8236,28111,27305],{},[5288,28112,27304],{},[6781,28114],{},[5205,28116,27310],{}," До об'єкта можна додати нові поля без порушення сумісності, до масиву — ні.",[5201,28119,28120,28123],{},[5205,28121,28122],{},"Пустий об'єкт замість порожнього тіла:",[5198,28124,28125,28131],{},[5201,28126,8227,28127,5946,28129,27329],{},[5288,28128,27325],{},[5288,28130,7280],{},[5201,28132,28133],{},"❌ Неправильно: порожня стрічка (не є валідним JSON)",[5374,28135,28137],{"id":28136},"правила-безпечного-використання-http","Правила безпечного використання HTTP",[9496,28139,28140,28145],{},[5379,28141,28142],{},[5205,28143,28144],{},"Дотримуйтесь семантики методів:",[5198,28146,28147,28155,28164,28177,28191],{},[5201,28148,28149,28152,28153,5787],{},[5205,28150,28151],{},"Не розміщуйте"," модифікуючі операції за методом ",[5288,28154,5258],{},[5201,28156,28157,28159,28160,6487,28162,5787],{},[5205,28158,28151],{}," неідемпотентні операції за ",[5288,28161,5265],{},[5288,28163,5268],{},[5201,28165,28166,28169,28170,6487,28172,6487,28174,28176],{},[5205,28167,28168],{},"Дотримуйтесь"," симетрії ",[5288,28171,5258],{},[5288,28173,5265],{},[5288,28175,5268],{}," методів.",[5201,28178,28179,28182,28183,6487,28185,6487,28188,28190],{},[5205,28180,28181],{},"Не дозволяйте"," методам ",[5288,28184,5258],{},[5288,28186,28187],{},"HEAD",[5288,28189,5268],{}," мати тіло запиту.",[5201,28192,28193,28196,28197,28199,28200,5787],{},[5205,28194,28195],{},"Не повертайте"," тіло у відповіді на ",[5288,28198,28187],{}," або зі статусом ",[5288,28201,7280],{},[5374,28203,28205],{"id":28204},"безпека-http-api-захист-від-типових-вразливостей","Безпека HTTP API: захист від типових вразливостей",[5444,28207,28208,28230,28252,28270,28283,28296],{},[5201,28209,28210,28213],{},[5205,28211,28212],{},"CSRF (Cross-Site Request Forgery):",[5198,28214,28215,28218,28227],{},[5201,28216,28217],{},"Використовуйте CSRF-токени для state-changing операцій.",[5201,28219,28220,28221,5946,28224,5787],{},"Перевіряйте заголовок ",[5288,28222,28223],{},"Origin",[5288,28225,28226],{},"Referer",[5201,28228,28229],{},"Для API з JWT-автентифікацією CSRF менш критичний (токен не надсилається автоматично браузером).",[5201,28231,28232,28235],{},[5205,28233,28234],{},"SSRF (Server-Side Request Forgery):",[5198,28236,28237,28240],{},[5201,28238,28239],{},"Валідуйте всі URL, які клієнт може передати серверу.",[5201,28241,28242,28243,5259,28246,5259,28249,5407],{},"Блокуйте запити до приватних IP-діапазонів (",[5288,28244,28245],{},"127.0.0.1",[5288,28247,28248],{},"10.0.0.0\u002F8",[5288,28250,28251],{},"192.168.0.0\u002F16",[5201,28253,28254,28257],{},[5205,28255,28256],{},"HTTP Response Splitting:",[5198,28258,28259,28267],{},[5201,28260,28261,28262,6374,28265,5787],{},"Очищайте всі заголовки від символів ",[5288,28263,28264],{},"\\r",[5288,28266,25274],{},[5201,28268,28269],{},"Використовуйте безпечні бібліотеки для встановлення заголовків.",[5201,28271,28272,28275],{},[5205,28273,28274],{},"Unvalidated Redirects:",[5198,28276,28277,28280],{},[5201,28278,28279],{},"Ніколи не редиректьте на URL, який контролюється клієнтом, без валідації.",[5201,28281,28282],{},"Використовуйте whitelist дозволених доменів для редиректів.",[5201,28284,28285,28288],{},[5205,28286,28287],{},"Ін'єкції (SQL, NoSQL, Command Injection):",[5198,28289,28290,28293],{},[5201,28291,28292],{},"Завжди використовуйте параметризовані запити.",[5201,28294,28295],{},"Ніколи не конкатенуйте вхідні дані користувача безпосередньо у SQL-запити.",[5201,28297,28298,28301],{},[5205,28299,28300],{},"Хешування паролів:",[5198,28302,28303,28327],{},[5201,28304,28305,28306,5259,28309,5946,28312,28315,28316,28319,28320,28323,28324,5787],{},"Використовуйте ",[5288,28307,28308],{},"bcrypt",[5288,28310,28311],{},"argon2",[5288,28313,28314],{},"scrypt"," — ",[5205,28317,28318],{},"ніколи"," не ",[5288,28321,28322],{},"MD5"," чи ",[5288,28325,28326],{},"SHA-1",[5201,28328,28329],{},"Не зберігайте паролі у відкритому вигляді навіть у логах.",[5587,28331,28332,28337],{},[5379,28333,28334],{},[5205,28335,28336],{},"Корисні ресурси з безпеки:",[5198,28338,28339,28348],{},[5201,28340,28341],{},[28342,28343,28347],"a",{"href":28344,"rel":28345},"https:\u002F\u002Fcheatsheetseries.owasp.org\u002Fcheatsheets\u002FREST_Security_Cheat_Sheet.html",[28346],"nofollow","OWASP REST Security Cheat Sheet",[5201,28349,28350],{},[28342,28351,28354],{"href":28352,"rel":28353},"https:\u002F\u002Fowasp.org\u002FAPI-Security\u002Feditions\u002F2023\u002Fen\u002F0x11-t10\u002F",[28346],"OWASP API Security Top 10",[5374,28356,28358],{"id":28357},"політика-кешування-для-get-запитів","Політика кешування для GET-запитів",[5379,28360,28361,28362,28364],{},"Завжди вказуйте політику кешування для ",[5288,28363,5258],{},"-запитів, інакше клієнт або проміжний агент можуть придумати її самостійно:",[5530,28366,28368],{"className":6467,"code":28367,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\n\n→ HTTP\u002F1.1 200 OK\nCache-Control: max-age=300, private\nETag: \"v123abc\"\n\n{ \"id\": \"order_123\", \"status\": \"completed\" }\n",[5288,28369,28370,28382,28386,28390,28399,28407,28411],{"__ignoreMap":5538},[6124,28371,28372,28374,28376,28378,28380],{"class":6126,"line":6127},[6124,28373,5258],{"class":6476},[6124,28375,8870],{"class":6479},[6124,28377,6484],{"class":6483},[6124,28379,6487],{"class":6479},[6124,28381,6491],{"class":6490},[6124,28383,28384],{"class":6126,"line":6133},[6124,28385,6149],{"emptyLinePlaceholder":6148},[6124,28387,28388],{"class":6126,"line":6139},[6124,28389,7533],{"class":6479},[6124,28391,28392,28394,28396],{"class":6126,"line":6145},[6124,28393,7770],{"class":6496},[6124,28395,6500],{"class":6483},[6124,28397,28398],{"class":6503}," max-age=300, private\n",[6124,28400,28401,28403,28405],{"class":6126,"line":6152},[6124,28402,7845],{"class":6496},[6124,28404,6500],{"class":6483},[6124,28406,7850],{"class":6503},[6124,28408,28409],{"class":6126,"line":6158},[6124,28410,6149],{"emptyLinePlaceholder":6148},[6124,28412,28413,28415,28417,28419,28421,28423,28425,28427,28429],{"class":6126,"line":6164},[6124,28414,26110],{"class":6479},[6124,28416,7599],{"class":6548},[6124,28418,6552],{"class":6479},[6124,28420,8897],{"class":6503},[6124,28422,5259],{"class":6479},[6124,28424,7609],{"class":6548},[6124,28426,6552],{"class":6479},[6124,28428,7647],{"class":6503},[6124,28430,16144],{"class":6479},[5379,28432,28433],{},[5205,28434,28435,28436,6500],{},"Директиви ",[5288,28437,7770],{},[5198,28439,28440,28446,28454,28460,28465],{},[5201,28441,28442,28445],{},[5288,28443,28444],{},"max-age=\u003Cseconds>"," — максимальний час кешування.",[5201,28447,28448,28451,28452,5407],{},[5288,28449,28450],{},"no-cache"," — необхідно перевірити актуальність перед використанням кешу (через ",[5288,28453,7845],{},[5201,28455,28456,28459],{},[5288,28457,28458],{},"no-store"," — ніколи не кешувати (для чутливих даних).",[5201,28461,28462,28464],{},[5288,28463,23526],{}," — може бути закешовано проміжними проксі.",[5201,28466,28467,28470],{},[5288,28468,28469],{},"private"," — може бути закешовано лише на клієнті, не на проксі.",[5366,28472],{},[5369,28474,28476],{"id":28475},"заключні-висновки-коли-використовувати-http-api","Заключні висновки: коли використовувати HTTP API",[5190,28478,28479,28515],{},[5193,28480,28483],{"icon":28481,"title":28482},"i-lucide-check","✅ HTTP API підходить для:",[5198,28484,28485,28491,28497,28503,28509],{},[5201,28486,28487,28490],{},[5205,28488,28489],{},"Публічних API"," — максимальна інтероперабельність з будь-якими клієнтами.",[5201,28492,28493,28496],{},[5205,28494,28495],{},"MVP та прототипів"," — швидка розробка, величезна екосистема інструментів.",[5201,28498,28499,28502],{},[5205,28500,28501],{},"Вебклієнтів"," — нативна підтримка у браузерах.",[5201,28504,28505,28508],{},[5205,28506,28507],{},"Систем з гетерогенними клієнтами"," — Desktop, Mobile, CLI, IoT.",[5201,28510,28511,28514],{},[5205,28512,28513],{},"API з складною бізнес-логікою"," — читабельність та зрозумілість URL\u002Fметодів.",[5193,28516,28519],{"icon":28517,"title":28518},"i-lucide-settings","⚙️ gRPC\u002FGraphQL підходять для:",[5198,28520,28521,28527,28533,28539],{},[5201,28522,28523,28526],{},[5205,28524,28525],{},"Внутрішньої міжсервісної взаємодії"," — висока продуктивність.",[5201,28528,28529,28532],{},[5205,28530,28531],{},"Систем реального часу"," — bidirectional streaming.",[5201,28534,28535,28538],{},[5205,28536,28537],{},"Строго типізованих контрактів"," — кодогенерація клієнтів.",[5201,28540,28541,28544],{},[5205,28542,28543],{},"Складних запитів до графів даних"," — GraphQL для frontend-driven API.",[5409,28546,28547,28550,28551,28554],{},[5205,28548,28549],{},"Висновок:"," HTTP API — це вибір за замовчуванням для публічних API. На сьогодні ",[5205,28552,28553],{},"швидше треба обґрунтовувати відмову від HTTP API",", ніж вибір на його користь. Екосистема HTTP надає найширший словник для опису різноманітних ситуацій, що виникають під час роботи клієнт-серверних застосунків.",[5366,28556],{},[5379,28558,28559,28561],{},[5205,28560,26052],{}," Шарувата архітектура та конвеєри обробки запитів — Middleware Pipeline, патерн Repository, Dependency Injection та тестування HTTP-шару.",[6994,28563,28358],{"id":28564},"політика-кешування-для-get-запитів-1",[5379,28566,28567,26285,28570,28572],{},[5205,28568,28569],{},"Завжди вказуйте політику кешування",[5288,28571,5258],{},"-запитів, інакше клієнт або проміжний агент можуть придумати її самостійно, що призведе до непередбачуваної поведінки:",[5530,28574,28576],{"className":6467,"code":28575,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\n\n→ HTTP\u002F1.1 200 OK\nCache-Control: max-age=300, private\nETag: \"v123abc\"\nLast-Modified: Tue, 01 Sep 2026 14:00:00 GMT\n\n{ \"id\": \"order_123\", \"status\": \"completed\" }\n",[5288,28577,28578,28590,28594,28598,28606,28614,28624,28628],{"__ignoreMap":5538},[6124,28579,28580,28582,28584,28586,28588],{"class":6126,"line":6127},[6124,28581,5258],{"class":6476},[6124,28583,8870],{"class":6479},[6124,28585,6484],{"class":6483},[6124,28587,6487],{"class":6479},[6124,28589,6491],{"class":6490},[6124,28591,28592],{"class":6126,"line":6133},[6124,28593,6149],{"emptyLinePlaceholder":6148},[6124,28595,28596],{"class":6126,"line":6139},[6124,28597,7533],{"class":6479},[6124,28599,28600,28602,28604],{"class":6126,"line":6145},[6124,28601,7770],{"class":6496},[6124,28603,6500],{"class":6483},[6124,28605,28398],{"class":6503},[6124,28607,28608,28610,28612],{"class":6126,"line":6152},[6124,28609,7845],{"class":6496},[6124,28611,6500],{"class":6483},[6124,28613,7850],{"class":6503},[6124,28615,28616,28619,28621],{"class":6126,"line":6158},[6124,28617,28618],{"class":6496},"Last-Modified",[6124,28620,6500],{"class":6483},[6124,28622,28623],{"class":6503}," Tue, 01 Sep 2026 14:00:00 GMT\n",[6124,28625,28626],{"class":6126,"line":6164},[6124,28627,6149],{"emptyLinePlaceholder":6148},[6124,28629,28630,28632,28634,28636,28638,28640,28642,28644,28646],{"class":6126,"line":6170},[6124,28631,26110],{"class":6479},[6124,28633,7599],{"class":6548},[6124,28635,6552],{"class":6479},[6124,28637,8897],{"class":6503},[6124,28639,5259],{"class":6479},[6124,28641,7609],{"class":6548},[6124,28643,6552],{"class":6479},[6124,28645,7647],{"class":6503},[6124,28647,16144],{"class":6479},[5379,28649,28650],{},[5205,28651,28435,28652,6500],{},[5288,28653,7770],{},[5198,28655,28656,28661,28669,28674,28679,28684],{},[5201,28657,28658,28660],{},[5288,28659,28444],{}," — максимальний час кешування у секундах.",[5201,28662,28663,28451,28665,5946,28667,5407],{},[5288,28664,28450],{},[5288,28666,7845],{},[5288,28668,28618],{},[5201,28670,28671,28673],{},[5288,28672,28458],{}," — ніколи не кешувати (для чутливих даних, як-от токени, паролі, персональні дані).",[5201,28675,28676,28678],{},[5288,28677,23526],{}," — може бути закешовано будь-яким проміжним кешем (CDN, проксі).",[5201,28680,28681,28683],{},[5288,28682,28469],{}," — може бути закешовано лише на клієнті, не на проміжних проксі.",[5201,28685,28686,28689,28690,28693],{},[5288,28687,28688],{},"must-revalidate"," — після закінчення ",[5288,28691,28692],{},"max-age"," обов'язково перевірити актуальність на сервері.",[5379,28695,28696],{},[5205,28697,28698],{},"Приклади політик для різних типів даних:",[5530,28700,28702],{"className":9594,"code":28701,"language":9579,"meta":5538,"style":5538},"\u002F\u002F Статичні дані (профіль користувача)\nw.Header().Set(\"Cache-Control\", \"max-age=3600, private\")\n\n\u002F\u002F Динамічні дані (список замовлень)\nw.Header().Set(\"Cache-Control\", \"no-cache, private\")\nw.Header().Set(\"ETag\", fmt.Sprintf(`\"%s\"`, generateETag(orders)))\n\n\u002F\u002F Чутливі дані (токени, паролі)\nw.Header().Set(\"Cache-Control\", \"no-store, no-cache, must-revalidate, private\")\nw.Header().Set(\"Pragma\", \"no-cache\") \u002F\u002F Для HTTP\u002F1.0 клієнтів\n\n\u002F\u002F Публічні статичні ресурси (аватари, логотипи)\nw.Header().Set(\"Cache-Control\", \"max-age=86400, public\")\n",[5288,28703,28704,28709,28733,28737,28742,28765,28812,28816,28821,28844,28871,28875,28880],{"__ignoreMap":5538},[6124,28705,28706],{"class":6126,"line":6127},[6124,28707,28708],{"class":9691},"\u002F\u002F Статичні дані (профіль користувача)\n",[6124,28710,28711,28713,28715,28717,28719,28721,28723,28726,28728,28731],{"class":6126,"line":6133},[6124,28712,9967],{"class":9667},[6124,28714,5787],{"class":6479},[6124,28716,10189],{"class":9578},[6124,28718,10167],{"class":6479},[6124,28720,10194],{"class":9578},[6124,28722,9704],{"class":6479},[6124,28724,28725],{"class":6503},"\"Cache-Control\"",[6124,28727,5259],{"class":6479},[6124,28729,28730],{"class":6503},"\"max-age=3600, private\"",[6124,28732,9647],{"class":6479},[6124,28734,28735],{"class":6126,"line":6139},[6124,28736,6149],{"emptyLinePlaceholder":6148},[6124,28738,28739],{"class":6126,"line":6145},[6124,28740,28741],{"class":9691},"\u002F\u002F Динамічні дані (список замовлень)\n",[6124,28743,28744,28746,28748,28750,28752,28754,28756,28758,28760,28763],{"class":6126,"line":6152},[6124,28745,9967],{"class":9667},[6124,28747,5787],{"class":6479},[6124,28749,10189],{"class":9578},[6124,28751,10167],{"class":6479},[6124,28753,10194],{"class":9578},[6124,28755,9704],{"class":6479},[6124,28757,28725],{"class":6503},[6124,28759,5259],{"class":6479},[6124,28761,28762],{"class":6503},"\"no-cache, private\"",[6124,28764,9647],{"class":6479},[6124,28766,28767,28769,28771,28773,28775,28777,28779,28782,28784,28786,28788,28790,28792,28795,28797,28800,28802,28805,28807,28809],{"class":6126,"line":6158},[6124,28768,9967],{"class":9667},[6124,28770,5787],{"class":6479},[6124,28772,10189],{"class":9578},[6124,28774,10167],{"class":6479},[6124,28776,10194],{"class":9578},[6124,28778,9704],{"class":6479},[6124,28780,28781],{"class":6503},"\"ETag\"",[6124,28783,5259],{"class":6479},[6124,28785,14010],{"class":9667},[6124,28787,5787],{"class":6479},[6124,28789,14015],{"class":9578},[6124,28791,9704],{"class":6479},[6124,28793,28794],{"class":6503},"`\"",[6124,28796,11179],{"class":9667},[6124,28798,28799],{"class":6503},"\"`",[6124,28801,5259],{"class":6479},[6124,28803,28804],{"class":9578},"generateETag",[6124,28806,9704],{"class":6479},[6124,28808,14491],{"class":9667},[6124,28810,28811],{"class":6479},")))\n",[6124,28813,28814],{"class":6126,"line":6164},[6124,28815,6149],{"emptyLinePlaceholder":6148},[6124,28817,28818],{"class":6126,"line":6170},[6124,28819,28820],{"class":9691},"\u002F\u002F Чутливі дані (токени, паролі)\n",[6124,28822,28823,28825,28827,28829,28831,28833,28835,28837,28839,28842],{"class":6126,"line":6175},[6124,28824,9967],{"class":9667},[6124,28826,5787],{"class":6479},[6124,28828,10189],{"class":9578},[6124,28830,10167],{"class":6479},[6124,28832,10194],{"class":9578},[6124,28834,9704],{"class":6479},[6124,28836,28725],{"class":6503},[6124,28838,5259],{"class":6479},[6124,28840,28841],{"class":6503},"\"no-store, no-cache, must-revalidate, private\"",[6124,28843,9647],{"class":6479},[6124,28845,28846,28848,28850,28852,28854,28856,28858,28861,28863,28866,28868],{"class":6126,"line":6181},[6124,28847,9967],{"class":9667},[6124,28849,5787],{"class":6479},[6124,28851,10189],{"class":9578},[6124,28853,10167],{"class":6479},[6124,28855,10194],{"class":9578},[6124,28857,9704],{"class":6479},[6124,28859,28860],{"class":6503},"\"Pragma\"",[6124,28862,5259],{"class":6479},[6124,28864,28865],{"class":6503},"\"no-cache\"",[6124,28867,7173],{"class":6479},[6124,28869,28870],{"class":9691},"\u002F\u002F Для HTTP\u002F1.0 клієнтів\n",[6124,28872,28873],{"class":6126,"line":6187},[6124,28874,6149],{"emptyLinePlaceholder":6148},[6124,28876,28877],{"class":6126,"line":6193},[6124,28878,28879],{"class":9691},"\u002F\u002F Публічні статичні ресурси (аватари, логотипи)\n",[6124,28881,28882,28884,28886,28888,28890,28892,28894,28896,28898,28901],{"class":6126,"line":6199},[6124,28883,9967],{"class":9667},[6124,28885,5787],{"class":6479},[6124,28887,10189],{"class":9578},[6124,28889,10167],{"class":6479},[6124,28891,10194],{"class":9578},[6124,28893,9704],{"class":6479},[6124,28895,28725],{"class":6503},[6124,28897,5259],{"class":6479},[6124,28899,28900],{"class":6503},"\"max-age=86400, public\"",[6124,28902,9647],{"class":6479},[9496,28904,28905,28908,28909,5333,28911,28914,28915,28917,28918,5946,28921,28924],{},[5205,28906,28907],{},"Небезпека кешування помилок:"," За замовчуванням статус-код ",[5288,28910,6340],{},[5205,28912,28913],{},"кешується"," більшістю браузерів та проксі. Якщо ваше API може повернути ",[5288,28916,7471],{}," для ресурсу, який може з'явитися пізніше (наприклад, асинхронна обробка завдання), обов'язково вказуйте ",[5288,28919,28920],{},"Cache-Control: no-cache",[5288,28922,28923],{},"Cache-Control: max-age=0",", щоб уникнути кешування відсутності ресурсу.",[6994,28926,28928],{"id":28927},"умовні-запити-для-оптимізації-трафіку","Умовні запити для оптимізації трафіку",[5379,28930,28305,28931,28933],{},[5288,28932,7845],{}," та умовні заголовки для зменшення трафіку:",[5379,28935,28936],{},[5205,28937,28938],{},"Сервер генерує ETag:",[5530,28940,28942],{"className":9594,"code":28941,"language":9579,"meta":5538,"style":5538},"func getOrderHandler(w http.ResponseWriter, r *http.Request) {\n    orderID := chi.URLParam(r, \"id\")\n    order, err := getOrderFromDB(orderID)\n    if err != nil {\n        http.Error(w, \"Order not found\", http.StatusNotFound)\n        return\n    }\n\n    \u002F\u002F Генеруємо ETag на основі хеша даних або version field\n    etag := fmt.Sprintf(`\"%s-%d\"`, order.ID, order.UpdatedAt.Unix())\n    w.Header().Set(\"ETag\", etag)\n    w.Header().Set(\"Cache-Control\", \"no-cache, private\")\n\n    \u002F\u002F Перевіряємо If-None-Match\n    if r.Header.Get(\"If-None-Match\") == etag {\n        w.WriteHeader(http.StatusNotModified)\n        return\n    }\n\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    json.NewEncoder(w).Encode(order)\n}\n",[5288,28943,28944,28974,28996,29015,29027,29053,29057,29061,29065,29070,29120,29143,29165,29169,29174,29200,29219,29223,29227,29231,29253,29275],{"__ignoreMap":5538},[6124,28945,28946,28948,28950,28952,28954,28956,28958,28960,28962,28964,28966,28968,28970,28972],{"class":6126,"line":6127},[6124,28947,9656],{"class":6483},[6124,28949,10294],{"class":9578},[6124,28951,9704],{"class":6479},[6124,28953,9967],{"class":9667},[6124,28955,9970],{"class":9605},[6124,28957,5787],{"class":6479},[6124,28959,9975],{"class":9605},[6124,28961,5259],{"class":6479},[6124,28963,9806],{"class":9667},[6124,28965,9982],{"class":6479},[6124,28967,6469],{"class":9605},[6124,28969,5787],{"class":6479},[6124,28971,9989],{"class":9605},[6124,28973,9817],{"class":6479},[6124,28975,28976,28978,28980,28982,28984,28986,28988,28990,28992,28994],{"class":6126,"line":6133},[6124,28977,10330],{"class":9667},[6124,28979,9671],{"class":6479},[6124,28981,9674],{"class":9667},[6124,28983,5787],{"class":6479},[6124,28985,10339],{"class":9578},[6124,28987,9704],{"class":6479},[6124,28989,9806],{"class":9667},[6124,28991,5259],{"class":6479},[6124,28993,7599],{"class":6503},[6124,28995,9647],{"class":6479},[6124,28997,28998,29000,29002,29004,29006,29009,29011,29013],{"class":6126,"line":6139},[6124,28999,19897],{"class":9667},[6124,29001,5259],{"class":6479},[6124,29003,10590],{"class":9667},[6124,29005,9671],{"class":6479},[6124,29007,29008],{"class":9578},"getOrderFromDB",[6124,29010,9704],{"class":6479},[6124,29012,10428],{"class":9667},[6124,29014,9647],{"class":6479},[6124,29016,29017,29019,29021,29023,29025],{"class":6126,"line":6145},[6124,29018,10551],{"class":6476},[6124,29020,10554],{"class":9667},[6124,29022,10593],{"class":6479},[6124,29024,10596],{"class":6483},[6124,29026,10516],{"class":6479},[6124,29028,29029,29031,29033,29035,29037,29039,29041,29043,29045,29047,29049,29051],{"class":6126,"line":6152},[6124,29030,10604],{"class":9667},[6124,29032,5787],{"class":6479},[6124,29034,10609],{"class":9578},[6124,29036,9704],{"class":6479},[6124,29038,9967],{"class":9667},[6124,29040,5259],{"class":6479},[6124,29042,20454],{"class":6503},[6124,29044,5259],{"class":6479},[6124,29046,6469],{"class":9667},[6124,29048,5787],{"class":6479},[6124,29050,13798],{"class":9667},[6124,29052,9647],{"class":6479},[6124,29054,29055],{"class":6126,"line":6158},[6124,29056,10635],{"class":6476},[6124,29058,29059],{"class":6126,"line":6164},[6124,29060,10545],{"class":6479},[6124,29062,29063],{"class":6126,"line":6170},[6124,29064,6149],{"emptyLinePlaceholder":6148},[6124,29066,29067],{"class":6126,"line":6175},[6124,29068,29069],{"class":9691},"    \u002F\u002F Генеруємо ETag на основі хеша даних або version field\n",[6124,29071,29072,29075,29077,29079,29081,29083,29085,29087,29089,29092,29095,29097,29099,29101,29103,29105,29107,29109,29111,29113,29115,29118],{"class":6126,"line":6181},[6124,29073,29074],{"class":9667},"    etag",[6124,29076,9671],{"class":6479},[6124,29078,14010],{"class":9667},[6124,29080,5787],{"class":6479},[6124,29082,14015],{"class":9578},[6124,29084,9704],{"class":6479},[6124,29086,28794],{"class":6503},[6124,29088,11179],{"class":9667},[6124,29090,29091],{"class":6503},"-",[6124,29093,29094],{"class":9667},"%d",[6124,29096,28799],{"class":6503},[6124,29098,5259],{"class":6479},[6124,29100,18764],{"class":9667},[6124,29102,5787],{"class":6479},[6124,29104,14442],{"class":9667},[6124,29106,5259],{"class":6479},[6124,29108,18764],{"class":9667},[6124,29110,5787],{"class":6479},[6124,29112,19194],{"class":9667},[6124,29114,5787],{"class":6479},[6124,29116,29117],{"class":9578},"Unix",[6124,29119,12801],{"class":6479},[6124,29121,29122,29124,29126,29128,29130,29132,29134,29136,29138,29141],{"class":6126,"line":6187},[6124,29123,9996],{"class":9667},[6124,29125,5787],{"class":6479},[6124,29127,10189],{"class":9578},[6124,29129,10167],{"class":6479},[6124,29131,10194],{"class":9578},[6124,29133,9704],{"class":6479},[6124,29135,28781],{"class":6503},[6124,29137,5259],{"class":6479},[6124,29139,29140],{"class":9667},"etag",[6124,29142,9647],{"class":6479},[6124,29144,29145,29147,29149,29151,29153,29155,29157,29159,29161,29163],{"class":6126,"line":6193},[6124,29146,9996],{"class":9667},[6124,29148,5787],{"class":6479},[6124,29150,10189],{"class":9578},[6124,29152,10167],{"class":6479},[6124,29154,10194],{"class":9578},[6124,29156,9704],{"class":6479},[6124,29158,28725],{"class":6503},[6124,29160,5259],{"class":6479},[6124,29162,28762],{"class":6503},[6124,29164,9647],{"class":6479},[6124,29166,29167],{"class":6126,"line":6199},[6124,29168,6149],{"emptyLinePlaceholder":6148},[6124,29170,29171],{"class":6126,"line":6204},[6124,29172,29173],{"class":9691},"    \u002F\u002F Перевіряємо If-None-Match\n",[6124,29175,29176,29178,29180,29182,29184,29186,29188,29190,29193,29196,29198],{"class":6126,"line":6209},[6124,29177,10551],{"class":6476},[6124,29179,10649],{"class":9667},[6124,29181,5787],{"class":6479},[6124,29183,10189],{"class":9667},[6124,29185,5787],{"class":6479},[6124,29187,9751],{"class":9578},[6124,29189,9704],{"class":6479},[6124,29191,29192],{"class":6503},"\"If-None-Match\"",[6124,29194,29195],{"class":6479},") == ",[6124,29197,29140],{"class":9667},[6124,29199,10516],{"class":6479},[6124,29201,29202,29204,29206,29208,29210,29212,29214,29217],{"class":6126,"line":6215},[6124,29203,11873],{"class":9667},[6124,29205,5787],{"class":6479},[6124,29207,10681],{"class":9578},[6124,29209,9704],{"class":6479},[6124,29211,6469],{"class":9667},[6124,29213,5787],{"class":6479},[6124,29215,29216],{"class":9667},"StatusNotModified",[6124,29218,9647],{"class":6479},[6124,29220,29221],{"class":6126,"line":6221},[6124,29222,10635],{"class":6476},[6124,29224,29225],{"class":6126,"line":6227},[6124,29226,10545],{"class":6479},[6124,29228,29229],{"class":6126,"line":6232},[6124,29230,6149],{"emptyLinePlaceholder":6148},[6124,29232,29233,29235,29237,29239,29241,29243,29245,29247,29249,29251],{"class":6126,"line":6237},[6124,29234,9996],{"class":9667},[6124,29236,5787],{"class":6479},[6124,29238,10189],{"class":9578},[6124,29240,10167],{"class":6479},[6124,29242,10194],{"class":9578},[6124,29244,9704],{"class":6479},[6124,29246,10199],{"class":6503},[6124,29248,5259],{"class":6479},[6124,29250,10204],{"class":6503},[6124,29252,9647],{"class":6479},[6124,29254,29255,29257,29259,29261,29263,29265,29267,29269,29271,29273],{"class":6126,"line":6243},[6124,29256,10059],{"class":9667},[6124,29258,5787],{"class":6479},[6124,29260,10064],{"class":9578},[6124,29262,9704],{"class":6479},[6124,29264,9967],{"class":9667},[6124,29266,5407],{"class":6479},[6124,29268,10073],{"class":9578},[6124,29270,9704],{"class":6479},[6124,29272,18764],{"class":9667},[6124,29274,9647],{"class":6479},[6124,29276,29277],{"class":6126,"line":6249},[6124,29278,6167],{"class":6479},[5379,29280,29281],{},[5205,29282,29283],{},"Клієнт використовує ETag при повторному запиті:",[5530,29285,29287],{"className":6467,"code":29286,"language":6469,"meta":5538,"style":5538},"GET \u002Fv1\u002Forders\u002F123 HTTP\u002F1.1\nIf-None-Match: \"order_123-1725196800\"\n\n→ HTTP\u002F1.1 304 Not Modified\nETag: \"order_123-1725196800\"\n(порожнє тіло — клієнт використовує закешовану версію)\n",[5288,29288,29289,29301,29311,29315,29320,29328],{"__ignoreMap":5538},[6124,29290,29291,29293,29295,29297,29299],{"class":6126,"line":6127},[6124,29292,5258],{"class":6476},[6124,29294,8870],{"class":6479},[6124,29296,6484],{"class":6483},[6124,29298,6487],{"class":6479},[6124,29300,6491],{"class":6490},[6124,29302,29303,29306,29308],{"class":6126,"line":6133},[6124,29304,29305],{"class":6496},"If-None-Match",[6124,29307,6500],{"class":6483},[6124,29309,29310],{"class":6503}," \"order_123-1725196800\"\n",[6124,29312,29313],{"class":6126,"line":6139},[6124,29314,6149],{"emptyLinePlaceholder":6148},[6124,29316,29317],{"class":6126,"line":6145},[6124,29318,29319],{"class":6479},"→ HTTP\u002F1.1 304 Not Modified\n",[6124,29321,29322,29324,29326],{"class":6126,"line":6152},[6124,29323,7845],{"class":6496},[6124,29325,6500],{"class":6483},[6124,29327,29310],{"class":6503},[6124,29329,29330],{"class":6126,"line":6158},[6124,29331,29332],{"class":6479},"(порожнє тіло — клієнт використовує закешовану версію)\n",[29334,29335,29336],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":5538,"searchDepth":6133,"depth":6133,"links":29338},[29339,29345,29356,29361,29369,29373,29377,29391,29395,29396,29401,29402,29410,29422],{"id":5371,"depth":6133,"text":5372,"children":29340},[29341,29342,29343,29344],{"id":5376,"depth":6139,"text":5377},{"id":5438,"depth":6139,"text":5439},{"id":5492,"depth":6139,"text":5493},{"id":5595,"depth":6139,"text":5596},{"id":5768,"depth":6133,"text":5769,"children":29346},[29347,29348,29349,29350,29351,29352,29353,29354,29355],{"id":5772,"depth":6139,"text":5773},{"id":5804,"depth":6139,"text":5805},{"id":5814,"depth":6139,"text":5815},{"id":5824,"depth":6139,"text":5825},{"id":5842,"depth":6139,"text":5843},{"id":5852,"depth":6139,"text":5853},{"id":5862,"depth":6139,"text":5863},{"id":5885,"depth":6139,"text":5886},{"id":5931,"depth":6139,"text":5932},{"id":5978,"depth":6133,"text":5979,"children":29357},[29358,29359,29360],{"id":5982,"depth":6139,"text":5983},{"id":6051,"depth":6139,"text":6052},{"id":6344,"depth":6139,"text":6345},{"id":6416,"depth":6133,"text":6417,"children":29362},[29363,29364,29365,29366,29367,29368],{"id":6420,"depth":6139,"text":4121},{"id":6624,"depth":6139,"text":6625},{"id":6754,"depth":6139,"text":6755},{"id":6844,"depth":6139,"text":6845},{"id":6970,"depth":6139,"text":6971},{"id":7246,"depth":6139,"text":7247},{"id":7489,"depth":6133,"text":7490,"children":29370},[29371,29372],{"id":7493,"depth":6139,"text":7494},{"id":7696,"depth":6139,"text":7697},{"id":8203,"depth":6133,"text":8204,"children":29374},[29375,29376],{"id":8207,"depth":6139,"text":8208},{"id":8356,"depth":6139,"text":8357},{"id":9518,"depth":6133,"text":9519,"children":29378},[29379,29380,29381,29382,29383,29384,29385,29386,29387,29388,29389,29390],{"id":9522,"depth":6139,"text":9523},{"id":9565,"depth":6139,"text":9566},{"id":11046,"depth":6139,"text":11047},{"id":11304,"depth":6139,"text":11305},{"id":11551,"depth":6139,"text":11552},{"id":12342,"depth":6139,"text":12343},{"id":13202,"depth":6139,"text":13203},{"id":13690,"depth":6139,"text":13691},{"id":14089,"depth":6139,"text":14090},{"id":14744,"depth":6139,"text":14745},{"id":14870,"depth":6139,"text":14871},{"id":16686,"depth":6139,"text":16687},{"id":17945,"depth":6133,"text":17946,"children":29392},[29393,29394],{"id":17949,"depth":6139,"text":17950},{"id":20912,"depth":6139,"text":20913},{"id":21996,"depth":6133,"text":21997},{"id":23465,"depth":6133,"text":23466,"children":29397},[29398,29399,29400],{"id":23469,"depth":6139,"text":23470},{"id":24072,"depth":6139,"text":24073},{"id":24593,"depth":6139,"text":24594},{"id":25882,"depth":6133,"text":25883},{"id":26058,"depth":6133,"text":26059,"children":29403},[29404,29405,29406,29407,29408,29409],{"id":26062,"depth":6139,"text":26063},{"id":26178,"depth":6139,"text":26179},{"id":26234,"depth":6139,"text":26235},{"id":26429,"depth":6139,"text":26430},{"id":26819,"depth":6139,"text":26820},{"id":27131,"depth":6139,"text":27132},{"id":27188,"depth":6133,"text":27189,"children":29411},[29412,29413,29414,29415,29416,29417,29418,29419,29420,29421],{"id":27192,"depth":6139,"text":27193},{"id":27203,"depth":6139,"text":27204},{"id":27210,"depth":6139,"text":27211},{"id":27217,"depth":6139,"text":27218},{"id":27224,"depth":6139,"text":27225},{"id":27231,"depth":6139,"text":27232},{"id":27238,"depth":6139,"text":27239},{"id":28136,"depth":6139,"text":28137},{"id":28204,"depth":6139,"text":28205},{"id":28357,"depth":6139,"text":28358},{"id":28475,"depth":6133,"text":28476},"Еволюція від RPC до HTTP API, архітектурний стиль REST, мотивація та обмеження, складові HTTP-запитів (URL, заголовки, методи, статус-коди), проєктування номенклатури URL, CRUD-операції, маршрутизатор go-chi\u002Fchi з підтримкою Radix Tree, параметри шляху, суб-роутери, Middleware та побудова REST API у Go з дотриманням принципів Clean Architecture.","md",null,{},{"title":4021,"description":29423},"jEYUhPXWTb69gFBHrQowtGF1AnciZN99wZ-DC4XCCiA",[29430,29432],{"title":4017,"path":4018,"stem":4019,"description":29431,"children":-1},"Еволюція протоколу HTTP від версії 1.0 до HTTP\u002F3 з транспортом QUIC, детальний розбір анатомії HTTP-запитів та відповідей (методи, статус-коди, заголовки, тіло), принципи ідемпотентності та безпеки методів, стандартний пакет net\u002Fhttp у Go (інтерфейс http.Handler, роутер http.ServeMux, кастомний http.Server), налаштування таймаутів, TLS та обробка потокових даних.",{"title":4025,"path":4026,"stem":4027,"description":29433,"children":-1},"Патерн Middleware у Go, принципи Clean Architecture, впровадження залежностей та модульне тестування HTTP-шару",1791986745302]