752 lines
107 KiB
HTML
752 lines
107 KiB
HTML
<!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">-></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">-></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">-></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">-></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">=></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">=></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">=></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">=></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">=></span> <span class="token punctuation">[</span>
|
||
<span class="token string single-quoted-string">'verify_csrf_token'</span> <span class="token operator">=></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">=></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></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">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token this keyword">$this</span><span class="token operator">-></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">=></span> <span class="token variable">$request</span><span class="token operator">-></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">=></span> <span class="token variable">$request</span><span class="token operator">-></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">=></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">-></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">-></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">-></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">-></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">=></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">=></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">=></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">-></span><span class="token property">email</span><span class="token punctuation">)</span><span class="token operator">-></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">-></span><span class="token property">password</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-></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">-></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">=></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">-></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">-></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">-></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">=></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">=></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">=></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">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">currentAccessToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></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">-></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">=></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">-></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">=></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">-></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">-></span><span class="token function">latest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></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">=></span> <span class="token variable">$request</span><span class="token operator">-></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">=></span> <span class="token variable">$request</span><span class="token operator">-></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">=></span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></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">-></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">-></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">=></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">=></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">-></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">-></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">=></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">-></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">-></span><span class="token function">update</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></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">-></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">=></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">=></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">-></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">-></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">-></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">=></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">=></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">=></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">=></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">=></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">=></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">=></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">=></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></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">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></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">=></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">-></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">-></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">-></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">-></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> |