laravel-12/SANCTUM_SETUP_GUIDE.html

752 lines
107 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html><html><head>
<title>SANCTUM_SETUP_GUIDE</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="file:////home/user/.vscode/extensions/shd101wyy.markdown-preview-enhanced-0.8.21/crossnote/dependencies/katex/katex.min.css">
<style>
code[class*=language-],pre[class*=language-]{color:#333;background:0 0;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.4;-moz-tab-size:8;-o-tab-size:8;tab-size:8;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:.8em;overflow:auto;border-radius:3px;background:#f5f5f5}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal;background:#f5f5f5}.token.blockquote,.token.comment{color:#969896}.token.cdata{color:#183691}.token.doctype,.token.macro.property,.token.punctuation,.token.variable{color:#333}.token.builtin,.token.important,.token.keyword,.token.operator,.token.rule{color:#a71d5d}.token.attr-value,.token.regex,.token.string,.token.url{color:#183691}.token.atrule,.token.boolean,.token.code,.token.command,.token.constant,.token.entity,.token.number,.token.property,.token.symbol{color:#0086b3}.token.prolog,.token.selector,.token.tag{color:#63a35c}.token.attr-name,.token.class,.token.class-name,.token.function,.token.id,.token.namespace,.token.pseudo-class,.token.pseudo-element,.token.url-reference .token.variable{color:#795da3}.token.entity{cursor:help}.token.title,.token.title .token.punctuation{font-weight:700;color:#1d3e81}.token.list{color:#ed6a43}.token.inserted{background-color:#eaffea;color:#55a532}.token.deleted{background-color:#ffecec;color:#bd2c00}.token.bold{font-weight:700}.token.italic{font-style:italic}.language-json .token.property{color:#183691}.language-markup .token.tag .token.punctuation{color:#333}.language-css .token.function,code.language-css{color:#0086b3}.language-yaml .token.atrule{color:#63a35c}code.language-yaml{color:#183691}.language-ruby .token.function{color:#333}.language-markdown .token.url{color:#795da3}.language-makefile .token.symbol{color:#795da3}.language-makefile .token.variable{color:#183691}.language-makefile .token.builtin{color:#0086b3}.language-bash .token.keyword{color:#0086b3}pre[data-line]{position:relative;padding:1em 0 1em 3em}pre[data-line] .line-highlight-wrapper{position:absolute;top:0;left:0;background-color:transparent;display:block;width:100%}pre[data-line] .line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}pre[data-line] .line-highlight:before,pre[data-line] .line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}pre[data-line] .line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}html body{font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif;font-size:16px;line-height:1.6;color:#333;background-color:#fff;overflow:initial;box-sizing:border-box;word-wrap:break-word}html body>:first-child{margin-top:0}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{line-height:1.2;margin-top:1em;margin-bottom:16px;color:#000}html body h1{font-size:2.25em;font-weight:300;padding-bottom:.3em}html body h2{font-size:1.75em;font-weight:400;padding-bottom:.3em}html body h3{font-size:1.5em;font-weight:500}html body h4{font-size:1.25em;font-weight:600}html body h5{font-size:1.1em;font-weight:600}html body h6{font-size:1em;font-weight:600}html body h1,html body h2,html body h3,html body h4,html body h5{font-weight:600}html body h5{font-size:1em}html body h6{color:#5c5c5c}html body strong{color:#000}html body del{color:#5c5c5c}html body a:not([href]){color:inherit;text-decoration:none}html body a{color:#08c;text-decoration:none}html body a:hover{color:#00a3f5;text-decoration:none}html body img{max-width:100%}html body>p{margin-top:0;margin-bottom:16px;word-wrap:break-word}html body>ol,html body>ul{margin-bottom:16px}html body ol,html body ul{padding-left:2em}html body ol.no-list,html body ul.no-list{padding:0;list-style-type:none}html body ol ol,html body ol ul,html body ul ol,html body ul ul{margin-top:0;margin-bottom:0}html body li{margin-bottom:0}html body li.task-list-item{list-style:none}html body li>p{margin-top:0;margin-bottom:0}html body .task-list-item-checkbox{margin:0 .2em .25em -1.8em;vertical-align:middle}html body .task-list-item-checkbox:hover{cursor:pointer}html body blockquote{margin:16px 0;font-size:inherit;padding:0 15px;color:#5c5c5c;background-color:#f0f0f0;border-left:4px solid #d6d6d6}html body blockquote>:first-child{margin-top:0}html body blockquote>:last-child{margin-bottom:0}html body hr{height:4px;margin:32px 0;background-color:#d6d6d6;border:0 none}html body table{margin:10px 0 15px 0;border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}html body table th{font-weight:700;color:#000}html body table td,html body table th{border:1px solid #d6d6d6;padding:6px 13px}html body dl{padding:0}html body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}html body dl dd{padding:0 16px;margin-bottom:16px}html body code{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:.85em;color:#000;background-color:#f0f0f0;border-radius:3px;padding:.2em 0}html body code::after,html body code::before{letter-spacing:-.2em;content:'\00a0'}html body pre>code{padding:0;margin:0;word-break:normal;white-space:pre;background:0 0;border:0}html body .highlight{margin-bottom:16px}html body .highlight pre,html body pre{padding:1em;overflow:auto;line-height:1.45;border:#d6d6d6;border-radius:3px}html body .highlight pre{margin-bottom:0;word-break:normal}html body pre code,html body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}html body pre code:after,html body pre code:before,html body pre tt:after,html body pre tt:before{content:normal}html body blockquote,html body dl,html body ol,html body p,html body pre,html body ul{margin-top:0;margin-bottom:16px}html body kbd{color:#000;border:1px solid #d6d6d6;border-bottom:2px solid #c7c7c7;padding:2px 4px;background-color:#f0f0f0;border-radius:3px}@media print{html body{background-color:#fff}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{color:#000;page-break-after:avoid}html body blockquote{color:#5c5c5c}html body pre{page-break-inside:avoid}html body table{display:table}html body img{display:block;max-width:100%;max-height:100%}html body code,html body pre{word-wrap:break-word;white-space:pre}}.markdown-preview{width:100%;height:100%;box-sizing:border-box}.markdown-preview ul{list-style:disc}.markdown-preview ul ul{list-style:circle}.markdown-preview ul ul ul{list-style:square}.markdown-preview ol{list-style:decimal}.markdown-preview ol ol,.markdown-preview ul ol{list-style-type:lower-roman}.markdown-preview ol ol ol,.markdown-preview ol ul ol,.markdown-preview ul ol ol,.markdown-preview ul ul ol{list-style-type:lower-alpha}.markdown-preview .newpage,.markdown-preview .pagebreak{page-break-before:always}.markdown-preview pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}.markdown-preview pre.line-numbers>code{position:relative}.markdown-preview pre.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:1em;font-size:100%;left:0;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-preview pre.line-numbers .line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.markdown-preview pre.line-numbers .line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.markdown-preview .mathjax-exps .MathJax_Display{text-align:center!important}.markdown-preview:not([data-for=preview]) .code-chunk .code-chunk-btn-group{display:none}.markdown-preview:not([data-for=preview]) .code-chunk .status{display:none}.markdown-preview:not([data-for=preview]) .code-chunk .output-div{margin-bottom:16px}.markdown-preview .md-toc{padding:0}.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link{display:inline;padding:.25rem 0}.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link div,.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link p{display:inline}.markdown-preview .md-toc .md-toc-link-wrapper.highlighted .md-toc-link{font-weight:800}.scrollbar-style::-webkit-scrollbar{width:8px}.scrollbar-style::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}.scrollbar-style::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,.66);border:4px solid rgba(150,150,150,.66);background-clip:content-box}html body[for=html-export]:not([data-presentation-mode]){position:relative;width:100%;height:100%;top:0;left:0;margin:0;padding:0;overflow:auto}html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{position:relative;top:0;min-height:100vh}@media screen and (min-width:914px){html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{padding:2em calc(50% - 457px + 2em)}}@media screen and (max-width:914px){html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for=html-export]:not([data-presentation-mode]) .markdown-preview{font-size:14px!important;padding:1em}}@media print{html body[for=html-export]:not([data-presentation-mode]) #sidebar-toc-btn{display:none}}html body[for=html-export]:not([data-presentation-mode]) #sidebar-toc-btn{position:fixed;bottom:8px;left:8px;font-size:28px;cursor:pointer;color:inherit;z-index:99;width:32px;text-align:center;opacity:.4}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn{opacity:1}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc{position:fixed;top:0;left:0;width:300px;height:100%;padding:32px 0 48px 0;font-size:14px;box-shadow:0 0 4px rgba(150,150,150,.33);box-sizing:border-box;overflow:auto;background-color:inherit}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar{width:8px}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,.66);border:4px solid rgba(150,150,150,.66);background-clip:content-box}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a{text-decoration:none}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc{padding:0 16px}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link{display:inline;padding:.25rem 0}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link div,html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link p{display:inline}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper.highlighted .md-toc-link{font-weight:800}html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{left:300px;width:calc(100% - 300px);padding:2em calc(50% - 457px - 300px / 2);margin:0;box-sizing:border-box}@media screen and (max-width:1274px){html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for=html-export]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{width:100%}}html body[for=html-export]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview{left:50%;transform:translateX(-50%)}html body[for=html-export]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc{display:none}
/* Please visit the URL below for more information: */
/* https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */
</style>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
// your code here
});
</script>
</head>
<body for="html-export">
<div class="crossnote markdown-preview ">
<h1 id="руководство-по-установке-и-настройке-laravel-sanctum-с-api-авторизацией">Руководство по установке и настройке Laravel Sanctum с API авторизацией </h1>
<h2 id="описание">Описание </h2>
<p>Данное руководство описывает процесс установки и настройки <strong>Laravel Sanctum</strong> для API аутентификации с использованием <strong>wadakatu/laravel-spectrum</strong> для автоматической генерации Swagger документации.</p>
<hr>
<h2 id="содержание">Содержание </h2>
<ol>
<li><a href="#1-%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%BF%D0%B0%D0%BA%D0%B5%D1%82%D0%BE%D0%B2">Установка пакетов</a></li>
<li><a href="#2-%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-sanctum">Настройка Sanctum</a></li>
<li><a href="#3-%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0-api">Структура API</a></li>
<li><a href="#4-api-endpoints">API Endpoints</a></li>
<li><a href="#5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-api">Использование API</a></li>
<li><a href="#6-swagger-%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D1%8F">Swagger документация</a></li>
<li><a href="#7-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-artisan">Команды Artisan</a></li>
</ol>
<hr>
<h2 id="1-установка-пакетов">1. Установка пакетов </h2>
<h3 id="11-установка-laravel-sanctum">1.1 Установка Laravel Sanctum </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">composer</span> require laravel/sanctum
</code></pre><h3 id="12-установка-wadakatularavel-spectrum">1.2 Установка wadakatu/laravel-spectrum </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">composer</span> require wadakatu/laravel-spectrum
</code></pre><h3 id="13-публикация-конфигураций">1.3 Публикация конфигураций </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token comment"># Публикация Sanctum</span>
php artisan vendor:publish <span class="token parameter variable">--provider</span><span class="token operator">=</span><span class="token string">"Laravel\Sanctum\SanctumServiceProvider"</span>
<span class="token comment"># Публикация Spectrum (если требуется)</span>
php artisan vendor:publish <span class="token parameter variable">--provider</span><span class="token operator">=</span><span class="token string">"Wadakatu\LaravelSpectrum\LaravelSpectrumServiceProvider"</span>
</code></pre><h3 id="14-запуск-миграций">1.4 Запуск миграций </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code>php artisan migrate
</code></pre><blockquote>
<p><strong>Примечание:</strong> Если таблица <code>personal_access_tokens</code> уже существует, пропустите этот шаг.</p>
</blockquote>
<hr>
<h2 id="2-настройка-sanctum">2. Настройка Sanctum </h2>
<h3 id="21-обновление-модели-user">2.1 Обновление модели User </h3>
<p>Добавьте трейт <code>HasApiTokens</code> в модель <code>User</code>:</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Models/User.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Factories<span class="token punctuation">\</span>HasFactory</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>User</span> <span class="token keyword keyword-as">as</span> Authenticatable<span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Notifications<span class="token punctuation">\</span>Notifiable</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>HasApiTokens</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">Authenticatable</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-use">use</span> <span class="token package">HasApiTokens</span><span class="token punctuation">,</span> HasFactory<span class="token punctuation">,</span> Notifiable<span class="token punctuation">;</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="22-настройка-middleware">2.2 Настройка middleware </h3>
<p>Обновите файл <code>bootstrap/app.php</code>:</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// bootstrap/app.php</span>
<span class="token keyword keyword-return">return</span> <span class="token scope">Application<span class="token punctuation">::</span></span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token argument-name">basePath</span><span class="token punctuation">:</span> <span class="token function">dirname</span><span class="token punctuation">(</span><span class="token constant">__DIR__</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token operator">-&gt;</span><span class="token function">withRouting</span><span class="token punctuation">(</span>
<span class="token argument-name">web</span><span class="token punctuation">:</span> <span class="token constant">__DIR__</span><span class="token operator">.</span><span class="token string single-quoted-string">'/../routes/web.php'</span><span class="token punctuation">,</span>
<span class="token argument-name">api</span><span class="token punctuation">:</span> <span class="token constant">__DIR__</span><span class="token operator">.</span><span class="token string single-quoted-string">'/../routes/api.php'</span><span class="token punctuation">,</span>
<span class="token argument-name">commands</span><span class="token punctuation">:</span> <span class="token constant">__DIR__</span><span class="token operator">.</span><span class="token string single-quoted-string">'/../routes/console.php'</span><span class="token punctuation">,</span>
<span class="token argument-name">health</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'/up'</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
<span class="token operator">-&gt;</span><span class="token function">withMiddleware</span><span class="token punctuation">(</span><span class="token keyword keyword-function">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Middleware</span> <span class="token variable">$middleware</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-void">void</span> <span class="token punctuation">{</span>
<span class="token comment">//</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token operator">-&gt;</span><span class="token function">withExceptions</span><span class="token punctuation">(</span><span class="token keyword keyword-function">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Exceptions</span> <span class="token variable">$exceptions</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-void">void</span> <span class="token punctuation">{</span>
<span class="token comment">//</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><blockquote>
<p><strong>Важно:</strong> Не используйте <code>statefulApi()</code> для чистого token-based API, это вызовет ошибку 419 CSRF.</p>
</blockquote>
<h3 id="23-конфигурация-sanctum">2.3 Конфигурация Sanctum </h3>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// config/sanctum.php</span>
<span class="token keyword keyword-return">return</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'stateful'</span> <span class="token operator">=&gt;</span> <span class="token function">explode</span><span class="token punctuation">(</span><span class="token string single-quoted-string">','</span><span class="token punctuation">,</span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'SANCTUM_STATEFUL_DOMAINS'</span><span class="token punctuation">,</span> <span class="token function">sprintf</span><span class="token punctuation">(</span>
<span class="token string single-quoted-string">'%s%s'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1'</span><span class="token punctuation">,</span>
<span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'APP_URL'</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string single-quoted-string">','</span><span class="token operator">.</span><span class="token function">parse_url</span><span class="token punctuation">(</span><span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'APP_URL'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token constant">PHP_URL_HOST</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token string single-quoted-string">''</span>
<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'guard'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'web'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'expiration'</span> <span class="token operator">=&gt;</span> <span class="token constant">null</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'token_prefix'</span> <span class="token operator">=&gt;</span> <span class="token function">env</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'SANCTUM_TOKEN_PREFIX'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'middleware'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'verify_csrf_token'</span> <span class="token operator">=&gt;</span> <span class="token scope">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>VerifyCsrfToken<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'encrypt_cookies'</span> <span class="token operator">=&gt;</span> <span class="token scope">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EncryptCookies<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre><hr>
<h2 id="3-структура-api">3. Структура API </h2>
<h3 id="31-директории">3.1 Директории </h3>
<pre data-role="codeBlock" data-info="" class="language-text"><code>app/
├── Http/
│ ├── Controllers/
│ │ └── Api/
│ │ ├── AuthController.php
│ │ └── PostController.php
│ ├── Requests/
│ │ ├── LoginRequest.php
│ │ ├── RegisterRequest.php
│ │ ├── StorePostRequest.php
│ │ └── UpdatePostRequest.php
│ └── Resources/
│ ├── PostCollection.php
│ ├── PostResource.php
│ └── UserResource.php
└── Policies/
└── PostPolicy.php
</code></pre><h3 id="32-api-resources">3.2 API Resources </h3>
<p><strong>Laravel Spectrum</strong> автоматически определяет структуру ответа из API Resources.</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Resources/UserResource.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources<span class="token punctuation">\</span>Json<span class="token punctuation">\</span>JsonResource</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">UserResource</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">JsonResource</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">toArray</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-array">array</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'id'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">id</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'name'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">name</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'email'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">email</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'role'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">role</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'created_at'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">created_at</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Resources/PostResource.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources<span class="token punctuation">\</span>Json<span class="token punctuation">\</span>JsonResource</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">PostResource</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">JsonResource</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">toArray</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-array">array</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'id'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">id</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'title'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">title</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'content'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">content</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'user_id'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">user_id</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'user'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">UserResource</span><span class="token punctuation">(</span><span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token function">whenLoaded</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'created_at'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">created_at</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'updated_at'</span> <span class="token operator">=&gt;</span> <span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token property">updated_at</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="33-api-controllers">3.3 API Controllers </h3>
<p><strong>Laravel Spectrum</strong> автоматически анализирует контроллеры для генерации документации.</p>
<h4 id="authcontroller">AuthController </h4>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Controllers/Api/AuthController.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Api</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests<span class="token punctuation">\</span>LoginRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests<span class="token punctuation">\</span>RegisterRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources<span class="token punctuation">\</span>UserResource</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>JsonResponse</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Hash</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">AuthController</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token doc-comment comment">/**
* Register a new user.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token class-name type-declaration">RegisterRequest</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token variable">$user</span> <span class="token operator">=</span> <span class="token scope">User<span class="token punctuation">::</span></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'name'</span> <span class="token operator">=&gt;</span> <span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">name</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'email'</span> <span class="token operator">=&gt;</span> <span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">email</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'password'</span> <span class="token operator">=&gt;</span> <span class="token scope">Hash<span class="token punctuation">::</span></span><span class="token function">make</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">password</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$token</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-&gt;</span><span class="token function">createToken</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth-token'</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token property">plainTextToken</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'User registered successfully'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'user'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">UserResource</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'token'</span> <span class="token operator">=&gt;</span> <span class="token variable">$token</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">201</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Login user.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">login</span><span class="token punctuation">(</span><span class="token class-name type-declaration">LoginRequest</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token variable">$user</span> <span class="token operator">=</span> <span class="token scope">User<span class="token punctuation">::</span></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'email'</span><span class="token punctuation">,</span> <span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">email</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token variable">$user</span> <span class="token operator">||</span> <span class="token operator">!</span><span class="token scope">Hash<span class="token punctuation">::</span></span><span class="token function">check</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">password</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-&gt;</span><span class="token property">password</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'Invalid credentials'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">401</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token variable">$token</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-&gt;</span><span class="token function">createToken</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth-token'</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token property">plainTextToken</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'Login successful'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'user'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">UserResource</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'token'</span> <span class="token operator">=&gt;</span> <span class="token variable">$token</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Logout user.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">logout</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">currentAccessToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'Logged out successfully'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Get authenticated user.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">user</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'user'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">UserResource</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h4 id="postcontroller">PostController </h4>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Controllers/Api/PostController.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Api</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests<span class="token punctuation">\</span>StorePostRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests<span class="token punctuation">\</span>UpdatePostRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources<span class="token punctuation">\</span>PostCollection</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Resources<span class="token punctuation">\</span>PostResource</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>JsonResponse</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">Controller</span>
<span class="token punctuation">{</span>
<span class="token doc-comment comment">/**
* Display a listing of posts.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">PostCollection</span>
<span class="token punctuation">{</span>
<span class="token variable">$posts</span> <span class="token operator">=</span> <span class="token scope">Post<span class="token punctuation">::</span></span><span class="token function">with</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">latest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">paginate</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">PostCollection</span><span class="token punctuation">(</span><span class="token variable">$posts</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Store a newly created post.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">store</span><span class="token punctuation">(</span><span class="token class-name type-declaration">StorePostRequest</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token variable">$post</span> <span class="token operator">=</span> <span class="token scope">Post<span class="token punctuation">::</span></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'title'</span> <span class="token operator">=&gt;</span> <span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">title</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'content'</span> <span class="token operator">=&gt;</span> <span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token property">content</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'user_id'</span> <span class="token operator">=&gt;</span> <span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token property">id</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$post</span><span class="token operator">-&gt;</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'Post created successfully'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'post'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">PostResource</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">201</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Display the specified post.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">show</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token variable">$post</span><span class="token operator">-&gt;</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'post'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">PostResource</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Update the specified post.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">UpdatePostRequest</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$post</span><span class="token operator">-&gt;</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-&gt;</span><span class="token function">validated</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'Post updated successfully'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'post'</span> <span class="token operator">=&gt;</span> <span class="token keyword keyword-new">new</span> <span class="token class-name">PostResource</span><span class="token punctuation">(</span><span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* Remove the specified post.
*/</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">destroy</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">JsonResponse</span>
<span class="token punctuation">{</span>
<span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'delete'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$post</span><span class="token operator">-&gt;</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword keyword-return">return</span> <span class="token function">response</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string single-quoted-string">'message'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'Post deleted successfully'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="34-form-requests">3.4 Form Requests </h3>
<p><strong>Laravel Spectrum</strong> автоматически определяет правила валидации из Form Requests.</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Requests/RegisterRequest.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>FormRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">RegisterRequest</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">FormRequest</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">authorize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-bool">bool</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">rules</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-array">array</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'name'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'max:255'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'email'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'max:255'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'unique:users'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'password'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'min:8'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'confirmed'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Requests/LoginRequest.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>FormRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">LoginRequest</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">FormRequest</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">authorize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-bool">bool</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">rules</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-array">array</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'email'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'email'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'password'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Http/Requests/StorePostRequest.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Requests</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>FormRequest</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">StorePostRequest</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">FormRequest</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">authorize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-bool">bool</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">rules</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-array">array</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token punctuation">[</span>
<span class="token string single-quoted-string">'title'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'max:255'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'content'</span> <span class="token operator">=&gt;</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'string'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><hr>
<h2 id="4-api-endpoints">4. API Endpoints </h2>
<h3 id="41-маршруты">4.1 Маршруты </h3>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// routes/api.php</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Api<span class="token punctuation">\</span>AuthController</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Api<span class="token punctuation">\</span>PostController</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Route</span><span class="token punctuation">;</span>
<span class="token comment">/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
*/</span>
<span class="token comment">// Swagger Documentation - редирект на Swagger UI</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/docs'</span><span class="token punctuation">,</span> <span class="token keyword keyword-function">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/spectrum/openapi.html'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Public routes (без авторизации)</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/register'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">AuthController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'register'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.register'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/login'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">AuthController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'login'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.login'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Protected routes (требуют авторизации)</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">group</span><span class="token punctuation">(</span><span class="token keyword keyword-function">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Auth</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/logout'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">AuthController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'logout'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.logout'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">AuthController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'user'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.user'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Posts</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">PostController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'index'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.posts.index'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">PostController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'store'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.posts.store'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/{post}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">PostController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'show'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.posts.show'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/{post}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">PostController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'update'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.posts.update'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/posts/{post}'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token scope">PostController<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'destroy'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'api.posts.destroy'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><h3 id="42-список-endpoints">4.2 Список Endpoints </h3>
<table>
<thead>
<tr>
<th>Метод</th>
<th>Endpoint</th>
<th>Описание</th>
<th>Авторизация</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td><code>/api/register</code></td>
<td>Регистрация</td>
<td>Нет</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/login</code></td>
<td>Вход</td>
<td>Нет</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/logout</code></td>
<td>Выход</td>
<td>Да</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/user</code></td>
<td>Текущий пользователь</td>
<td>Да</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/posts</code></td>
<td>Список постов</td>
<td>Да</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/posts</code></td>
<td>Создание поста</td>
<td>Да</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/posts/{id}</code></td>
<td>Просмотр поста</td>
<td>Да</td>
</tr>
<tr>
<td>PUT</td>
<td><code>/api/posts/{id}</code></td>
<td>Обновление поста</td>
<td>Да</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/posts/{id}</code></td>
<td>Удаление поста</td>
<td>Да</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/docs</code></td>
<td>OpenAPI спецификация</td>
<td>Нет</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="5-использование-api">5. Использование API </h2>
<h3 id="51-регистрация">5.1 Регистрация </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">curl</span> <span class="token parameter variable">-X</span> POST http://la.test/api/register <span class="token punctuation">\</span>
<span class="token parameter variable">-H</span> <span class="token string">"Content-Type: application/json"</span> <span class="token punctuation">\</span>
<span class="token parameter variable">-d</span> <span class="token string">'{
"name": "John Doe",
"email": "john@example.com",
"password": "password123",
"password_confirmation": "password123"
}'</span>
</code></pre><h3 id="52-вход">5.2 Вход </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">curl</span> <span class="token parameter variable">-X</span> POST http://la.test/api/login <span class="token punctuation">\</span>
<span class="token parameter variable">-H</span> <span class="token string">"Content-Type: application/json"</span> <span class="token punctuation">\</span>
<span class="token parameter variable">-d</span> <span class="token string">'{
"email": "john@example.com",
"password": "password123"
}'</span>
</code></pre><h3 id="53-создание-поста">5.3 Создание поста </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">curl</span> <span class="token parameter variable">-X</span> POST http://la.test/api/posts <span class="token punctuation">\</span>
<span class="token parameter variable">-H</span> <span class="token string">"Content-Type: application/json"</span> <span class="token punctuation">\</span>
<span class="token parameter variable">-H</span> <span class="token string">"Authorization: Bearer {token}"</span> <span class="token punctuation">\</span>
<span class="token parameter variable">-d</span> <span class="token string">'{
"title": "My First Post",
"content": "This is the content of my post."
}'</span>
</code></pre><h3 id="54-выход">5.4 Выход </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">curl</span> <span class="token parameter variable">-X</span> POST http://la.test/api/logout <span class="token punctuation">\</span>
<span class="token parameter variable">-H</span> <span class="token string">"Authorization: Bearer {token}"</span>
</code></pre><hr>
<h2 id="6-swagger-документация">6. Swagger документация </h2>
<h3 id="61-доступ-к-документации">6.1 Доступ к документации </h3>
<p>Документация Swagger UI доступна по адресу:</p>
<pre data-role="codeBlock" data-info="" class="language-text"><code>{APP_URL}/api/docs
</code></pre><p>Например: <code>http://la.test/api/docs</code></p>
<h3 id="62-генерация-документации">6.2 Генерация документации </h3>
<p>Laravel Spectrum генерирует готовый HTML с Swagger UI:</p>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code>php artisan spectrum:generate <span class="token parameter variable">--format</span><span class="token operator">=</span>html
</code></pre><p>Это создаёт файл <code>public/spectrum/openapi.html</code>.</p>
<h3 id="63-настройка-доступа">6.3 Настройка доступа </h3>
<p>При генерации с флагом <code>--format=html</code> symlink создаётся автоматически.</p>
<p>Если symlink отсутствует, создайте его вручную:</p>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token function">ln</span> <span class="token parameter variable">-sf</span> /home/user/www/lara/storage/app/spectrum /home/user/www/lara/public/spectrum
</code></pre><h3 id="64-файлы-документации">6.4 Файлы документации </h3>
<pre data-role="codeBlock" data-info="" class="language-text"><code>public/
└── spectrum/
├── openapi.html # Swagger UI (генерируется с --format=html)
└── openapi.json # OpenAPI спецификация
</code></pre><h3 id="65-маршрут-для-документации">6.5 Маршрут для документации </h3>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// routes/api.php</span>
<span class="token comment">// Swagger Documentation</span>
<span class="token scope">Route<span class="token punctuation">::</span></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/docs'</span><span class="token punctuation">,</span> <span class="token keyword keyword-function">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">to</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/spectrum/openapi.html'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><hr>
<h2 id="7-команды-laravel-spectrum">7. Команды Laravel Spectrum </h2>
<h3 id="71-основные-команды">7.1 Основные команды </h3>
<p>Laravel Spectrum поставляется с готовыми командами для работы с документацией.</p>
<table>
<thead>
<tr>
<th>Команда</th>
<th>Описание</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>php artisan spectrum:generate</code></td>
<td>Генерация OpenAPI документации</td>
</tr>
<tr>
<td><code>php artisan spectrum:watch</code></td>
<td>Режим реального времени (port 8080)</td>
</tr>
<tr>
<td><code>php artisan spectrum:mock</code></td>
<td>Запуск mock сервера (port 8081)</td>
</tr>
<tr>
<td><code>php artisan spectrum:cache clear</code></td>
<td>Очистка кэша анализа</td>
</tr>
</tbody>
</table>
<h3 id="72-генерация-документации">7.2 Генерация документации </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token comment"># Генерация документации в формате HTML</span>
php artisan spectrum:generate <span class="token parameter variable">--format</span><span class="token operator">=</span>html
</code></pre><p><strong>Вывод:</strong></p>
<pre data-role="codeBlock" data-info="" class="language-text"><code>🚀 Generating API documentation...
🔍 Analyzing routes...
Found 9 API routes
📝 Generating OpenAPI specification...
✅ Documentation generated: /home/user/www/lara/public/spectrum/openapi.html
⏱️ Generation completed in 0.17 seconds
💾 Cache: 5 files, 7.04 KB
✅ Documentation generated successfully!
</code></pre><h3 id="73-режим-реального-времени">7.3 Режим реального времени </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token comment"># Запуск режима watch</span>
php artisan spectrum:watch
</code></pre><ul>
<li>Запускает локальный сервер на <code>http://localhost:8080</code></li>
<li>Автоматически обнаруживает изменения в файлах</li>
<li>Обновляет документацию в реальном времени</li>
</ul>
<h3 id="74-mock-сервер">7.4 Mock сервер </h3>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token comment"># Запуск mock API сервера</span>
php artisan spectrum:mock
</code></pre><ul>
<li>Запускает mock сервер на <code>http://localhost:8081</code></li>
<li>Генерирует моковые данные на основе спецификации</li>
<li>Позволяет тестировать API без реального бэкенда</li>
</ul>
<h3 id="75-обновление-документации">7.5 Обновление документации </h3>
<p>После добавления новых endpointов:</p>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token comment"># Очистить кэш и перегенерировать</span>
php artisan spectrum:cache <span class="token function">clear</span>
php artisan spectrum:generate
</code></pre><hr>
<h2 id="8-политики-доступа">8. Политики доступа </h2>
<h3 id="81-postpolicy">8.1 PostPolicy </h3>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Policies/PostPolicy.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">PostPolicy</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-bool">bool</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token variable">$user</span><span class="token operator">-&gt;</span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-&gt;</span><span class="token property">user_id</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">delete</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-bool">bool</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-return">return</span> <span class="token variable">$user</span><span class="token operator">-&gt;</span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-&gt;</span><span class="token property">user_id</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><h3 id="82-регистрация-политики">8.2 Регистрация политики </h3>
<p>Политики автоматически обнаруживаются Laravel. Для ручной регистрации:</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// app/Providers/AuthServiceProvider.php</span>
<span class="token keyword keyword-namespace">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">App<span class="token punctuation">\</span>Policies<span class="token punctuation">\</span>PostPolicy</span><span class="token punctuation">;</span>
<span class="token keyword keyword-use">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Providers<span class="token punctuation">\</span>AuthServiceProvider</span> <span class="token keyword keyword-as">as</span> ServiceProvider<span class="token punctuation">;</span>
<span class="token keyword keyword-class">class</span> <span class="token class-name-definition class-name">AuthServiceProvider</span> <span class="token keyword keyword-extends">extends</span> <span class="token class-name">ServiceProvider</span>
<span class="token punctuation">{</span>
<span class="token keyword keyword-protected">protected</span> <span class="token variable">$policies</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token scope">Post<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span> <span class="token operator">=&gt;</span> <span class="token scope">PostPolicy<span class="token punctuation">::</span></span><span class="token keyword keyword-class">class</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword keyword-public">public</span> <span class="token keyword keyword-function">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-void">void</span>
<span class="token punctuation">{</span>
<span class="token this keyword">$this</span><span class="token operator">-&gt;</span><span class="token function">registerPolicies</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><hr>
<h2 id="9-конфигурация-env">9. Конфигурация .env </h2>
<pre data-role="codeBlock" data-info="env" class="language-env env"><code>APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:...
APP_URL=http://la.test
DB_CONNECTION=sqlite
SESSION_DRIVER=database
</code></pre><hr>
<h2 id="10-тестирование">10. Тестирование </h2>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code><span class="token comment"># Проверка списка маршрутов</span>
php artisan route:list <span class="token parameter variable">--path</span><span class="token operator">=</span>api
<span class="token comment"># Генерация документации</span>
php artisan spectrum:generate
<span class="token comment"># Запуск сервера</span>
php artisan serve
</code></pre><hr>
<h2 id="troubleshooting">Troubleshooting </h2>
<h3 id="проблема-401-unauthorized">Проблема: 401 Unauthorized </h3>
<p><strong>Решение:</strong></p>
<ol>
<li>Проверьте токен в заголовке <code>Authorization: Bearer {token}</code></li>
<li>Убедитесь, что используете префикс <code>Bearer</code></li>
</ol>
<h3 id="проблема-419-csrf-error">Проблема: 419 CSRF Error </h3>
<p><strong>Решение:</strong><br>
Уберите <code>statefulApi()</code> из middleware в <code>bootstrap/app.php</code>:</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token operator">-&gt;</span><span class="token function">withMiddleware</span><span class="token punctuation">(</span><span class="token keyword keyword-function">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Middleware</span> <span class="token variable">$middleware</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type keyword-void">void</span> <span class="token punctuation">{</span>
<span class="token comment">// Не используйте statefulApi() для token-based API</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre><h3 id="проблема-rate-limiter-not-defined">Проблема: Rate limiter not defined </h3>
<p><strong>Решение:</strong><br>
Не используйте <code>throttleApi()</code>:</p>
<pre data-role="codeBlock" data-info="php" class="language-php php"><code><span class="token comment">// Неправильно</span>
<span class="token variable">$middleware</span><span class="token operator">-&gt;</span><span class="token function">throttleApi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Правильно (оставить пустым или удалить)</span>
<span class="token variable">$middleware</span><span class="token operator">-&gt;</span><span class="token function">api</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><hr>
<h2 id="заключение">Заключение </h2>
<p>Теперь у вас есть полностью настроенный API с:</p>
<ul>
<li><strong>Laravel Sanctum</strong> - аутентификация через токены</li>
<li><strong>wadakatu/laravel-spectrum</strong> - автоматическая генерация Swagger документации</li>
<li><strong>API Resources</strong> - форматирование ответов</li>
<li><strong>Form Requests</strong> - валидация</li>
<li><strong>Swagger документация</strong> - <code>/api/docs</code></li>
</ul>
<p><strong>Команды для работы:</strong></p>
<pre data-role="codeBlock" data-info="bash" class="language-bash bash"><code>php artisan spectrum:generate <span class="token comment"># Генерация документации</span>
php artisan spectrum:watch <span class="token comment"># Режим разработки</span>
php artisan spectrum:mock <span class="token comment"># Mock сервер</span>
</code></pre><p><strong>Документация:</strong> <code>http://la.test/api/docs</code></p>
</div>
</body></html>