Commit 9ad00304 authored by 郭勇志's avatar 郭勇志

Initial commit

parents
Pipeline #49 failed with stages

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

{
"directory" : "vendor/bower-asset"
}
# yii console commands
/yii
/yii_test
/yii_test.bat
# phpstorm project files
.idea
# netbeans project files
nbproject
# zend studio for eclipse project files
.buildpath
.project
.settings
# windows thumbnail cache
Thumbs.db
# composer vendor dir
/vendor
# composer itself is not needed
composer.phar
# Mac DS_Store Files
.DS_Store
# phpunit itself is not needed
phpunit.phar
# local phpunit config
/phpunit.xml
# vagrant runtime
/.vagrant
# ignore generated files
/frontend/web/index.php
/frontend/web/index-test.php
/frontend/web/robots.txt
/backend/web/index.php
/backend/web/index-test.php
/backend/web/robots.txt
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Yii Software LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
<p align="center">
<a href="https://github.com/yiisoft" target="_blank">
<img src="https://avatars0.githubusercontent.com/u/993323" height="100px">
</a>
<h1 align="center">Yii 2 Advanced Project Template</h1>
<br>
</p>
Yii 2 Advanced Project Template is a skeleton [Yii 2](http://www.yiiframework.com/) application best for
developing complex Web applications with multiple tiers.
The template includes three tiers: front end, back end, and console, each of which
is a separate Yii application.
The template is designed to work in a team development environment. It supports
deploying the application in different environments.
Documentation is at [docs/guide/README.md](docs/guide/README.md).
[![Latest Stable Version](https://img.shields.io/packagist/v/yiisoft/yii2-app-advanced.svg)](https://packagist.org/packages/yiisoft/yii2-app-advanced)
[![Total Downloads](https://img.shields.io/packagist/dt/yiisoft/yii2-app-advanced.svg)](https://packagist.org/packages/yiisoft/yii2-app-advanced)
[![Build Status](https://travis-ci.org/yiisoft/yii2-app-advanced.svg?branch=master)](https://travis-ci.org/yiisoft/yii2-app-advanced)
DIRECTORY STRUCTURE
-------------------
```
common
config/ contains shared configurations
mail/ contains view files for e-mails
models/ contains model classes used in both backend and frontend
tests/ contains tests for common classes
console
config/ contains console configurations
controllers/ contains console controllers (commands)
migrations/ contains database migrations
models/ contains console-specific model classes
runtime/ contains files generated during runtime
backend
assets/ contains application assets such as JavaScript and CSS
config/ contains backend configurations
controllers/ contains Web controller classes
models/ contains backend-specific model classes
runtime/ contains files generated during runtime
tests/ contains tests for backend application
views/ contains view files for the Web application
web/ contains the entry script and Web resources
frontend
assets/ contains application assets such as JavaScript and CSS
config/ contains frontend configurations
controllers/ contains Web controller classes
models/ contains frontend-specific model classes
runtime/ contains files generated during runtime
tests/ contains tests for frontend application
views/ contains view files for the Web application
web/ contains the entry script and Web resources
widgets/ contains frontend widgets
vendor/ contains dependent 3rd-party packages
environments/ contains environment-based overrides
```
require 'yaml'
require 'fileutils'
required_plugins = %w( vagrant-hostmanager vagrant-vbguest )
required_plugins.each do |plugin|
exec "vagrant plugin install #{plugin}" unless Vagrant.has_plugin? plugin
end
domains = {
frontend: 'y2aa-frontend.test',
backend: 'y2aa-backend.test'
}
config = {
local: './vagrant/config/vagrant-local.yml',
example: './vagrant/config/vagrant-local.example.yml'
}
# copy config from example if local config not exists
FileUtils.cp config[:example], config[:local] unless File.exist?(config[:local])
# read config
options = YAML.load_file config[:local]
# check github token
if options['github_token'].nil? || options['github_token'].to_s.length != 40
puts "You must place REAL GitHub token into configuration:\n/yii2-app-advanced/vagrant/config/vagrant-local.yml"
exit
end
# vagrant configurate
Vagrant.configure(2) do |config|
# select the box
config.vm.box = 'bento/ubuntu-16.04'
# should we ask about box updates?
config.vm.box_check_update = options['box_check_update']
config.vm.provider 'virtualbox' do |vb|
# machine cpus count
vb.cpus = options['cpus']
# machine memory size
vb.memory = options['memory']
# machine name (for VirtualBox UI)
vb.name = options['machine_name']
end
# machine name (for vagrant console)
config.vm.define options['machine_name']
# machine name (for guest machine console)
config.vm.hostname = options['machine_name']
# network settings
config.vm.network 'private_network', ip: options['ip']
# sync: folder 'yii2-app-advanced' (host machine) -> folder '/app' (guest machine)
config.vm.synced_folder './', '/app', owner: 'vagrant', group: 'vagrant'
# disable folder '/vagrant' (guest machine)
config.vm.synced_folder '.', '/vagrant', disabled: true
# hosts settings (host machine)
config.vm.provision :hostmanager
config.hostmanager.enabled = true
config.hostmanager.manage_host = true
config.hostmanager.ignore_private_ip = false
config.hostmanager.include_offline = true
config.hostmanager.aliases = domains.values
# provisioners
config.vm.provision 'shell', path: './vagrant/provision/once-as-root.sh', args: [options['timezone']]
config.vm.provision 'shell', path: './vagrant/provision/once-as-vagrant.sh', args: [options['github_token']], privileged: false
config.vm.provision 'shell', path: './vagrant/provision/always-as-root.sh', run: 'always'
# post-install message (vagrant console)
config.vm.post_up_message = "Frontend URL: http://#{domains[:frontend]}\nBackend URL: http://#{domains[:backend]}"
end
FROM yiisoftware/yii2-php:7.2-apache
# Change document root for Apache
RUN sed -i -e 's|/app/web|/app/backend/web|g' /etc/apache2/sites-available/000-default.conf
\ No newline at end of file
<?php
namespace backend\assets;
use yii\web\AssetBundle;
/**
* Main backend application asset bundle.
*/
class AppAsset extends AssetBundle
{
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'css/site.css',
];
public $js = [
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
}
namespace: backend\tests
actor_suffix: Tester
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
settings:
bootstrap: _bootstrap.php
colors: true
memory_limit: 1024M
modules:
config:
Yii2:
configFile: 'config/codeception-local.php'
codeception-local.php
main-local.php
params-local.php
test-local.php
<?php
$params = array_merge(
require __DIR__ . '/../../common/config/params.php',
require __DIR__ . '/../../common/config/params-local.php',
require __DIR__ . '/params.php',
require __DIR__ . '/params-local.php'
);
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => [],
'components' => [
'request' => [
'csrfParam' => '_csrf-backend',
],
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
],
'session' => [
// this is the name of the session cookie used for login on the backend
'name' => 'advanced-backend',
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing'=>true,
'rules' => [
[
'class'=>'yii\rest\UrlRule',
'controller'=>['swagger','v1/shop/branch/branch'],
'extraPatterns'=>[
'GET test'=>'test',
'GET swagger'=>'swagger',
],
],
'GET swaggers/swagger/<id>'=>'swagger/swagger',
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=weishopdb',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
'params' => $params,
];
<?php
return [
'adminEmail' => 'admin@example.com',
];
<?php
return [
'id' => 'app-backend-tests',
'components' => [
'assetManager' => [
'basePath' => __DIR__ . '/../web/assets',
],
'urlManager' => [
'showScriptName' => true,
],
'request' => [
'cookieValidationKey' => 'test',
],
],
];
<?php
namespace backend\controllers;
use Yii;
use yii\web\Controller;
/**
* Swagger controller
* 创建api文档
*/
class SwaggerController extends Controller
{
public function actionSwagger()
{
$get=Yii::$app->request->get();
if(!empty($get)&&in_array($get,['v1','v2'])){
$projectRoot = Yii::getAlias('@backend').'/controllers/'.$get;
}else{
$projectRoot = Yii::getAlias('@backend').'/controllers/v1';
}
$swaggerRoot = Yii::getAlias('@swagger');
$swagger = \OpenApi\scan($projectRoot);
$swagger = json_encode($swagger) ;
$json_file = $swaggerRoot . '/v1/swagger.yaml';
$is_write = file_put_contents($json_file, $swagger);
if ($is_write == true) {
$this->redirect('../../swagger-ui/dist/');
}
}
}
<?php
namespace backend\controllers\v1;
use Yii;
use yii\web\Response;
use yii\rest\ActiveController;
/**
* Base controller
* 基类
*/
/**
* @OA\Info(
* title="后台接口v1版",
* version="v1",
* @OA\Contact(
*
* )
* )
*/
class BaseController extends ActiveController
{
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
return $behaviors;
}
}
<?php
namespace backend\controllers\v1\shop\branch;
use Yii;
use backend\controllers\v1\BaseController;
class BranchController extends BaseController
{
public $modelClass='';
public $serializer = [
'class' => 'yii\rest\Serializer',
'collectionEnvelope' => 'branch',
];
/**
* @OA\Get(
* path="/guoyongzhi/weiShopNew/backend/web/v1/shop/branch/branches/test",
* tags={"swagger事例"},
* description="swagger事例",
* summary="swagger事例",
* operationId="returnGetParam",
* @OA\Parameter(name="param",in="query",required=true,@OA\Schema(type="string")),
* @OA\Response(response="200",description="OK。一切正常"),
* @OA\Response(response="201",description="响应 POST 请求时成功创建一个资源"),
* @OA\Response(response="204",description="该请求被成功处理,响应不包含正文内容 (类似 DELETE 请求)"),
* @OA\Response(response="304",description="资源没有被修改。可以使用缓存的版本"),
* @OA\Response(response="400",description="错误的请求。可能通过用户方面的多种原因引起的,例如在请求体内有无效的JSON 数据,无效的操作参数,等等"),
* @OA\Response(response="401",description="验证失败"),
* @OA\Response(response="403",description="已经经过身份验证的用户不允许访问指定的 API 末端"),
* @OA\Response(response="404",description="所请求的资源不存在。"),
* @OA\Response(response="405",description="不被允许的方法。 请检查 Allow header 允许的HTTP方法"),
* @OA\Response(response="415",description="不支持的媒体类型。 所请求的内容类型或版本号是无效的"),
* @OA\Response(response="422",description="数据验证失败 (例如,响应一个 POST 请求)。 请检查响应体内详细的错误消息"),
* @OA\Response(response="429",description="请求过多。 由于限速请求被拒绝"),
* @OA\Response(response="500",description="内部服务器错误。 这可能是由于内部程序错误引起的"),
*
* )
*/
public function actionTest()
{
$get=Yii::$app->request->get();
return $get;
}
}
<?php
namespace backend\controllers\v1\user;
use backend\controllers\v1\BaseController;
class UserController extends BaseController
{
public $modelClass='app\models\v1\user\RbacUser';
public $serializer = [
'class' => 'yii\rest\Serializer',
'collectionEnvelope' => 'user',
];
public function actionIndex()
{
}
}
<?php
namespace app\models\v1\user;
use Yii;
/**
* This is the model class for table "rbac_user".
*
* @property string $GUID
* @property string $CODE 用户名(手机号&工号)
* @property string $NAME 姓名
* @property string $PASSWORD 密码
* @property string $ORG_GUID 组织机构号
* @property string $EMPLOYEE_GUID 如果USERGROUPGUID是店长或省级管理员,用来存门店GUID或省级GUID
* @property string $CREATE_GUID 创建人GUID
* @property string $CREATE_NAME 创建人姓名
* @property string $CREATE_DATE 创建时间
* @property string $UPDATE_GUID 更新人GUID
* @property string $UPDATE_NAME 更新人姓名
* @property string $UPDATE_DATE 更新时间
* @property int $IS_FORBID 是否禁用
* @property string $MOBILEPHONE 手机号
* @property int $CONTACTSEX 性别,1:男,0:女
* @property string $DESCRIPTION 用户头像URL
* @property string $USER_GUID 大平台USERGUID,普通用户此信息为空
* @property string $IS_UPLOAD_HX 是否上传华信,1:是
* @property int $IS_BELONG 是否员工,1:是
* @property string $REMARK 备注
* @property string $ALIPAY_UID 是否员工,1:是
* @property string $WX_UNIONID 小程序UNIONID
* @property string $WX_OPENID 小程序OPENID
* @property int $AGE 年龄
* @property string $SHARE_NO 分享码
*/
class RbacUser extends ActiveRecord implements IdentityInterface
{
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'rbac_user';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['GUID', 'CODE'], 'required'],
[['CREATE_DATE', 'UPDATE_DATE'], 'safe'],
[['IS_FORBID', 'CONTACTSEX', 'IS_BELONG', 'AGE'], 'integer'],
[['GUID', 'CODE', 'PASSWORD', 'ORG_GUID', 'EMPLOYEE_GUID', 'CREATE_GUID', 'UPDATE_GUID', 'MOBILEPHONE', 'USER_GUID', 'REMARK', 'ALIPAY_UID', 'WX_UNIONID', 'WX_OPENID', 'SHARE_NO'], 'string', 'max' => 50],
[['NAME', 'CREATE_NAME', 'UPDATE_NAME'], 'string', 'max' => 100],
[['DESCRIPTION'], 'string', 'max' => 255],
[['IS_UPLOAD_HX'], 'string', 'max' => 10],
[['GUID'], 'unique'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'GUID' => 'Guid',
'CODE' => 'Code',
'NAME' => 'Name',
'PASSWORD' => 'Password',
'ORG_GUID' => 'Org Guid',
'EMPLOYEE_GUID' => 'Employee Guid',
'CREATE_GUID' => 'Create Guid',
'CREATE_NAME' => 'Create Name',
'CREATE_DATE' => 'Create Date',
'UPDATE_GUID' => 'Update Guid',
'UPDATE_NAME' => 'Update Name',
'UPDATE_DATE' => 'Update Date',
'IS_FORBID' => 'Is Forbid',
'MOBILEPHONE' => 'Mobilephone',
'CONTACTSEX' => 'Contactsex',
'DESCRIPTION' => 'Description',
'USER_GUID' => 'User Guid',
'IS_UPLOAD_HX' => 'Is Upload Hx',
'IS_BELONG' => 'Is Belong',
'REMARK' => 'Remark',
'ALIPAY_UID' => 'Alipay Uid',
'WX_UNIONID' => 'Wx Unionid',
'WX_OPENID' => 'Wx Openid',
'AGE' => 'Age',
'SHARE_NO' => 'Share No',
];
}
}
*
!.gitignore
\ No newline at end of file
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', __DIR__.'/../../');
require_once YII_APP_BASE_PATH . '/vendor/autoload.php';
require_once YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php';
require_once YII_APP_BASE_PATH . '/common/config/bootstrap.php';
require_once __DIR__ . '/../config/bootstrap.php';
<?php
return [
[
'username' => 'erau',
'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI',
// password_0
'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne',
'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490',
'created_at' => '1392559490',
'updated_at' => '1392559490',
'email' => 'sfriesen@jenkins.info',
],
];
<?php
namespace backend\tests;
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class FunctionalTester extends \Codeception\Actor
{
use _generated\FunctionalTesterActions;
/**
* Define custom actions here
*/
}
<?php
namespace backend\tests;
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}
suite_namespace: backend\tests\functional
actor: FunctionalTester
modules:
enabled:
- Yii2
<?php
namespace backend\tests\functional;
use backend\tests\FunctionalTester;
use common\fixtures\UserFixture;
/**
* Class LoginCest
*/
class LoginCest
{
/**
* Load fixtures before db transaction begin
* Called in _before()
* @see \Codeception\Module\Yii2::_before()
* @see \Codeception\Module\Yii2::loadFixtures()
* @return array
*/
public function _fixtures()
{
return [
'user' => [
'class' => UserFixture::className(),
'dataFile' => codecept_data_dir() . 'login_data.php'
]
];
}
/**
* @param FunctionalTester $I
*/
public function loginUser(FunctionalTester $I)
{
$I->amOnPage('/site/login');
$I->fillField('Username', 'erau');
$I->fillField('Password', 'password_0');
$I->click('login-button');
$I->see('Logout (erau)', 'form button[type=submit]');
$I->dontSeeLink('Login');
$I->dontSeeLink('Signup');
}
}
<?php
/**
* Here you can initialize variables via \Codeception\Util\Fixtures class
* to store data in global array and use it in Cests.
*
* ```php
* // Here _bootstrap.php
* \Codeception\Util\Fixtures::add('user1', ['name' => 'davert']);
* ```
*
* In Cests
*
* ```php
* \Codeception\Util\Fixtures::get('user1');
* ```
*/
\ No newline at end of file
suite_namespace: backend\tests\unit
actor: UnitTester
<?php
/**
* Here you can initialize variables via \Codeception\Util\Fixtures class
* to store data in global array and use it in Tests.
*
* ```php
* // Here _bootstrap.php
* \Codeception\Util\Fixtures::add('user1', ['name' => 'davert']);
* ```
*
* In Tests
*
* ```php
* \Codeception\Util\Fixtures::get('user1');
* ```
*/
<?php
/* @var $this \yii\web\View */
/* @var $content string */
use backend\assets\AppAsset;
use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use common\widgets\Alert;
AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php $this->registerCsrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<div class="wrap">
<?php
NavBar::begin([
'brandLabel' => Yii::$app->name,
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar-inverse navbar-fixed-top',
],
]);
$menuItems = [
['label' => 'Home', 'url' => ['/site/index']],
];
if (Yii::$app->user->isGuest) {
$menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];
} else {
$menuItems[] = '<li>'
. Html::beginForm(['/site/logout'], 'post')
. Html::submitButton(
'Logout (' . Yii::$app->user->identity->username . ')',
['class' => 'btn btn-link logout']
)
. Html::endForm()
. '</li>';
}
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => $menuItems,
]);
NavBar::end();
?>
<div class="container">
<?= Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
<?= Alert::widget() ?>
<?= $content ?>
</div>
</div>
<footer class="footer">
<div class="container">
<p class="pull-left">&copy; <?= Html::encode(Yii::$app->name) ?> <?= date('Y') ?></p>
<p class="pull-right"><?= Yii::powered() ?></p>
</div>
</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
<?php
/* @var $this yii\web\View */
/* @var $name string */
/* @var $message string */
/* @var $exception Exception */
use yii\helpers\Html;
$this->title = $name;
?>
<div class="site-error">
<h1><?= Html::encode($this->title) ?></h1>
<div class="alert alert-danger">
<?= nl2br(Html::encode($message)) ?>
</div>
<p>
The above error occurred while the Web server was processing your request.
</p>
<p>
Please contact us if you think this is a server error. Thank you.
</p>
</div>
<?php
/* @var $this yii\web\View */
$this->title = 'My Yii Application';
?>
<div class="site-index">
<div class="jumbotron">
<h1>Congratulations!</h1>
<p class="lead">You have successfully created your Yii-powered application.</p>
<p><a class="btn btn-lg btn-success" href="http://www.yiiframework.com">Get started with Yii</a></p>
</div>
<div class="body-content">
<div class="row">
<div class="col-lg-4">
<h2>Heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.</p>
<p><a class="btn btn-default" href="http://www.yiiframework.com/doc/">Yii Documentation &raquo;</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.</p>
<p><a class="btn btn-default" href="http://www.yiiframework.com/forum/">Yii Forum &raquo;</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur.</p>
<p><a class="btn btn-default" href="http://www.yiiframework.com/extensions/">Yii Extensions &raquo;</a></p>
</div>
</div>
</div>
</div>
<?php
/* @var $this yii\web\View */
/* @var $form yii\bootstrap\ActiveForm */
/* @var $model \common\models\LoginForm */
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
$this->title = 'Login';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-login">
<h1><?= Html::encode($this->title) ?></h1>
<p>Please fill out the following fields to login:</p>
<div class="row">
<div class="col-lg-5">
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= $form->field($model, 'rememberMe')->checkbox() ?>
<div class="form-group">
<?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
</div>
# use mod_rewrite for pretty URL support
RewriteEngine on
# if a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward the request to index.php
RewriteRule . index.php
\ No newline at end of file
html,
body {
height: 100%;
}
.wrap {
min-height: 100%;
height: auto;
margin: 0 auto -60px;
padding: 0 0 60px;
}
.wrap > .container {
padding: 70px 15px 20px;
}
.footer {
height: 60px;
background-color: #f5f5f5;
border-top: 1px solid #ddd;
padding-top: 20px;
}
.jumbotron {
text-align: center;
background-color: transparent;
}
.jumbotron .btn {
font-size: 21px;
padding: 14px 24px;
}
.not-set {
color: #c55;
font-style: italic;
}
/* add sorting icons to gridview sort links */
a.asc:after, a.desc:after {
position: relative;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: normal;
line-height: 1;
padding-left: 5px;
}
a.asc:after {
content: /*"\e113"*/ "\e151";
}
a.desc:after {
content: /*"\e114"*/ "\e152";
}
.sort-numerical a.asc:after {
content: "\e153";
}
.sort-numerical a.desc:after {
content: "\e154";
}
.sort-ordinal a.asc:after {
content: "\e155";
}
.sort-ordinal a.desc:after {
content: "\e156";
}
.grid-view th,
.grid-view td:last-child {
white-space: nowrap;
}
.grid-view .filters input,
.grid-view .filters select {
min-width: 50px;
}
.hint-block {
display: block;
margin-top: 5px;
color: #999;
}
.error-summary {
color: #a94442;
background: #fdf7f7;
border-left: 3px solid #eed3d7;
padding: 10px 20px;
margin: 0 0 15px 0;
}
/* align the logout "link" (button in form) of the navbar */
.nav li > form > button.logout {
padding: 15px;
border: none;
}
@media(max-width:767px) {
.nav li > form > button.logout {
display:block;
text-align: left;
width: 100%;
padding: 10px 15px;
}
}
.nav > li > form > button.logout:focus,
.nav > li > form > button.logout:hover {
text-decoration: none;
}
.nav > li > form > button.logout:focus {
outline: none;
}
{
"presets": [
[
"@babel/env",
{
"targets": {
"browsers": [
/* benefit of C/S/FF/Edge only? */
"> 1%",
"last 2 versions",
"Firefox ESR",
"not dead",
]
},
"useBuiltIns": "entry",
"corejs": "2"
}
],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"corejs": "2"
}],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining",
["transform-react-remove-prop-types", {
"additionalLibraries": ["react-immutable-proptypes"]
}],
[
"babel-plugin-module-resolver",
{
"alias": {
"root": ".",
"components": "./src/core/components",
"containers": "./src/core/containers",
"core": "./src/core",
"plugins": "./src/plugins",
"img": "./src/img",
"corePlugins": "./src/core/plugins",
"less": "./src/less",
}
}
]
]
}
/.git
/.github
/dev-helpers
/docs
/src
/swagger-ui-dist-package
/test
/node_modules
\ No newline at end of file
root = true
[*]
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
parser: babel-eslint
env:
browser: true
node: true
es6: true
parserOptions:
ecmaFeatures:
jsx: true
extends:
- eslint:recommended
- plugin:react/recommended
plugins:
- react
- mocha
- import
settings:
react:
pragma: React
version: '15.0'
rules:
semi: [2, never]
strict: 0
quotes: [2, double, { allowTemplateLiterals: true }]
no-unused-vars: 2
no-multi-spaces: 1
camelcase: 1
no-use-before-define: [2, nofunc]
no-underscore-dangle: 0
no-unused-expressions: 1
comma-dangle: 0
no-console: [2, { allow: [warn, error] }]
react/jsx-no-bind: 1
react/jsx-no-target-blank: 2
react/display-name: 0
mocha/no-exclusive-tests: 2
import/no-extraneous-dependencies: 2
react/jsx-filename-extension: 2
\ No newline at end of file
---
name: Bug report
about: Report an issue you're experiencing
---
<!---
Thanks for filing a bug report! 😄
Before you submit, please read the following:
If you're here to report a security issue, please STOP writing an issue and
contact us at security@swagger.io instead!
Search open/closed issues before submitting!
Issues on GitHub are only related to problems of Swagger-UI itself. We'll try
to offer support here for your use case, but we can't offer help with projects
that use Swagger-UI indirectly, like Springfox or swagger-node.
Likewise, we can't accept bugs in the Swagger/OpenAPI specifications
themselves, or anything that violates the specifications.
-->
### Q&A (please complete the following information)
- OS: [e.g. macOS]
- Browser: [e.g. chrome, safari]
- Version: [e.g. 22]
- Method of installation: [e.g. npm, dist assets]
- Swagger-UI version: [e.g. 3.10.0]
- Swagger/OpenAPI version: [e.g. Swagger 2.0, OpenAPI 3.0]
### Content & configuration
<!--
Provide us with a way to see what you're seeing,
so that we can fix your issue.
-->
Example Swagger/OpenAPI definition:
```yaml
# your YAML here
```
Swagger-UI configuration options:
```js
SwaggerUI({
// your config options here
})
```
```
?yourQueryStringConfig
```
### Describe the bug you're encountering
<!-- A clear and concise description of what the bug is. -->
### To reproduce...
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
### Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
### Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
### Additional context or thoughts
<!-- Add any other context about the problem here. -->
---
name: Feature request
about: Suggest an new feature or enhancement for this project
---
### Content & configuration
Swagger/OpenAPI definition:
```yaml
# your YAML here
```
Swagger-UI configuration options:
```js
SwaggerUI({
// your config options here
})
```
```
?yourQueryStringConfig
```
### Is your feature request related to a problem?
<!--
Please provide a clear and concise description of what the problem is.
"I'm always frustrated when..."
-->
### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. -->
### Describe alternatives you've considered
<!--
A clear and concise description of any alternative solutions or features
you've considered.
-->
### Additional context
<!-- Add any other context or screenshots about the feature request here. -->
---
name: Support
about: Ask a question or request help with your implementation.
---
<!--
We can only offer support for Swagger-UI itself.
If you're having a problem with a library that uses Swagger-UI
(for example, Springfox or swagger-node), please open an issue
in that project's repository instead.
-->
### Q&A (please complete the following information)
- OS: [e.g. macOS]
- Browser: [e.g. chrome, safari]
- Version: [e.g. 22]
- Method of installation: [e.g. npm, dist assets]
- Swagger-UI version: [e.g. 3.10.0]
- Swagger/OpenAPI version: [e.g. Swagger 2.0, OpenAPI 3.0]
### Content & configuration
<!-- Provide us with a way to see what you're seeing, so that we can help. -->
Swagger/OpenAPI definition:
```yaml
# your YAML here
```
Swagger-UI configuration options:
```js
SwaggerUI({
// your config options here
})
```
```
?yourQueryStringConfig
```
### Screenshots
<!-- If applicable, add screenshots to help give context to your problem. -->
### How can we help?
<!-- Your question or problem goes here! -->
daysUntilLock: 365
skipCreatedBefore: 2017-03-29 # initial release of Swagger UI 3.0.0
exemptLabels: []
lockLabel: "locked-by: lock-bot"
setLockReason: false
only: issues
lockComment: false
# lockComment: |
# Locking due to inactivity.
# This is done to avoid resurrecting old issues and bumping long threads with new, possibly unrelated content.
# If you think you're experiencing something similar to what you've found here: please [open a new issue](https://github.com/swagger-api/swagger-ui/issues/new/choose), follow the template, and reference this issue in your report.
# Thanks!
<!--- Provide a general summary of your changes in the Title above -->
### Description
<!--- Describe your changes in detail -->
### Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
<!--- Use the magic "Fixes #1234" format, so the issues are -->
<!--- automatically closed when this PR is merged. -->
### How Has This Been Tested?
<!--- Please describe in detail how you manually tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
### Screenshots (if appropriate):
## Checklist
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
### My PR contains...
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] No code changes (`src/` is unmodified: changes to documentation, CI, metadata, etc.)
- [ ] Dependency changes (any modification to dependencies in `package.json`)
- [ ] Bug fixes (non-breaking change which fixes an issue)
- [ ] Improvements (misc. changes to existing features)
- [ ] Features (non-breaking change which adds functionality)
### My changes...
- [ ] are breaking changes to a public API (config options, System API, major UI change, etc).
- [ ] are breaking changes to a private API (Redux, component props, utility functions, etc.).
- [ ] are breaking changes to a developer API (npm script behavior changes, new dev system dependencies, etc).
- [ ] are not breaking changes.
### Documentation
- [ ] My changes do not require a change to the project documentation.
- [ ] My changes require a change to the project documentation.
- [ ] If yes to above: I have updated the documentation accordingly.
### Automated tests
- [ ] My changes can not or do not need to be tested.
- [ ] My changes can and should be tested by unit and/or integration tests.
- [ ] If yes to above: I have added tests to cover my changes.
- [ ] If yes to above: I have taken care to cover edge cases in my tests.
- [ ] All new and existing tests passed.
node_modules
.idea
.vscode
.deps_check
.DS_Store
.nyc_output
npm-debug.log*
.eslintcache
*.iml
selenium-debug.log
test/e2e/db.json
docs/_book
flavors/**/dist/*
# Cypress
test/e2e-cypress/screenshots
test/e2e-cypress/videos
\ No newline at end of file
*
*/
!README.md
!package.json
!dist/swagger-ui.js
!dist/swagger-ui.js.map
!dist/swagger-ui-standalone-preset.js
!dist/swagger-ui-standalone-preset.js.map
!dist/swagger-ui.css
!dist/swagger-ui.css.map
!dist/oauth2-redirect.html
semi: false
trailingComma: es5
endOfLine: lf
requirePragma: true
insertPragma: true
# Looking for information on environment variables?
# We don't declare them here — take a look at our docs.
# https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md
FROM nginx:1.17-alpine
RUN apk --no-cache add nodejs
LABEL maintainer="fehguy"
ENV API_KEY "**None**"
ENV SWAGGER_JSON "/app/swagger.json"
ENV PORT 8080
ENV BASE_URL ""
COPY ./docker/nginx.conf ./docker/cors.conf /etc/nginx/
# copy swagger files to the `/js` folder
COPY ./dist/* /usr/share/nginx/html/
COPY ./docker/run.sh /usr/share/nginx/
COPY ./docker/configurator /usr/share/nginx/configurator
RUN chmod +x /usr/share/nginx/run.sh && \
chmod -R a+rw /usr/share/nginx && \
chmod -R a+rw /etc/nginx && \
chmod -R a+rw /var && \
chmod -R a+rw /var/run
EXPOSE 8080
CMD ["sh", "/usr/share/nginx/run.sh"]
Copyright 2019 SmartBear Software
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# <img src="https://raw.githubusercontent.com/swagger-api/swagger.io/wordpress/images/assets/SWU-logo-clr.png" height="80">
[![NPM version](https://badge.fury.io/js/swagger-ui.svg)](http://badge.fury.io/js/swagger-ui)
[![Build Status](https://jenkins.swagger.io/view/OSS%20-%20JavaScript/job/oss-swagger-ui-master/badge/icon?subject=jenkins%20build)](https://jenkins.swagger.io/view/OSS%20-%20JavaScript/job/oss-swagger-ui-master/)
[![npm audit](https://jenkins.swagger.io/buildStatus/icon?job=oss-swagger-ui-security-audit&subject=npm%20audit)](https://jenkins.swagger.io/job/oss-swagger-ui-security-audit/lastBuild/console)
![total GitHub contributors](https://img.shields.io/github/contributors-anon/swagger-api/swagger-ui.svg)
![monthly npm installs](https://img.shields.io/npm/dm/swagger-ui.svg?label=npm%20downloads)
![total docker pulls](https://img.shields.io/docker/pulls/swaggerapi/swagger-ui.svg)
![monthly packagist installs](https://img.shields.io/packagist/dm/swagger-api/swagger-ui.svg?label=packagist%20installs)
![gzip size](https://img.shields.io/bundlephobia/minzip/swagger-ui.svg?label=gzip%20size)
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first issue](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%22) label.
**🕰️ Looking for the older version of Swagger UI?** Refer to the [*2.x* branch](https://github.com/swagger-api/swagger-ui/tree/2.x).
This repository publishes to three different NPM modules:
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is a traditional npm module intended for use in single-page applications that are capable of resolving dependencies (via Webpack, Browserify, etc).
* [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) is a dependency-free module that includes everything you need to serve Swagger UI in a server-side project, or a single-page application that can't resolve npm module dependencies.
* [swagger-ui-react](https://www.npmjs.com/package/swagger-ui-react) is Swagger UI packaged as a React component for use in React applications.
We strongly suggest that you use `swagger-ui` instead of `swagger-ui-dist` if you're building a single-page application, since `swagger-ui-dist` is significantly larger.
## Compatibility
The OpenAPI Specification has undergone 5 revisions since initial creation in 2010. Compatibility between Swagger UI and the OpenAPI Specification is as follows:
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | -----
3.18.3 | 2018-08-03 | 2.0, 3.0 | [tag v3.18.3](https://github.com/swagger-api/swagger-ui/tree/v3.18.3)
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
2.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24)
1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13)
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1)
## Documentation
#### Usage
- [Installation](docs/usage/installation.md)
- [Configuration](docs/usage/configuration.md)
- [CORS](docs/usage/cors.md)
- [OAuth2](docs/usage/oauth2.md)
- [Deep Linking](docs/usage/deep-linking.md)
- [Limitations](docs/usage/limitations.md)
- [Version detection](docs/usage/version-detection.md)
#### Customization
- [Overview](docs/customization/overview.md)
- [Plugin API](docs/customization/plugin-api.md)
- [Custom layout](docs/customization/custom-layout.md)
#### Development
- [Setting up](docs/development/setting-up.md)
- [Scripts](docs/development/scripts.md)
##### Integration Tests
You will need JDK of version 7 or higher as instructed here
https://nightwatchjs.org/gettingstarted/#selenium-server-setup
Integration tests can be run locally with `npm run e2e` - be sure you aren't running a dev server when testing!
### Browser support
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.
### Known Issues
To help with the migration, here are the currently known issues with 3.X. This list will update regularly, and will not include features that were not implemented in previous versions.
- Only part of the parameters previously supported are available.
- The JSON Form Editor is not implemented.
- Support for `collectionFormat` is partial.
- l10n (translations) is not implemented.
- Relative path support for external files is not implemented.
## Security contact
Please disclose any security-related issues or vulnerabilities by emailing [security@swagger.io](mailto:security@swagger.io), instead of using the public issue tracker.
## License
Copyright 2019 SmartBear Software
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# Security Policy
If you believe you've found an exploitable security issue in Swagger UI,
**please don't create a public issue**.
## Supported versions
This is the list of versions of `swagger-ui` which are
currently being supported with security updates.
| Version | Supported | Notes |
| -------- | ------------------ | ---------------------- |
| 3.x | :white_check_mark: | |
| 2.x | :x: | End-of-life as of 2017 |
## Reporting a vulnerability
To report a vulnerability please send an email with the details to [security@swagger.io](mailto:security@swagger.io).
We'll acknowledge receipt of your report ASAP, and set expectations on how we plan to handle it.
{
"name": "swagger-api/swagger-ui",
"description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.",
"keywords": [
"Swagger",
"OpenAPI",
"specification",
"documentation",
"API",
"UI"
],
"homepage": "http://swagger.io",
"license": "Apache-2.0",
"authors": [
{
"name": "Anna Bodnia",
"email": "anna.bodnia@gmail.com"
},
{
"name": "Buu Nguyen",
"email": "buunguyen@gmail.com"
},
{
"name": "Josh Ponelat",
"email": "jponelat@gmail.com"
},
{
"name": "Kyle Shockey",
"email": "kyleshockey1@gmail.com"
},
{
"name": "Robert Barnwell",
"email": "robert@robertismy.name"
},
{
"name": "Sahar Jafari",
"email": "shr.jafari@gmail.com"
}
]
}
{
"fileServerFolder": "test/e2e-cypress/static",
"fixturesFolder": "test/e2e-cypress/fixtures",
"integrationFolder": "test/e2e-cypress/tests",
"pluginsFile": "test/e2e-cypress/plugins/index.js",
"screenshotsFolder": "test/e2e-cypress/screenshots",
"supportFile": "test/e2e-cypress/support/index.js",
"videosFolder": "test/e2e-cypress/videos",
"baseUrl": "http://localhost:3230/",
"video": false
}
<!-- HTML for dev server -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
window["SwaggerUIBundle"] = window["swagger-ui-bundle"]
window["SwaggerUIStandalonePreset"] = window["swagger-ui-standalone-preset"]
// Build a system
const ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
ui.initOAuth({
clientId: "your-client-id",
clientSecret: "your-client-secret-if-required",
realm: "your-realms",
appName: "your-app-name",
scopeSeparator: " ",
additionalQueryStringParams: {},
usePkceWithAuthorizationCodeGrant: false
})
}
</script>
</body>
</html>
<!doctype html>
<html lang="en-US">
<body onload="run()">
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
</script>
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "../../swagger-yaml/v1/swagger.yaml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>
<!doctype html>
<html lang="en-US">
<title>Swagger UI: OAuth2 Redirect</title>
<body onload="run()">
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
</script>
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
module.exports.indent = function indent(str, len, fromLine = 0) {
return str
.split("\n")
.map((line, i) => {
if (i + 1 >= fromLine) {
return `${Array(len + 1).join(" ")}${line}`
} else {
return line
}
})
.join("\n")
}
\ No newline at end of file
const fs = require("fs")
const path = require("path")
const translator = require("./translator")
const oauthBlockBuilder = require("./oauth")
const indent = require("./helpers").indent
const START_MARKER = "// Begin Swagger UI call region"
const END_MARKER = "// End Swagger UI call region"
const targetPath = path.normalize(process.cwd() + "/" + process.argv[2])
const originalHtmlContent = fs.readFileSync(targetPath, "utf8")
const startMarkerIndex = originalHtmlContent.indexOf(START_MARKER)
const endMarkerIndex = originalHtmlContent.indexOf(END_MARKER)
const beforeStartMarkerContent = originalHtmlContent.slice(0, startMarkerIndex)
const afterEndMarkerContent = originalHtmlContent.slice(
endMarkerIndex + END_MARKER.length
)
if (startMarkerIndex < 0 || endMarkerIndex < 0) {
console.error("ERROR: Swagger UI was unable to inject Docker configuration data!")
console.error("! This can happen when you provide custom HTML to Swagger UI.")
console.error("! ")
console.error("! In order to solve this, add the `Begin Swagger UI call region`")
console.error("! and `End Swagger UI call region` markers to your HTML.")
console.error("! See the repository for an example:")
console.error("! https://github.com/swagger-api/swagger-ui/blob/02758b8125dbf38763cfd5d4f91c7c803e9bd0ad/dist/index.html#L40-L54")
console.error("! ")
console.error("! If you're seeing this message and aren't using custom HTML,")
console.error("! this message may be a bug. Please file an issue:")
console.error("! https://github.com/swagger-api/swagger-ui/issues/new/choose")
process.exit(0)
}
fs.writeFileSync(
targetPath,
`${beforeStartMarkerContent}
${START_MARKER}
const ui = SwaggerUIBundle({
${indent(translator(process.env, { injectBaseConfig: true }), 8, 2)}
})
${indent(oauthBlockBuilder(process.env), 6, 2)}
${END_MARKER}
${afterEndMarkerContent}`
)
const translator = require("./translator")
const indent = require("./helpers").indent
const oauthBlockSchema = {
OAUTH_CLIENT_ID: {
type: "string",
name: "clientId"
},
OAUTH_CLIENT_SECRET: {
type: "string",
name: "clientSecret",
onFound: () => console.warn("Swagger UI warning: don't use `OAUTH_CLIENT_SECRET` in production!")
},
OAUTH_REALM: {
type: "string",
name: "realm"
},
OAUTH_APP_NAME: {
type: "string",
name: "appName"
},
OAUTH_SCOPE_SEPARATOR: {
type: "string",
name: "scopeSeparator"
},
OAUTH_ADDITIONAL_PARAMS: {
type: "object",
name: "additionalQueryStringParams"
},
OAUTH_USE_PKCE: {
type: "boolean",
name: "usePkceWithAuthorizationCodeGrant"
}
}
module.exports = function oauthBlockBuilder(env) {
const translatorResult = translator(env, { schema: oauthBlockSchema })
if(translatorResult) {
return (
`ui.initOAuth({
${indent(translatorResult, 2)}
})`)
}
return ``
}
\ No newline at end of file
// Converts an object of environment variables into a Swagger UI config object
const configSchema = require("./variables")
const defaultBaseConfig = {
url: {
value: "https://petstore.swagger.io/v2/swagger.json",
schema: {
type: "string",
base: true
}
},
dom_id: {
value: "#swagger-ui",
schema: {
type: "string",
base: true
}
},
deepLinking: {
value: "true",
schema: {
type: "boolean",
base: true
}
},
presets: {
value: `[\n SwaggerUIBundle.presets.apis,\n SwaggerUIStandalonePreset\n]`,
schema: {
type: "array",
base: true
}
},
plugins: {
value: `[\n SwaggerUIBundle.plugins.DownloadUrl\n]`,
schema: {
type: "array",
base: true
}
},
layout: {
value: "StandaloneLayout",
schema: {
type: "string",
base: true
}
}
}
function objectToKeyValueString(env, { injectBaseConfig = false, schema = configSchema, baseConfig = defaultBaseConfig } = {}) {
let valueStorage = injectBaseConfig ? Object.assign({}, baseConfig) : {}
const keys = Object.keys(env)
// Compute an intermediate representation that holds candidate values and schemas.
//
// This is useful for deduping between multiple env keys that set the same
// config variable.
keys.forEach(key => {
const varSchema = schema[key]
const value = env[key]
if(!varSchema) return
if(varSchema.onFound) {
varSchema.onFound()
}
const storageContents = valueStorage[varSchema.name]
if(storageContents) {
if (varSchema.legacy === true && !storageContents.schema.base) {
// If we're looking at a legacy var, it should lose out to any already-set value
// except for base values
return
}
delete valueStorage[varSchema.name]
}
valueStorage[varSchema.name] = {
value,
schema: varSchema
}
})
// Compute a key:value string based on valueStorage's contents.
let result = ""
Object.keys(valueStorage).forEach(key => {
const value = valueStorage[key]
const escapedName = /[^a-zA-Z0-9]/.test(key) ? `"${key}"` : key
if (value.schema.type === "string") {
result += `${escapedName}: "${value.value}",\n`
} else {
result += `${escapedName}: ${value.value === "" ? `undefined` : value.value},\n`
}
})
return result.trim()
}
module.exports = objectToKeyValueString
\ No newline at end of file
const standardVariables = {
CONFIG_URL: {
type: "string",
name: "configUrl"
},
DOM_ID: {
type: "string",
name: "dom_id"
},
SPEC: {
type: "object",
name: "spec"
},
URL: {
type: "string",
name: "url"
},
URLS: {
type: "array",
name: "urls"
},
URLS_PRIMARY_NAME: {
type: "string",
name: "urls.primaryName"
},
LAYOUT: {
type: "string",
name: "layout"
},
DEEP_LINKING: {
type: "boolean",
name: "deepLinking"
},
DISPLAY_OPERATION_ID: {
type: "boolean",
name: "displayOperationId"
},
DEFAULT_MODELS_EXPAND_DEPTH: {
type: "number",
name: "defaultModelsExpandDepth"
},
DEFAULT_MODEL_EXPAND_DEPTH: {
type: "number",
name: "defaultModelExpandDepth"
},
DEFAULT_MODEL_RENDERING: {
type: "string",
name: "defaultModelRendering"
},
DISPLAY_REQUEST_DURATION: {
type: "boolean",
name: "displayRequestDuration"
},
DOC_EXPANSION: {
type: "string",
name: "docExpansion"
},
FILTER: {
type: "string",
name: "filter"
},
MAX_DISPLAYED_TAGS: {
type: "number",
name: "maxDisplayedTags"
},
SHOW_EXTENSIONS: {
type: "boolean",
name: "showExtensions"
},
SHOW_COMMON_EXTENSIONS: {
type: "boolean",
name: "showCommonExtensions"
},
OAUTH2_REDIRECT_URL: {
type: "string",
name: "oauth2RedirectUrl"
},
SHOW_MUTATED_REQUEST: {
type: "boolean",
name: "showMutatedRequest"
},
SUPPORTED_SUBMIT_METHODS: {
type: "array",
name: "supportedSubmitMethods"
},
VALIDATOR_URL: {
type: "string",
name: "validatorUrl"
},
WITH_CREDENTIALS: {
type: "boolean",
name: "withCredentials",
}
}
const legacyVariables = {
API_URL: {
type: "string",
name: "url",
legacy: true
},
API_URLS: {
type: "array",
name: "urls",
legacy: true
}
}
module.exports = Object.assign({}, standardVariables, legacyVariables)
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' $access_control_max_age always;
if ($request_method = OPTIONS) {
return 204;
}
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_static on;
gzip_disable "msie6";
gzip_vary on;
gzip_types text/plain text/css application/javascript;
map $request_method $access_control_max_age {
OPTIONS 1728000; # 20 days
}
server {
listen 8080;
server_name localhost;
index index.html index.htm;
location / {
alias /usr/share/nginx/html/;
expires 1d;
location ~* \.(?:json|yml|yaml)$ {
expires -1;
include cors.conf;
}
include cors.conf;
}
}
}
#! /bin/sh
set -e
BASE_URL=${BASE_URL:-/}
NGINX_ROOT=/usr/share/nginx/html
INDEX_FILE=$NGINX_ROOT/index.html
node /usr/share/nginx/configurator $INDEX_FILE
replace_in_index () {
if [ "$1" != "**None**" ]; then
sed -i "s|/\*||g" $INDEX_FILE
sed -i "s|\*/||g" $INDEX_FILE
sed -i "s|$1|$2|g" $INDEX_FILE
fi
}
replace_or_delete_in_index () {
if [ -z "$2" ]; then
sed -i "/$1/d" $INDEX_FILE
else
replace_in_index $1 $2
fi
}
if [ "${BASE_URL}" ]; then
sed -i "s|location / {|location $BASE_URL {|g" /etc/nginx/nginx.conf
fi
replace_in_index myApiKeyXXXX123456789 $API_KEY
if [[ -f $SWAGGER_JSON ]]; then
cp -s $SWAGGER_JSON $NGINX_ROOT
REL_PATH="./$(basename $SWAGGER_JSON)"
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
fi
# replace the PORT that nginx listens on if PORT is supplied
if [[ -n "${PORT}" ]]; then
sed -i "s|8080|${PORT}|g" /etc/nginx/nginx.conf
fi
find $NGINX_ROOT -type f -regex ".*\.\(html\|js\|css\)" -exec sh -c "gzip < {} > {}.gz" \;
exec nginx -g 'daemon off;'
# Swagger UI
Welcome to the Swagger UI documentation!
A table of contents can be found at `SUMMARY.md`.
#### Usage
- [Installation](usage/installation.md)
- [Configuration](usage/configuration.md)
- [CORS](usage/cors.md)
- [OAuth2](usage/oauth2.md)
- [Deep Linking](usage/deep-linking.md)
- [Limitations](usage/limitations.md)
- [Version detection](usage/version-detection.md)
#### Customization
- [Overview](customization/overview.md)
- [Plugin API](customization/plugin-api.md)
- [Custom layout](customization/custom-layout.md)
#### Development
- [Setting up](development/setting-up.md)
- [Scripts](development/scripts.md)
# Creating a custom layout
**Layouts** are a special type of component that Swagger UI uses as the root component for the entire application. You can define custom layouts in order to have high-level control over what ends up on the page.
By default, Swagger UI uses `BaseLayout`, which is built into the application. You can specify a different layout to be used by passing the layout's name as the `layout` parameter to Swagger UI. Be sure to provide your custom layout as a component to Swagger UI.
<br>
For example, if you wanted to create a custom layout that only displayed operations, you could define an `OperationsLayout`:
```js
import React from "react"
// Create the layout component
class OperationsLayout extends React.Component {
render() {
const {
getComponent
} = this.props
const Operations = getComponent("operations", true)
return (
<div>
<Operations />
</div>
)
}
}
// Create the plugin that provides our layout component
const OperationsLayoutPlugin = () => {
return {
components: {
OperationsLayout: OperationsLayout
}
}
}
// Provide the plugin to Swagger-UI, and select OperationsLayout
// as the layout for Swagger-UI
SwaggerUI({
url: "https://petstore.swagger.io/v2/swagger.json",
plugins: [ OperationsLayoutPlugin ],
layout: "OperationsLayout"
})
```
### Augmenting the default layout
If you'd like to build around the `BaseLayout` instead of replacing it, you can pull the `BaseLayout` into your custom layout and use it:
```js
import React from "react"
// Create the layout component
class AugmentingLayout extends React.Component {
render() {
const {
getComponent
} = this.props
const BaseLayout = getComponent("BaseLayout", true)
return (
<div>
<div className="myCustomHeader">
<h1>I have a custom header above Swagger-UI!</h1>
</div>
<BaseLayout />
</div>
)
}
}
// Create the plugin that provides our layout component
const AugmentingLayoutPlugin = () => {
return {
components: {
AugmentingLayout: AugmentingLayout
}
}
}
// Provide the plugin to Swagger-UI, and select AugmentingLayout
// as the layout for Swagger-UI
SwaggerUI({
url: "https://petstore.swagger.io/v2/swagger.json",
plugins: [ AugmentingLayoutPlugin ],
layout: "AugmentingLayout"
})
```
# Plugin system overview
### Prior art
Swagger UI leans heavily on concepts and patterns found in React and Redux.
If you aren't already familiar, here's some suggested reading:
- [React: Quick Start (reactjs.org)](https://reactjs.org/docs/hello-world.html)
- [Redux README (redux.js.org)](http://redux.js.org/)
In the following documentation, we won't take the time to define the fundamentals covered in the resources above.
> **Note**: Some of the examples in this section contain JSX, which is a syntax extension to JavaScript that is useful for writing React components.
>
> If you don't want to set up a build pipeline capable of translating JSX to JavaScript, take a look at [React without JSX (reactjs.org)](https://reactjs.org/docs/react-without-jsx.html). You can use our `system.React` reference to leverage React without needing to pull a copy into your project.
### The System
The _system_ is the heart of the Swagger UI application. At runtime, it's a JavaScript object that holds many things:
- React components
- Bound Redux actions and reducers
- Bound Reselect state selectors
- System-wide collection of available components
- Built-in helpers like `getComponent`, `makeMappedContainer`, and `getStore`
- References to the React and Immutable.js libraries (`system.React`, `system.Im`)
- User-defined helper functions
The system is built up when Swagger UI is called by iterating through ("compiling") each plugin that Swagger UI has been given, through the `presets` and `plugins` configuration options.
### Presets
Presets are arrays of plugins, which are provided to Swagger UI through the `presets` configuration option. All plugins within presets are compiled before any plugins provided via the `plugins` configuration option. Consider the following example:
```javascript
const MyPreset = [FirstPlugin, SecondPlugin, ThirdPlugin]
SwaggerUI({
presets: [
MyPreset
]
})
```
By default, Swagger UI includes the internal `ApisPreset`, which contains a set of plugins that provide baseline functionality for Swagger UI. If you specify your own `presets` option, you need to add the ApisPreset manually, like so:
```javascript
SwaggerUI({
presets: [
SwaggerUI.presets.apis,
MyAmazingCustomPreset
]
})
```
The need to provide the `apis` preset when adding other presets is an artifact of Swagger UI's original design, and will likely be removed in the next major version.
### getComponent
`getComponent` is a helper function injected into every container component, which is used to get references to components provided by the plugin system.
All components should be loaded through `getComponent`, since it allows other plugins to modify the component. It is preferred over a conventional `import` statement.
Container components in Swagger UI can be loaded by passing `true` as the second argument to `getComponent`, like so:
```javascript
getComponent("ContainerComponentName", true)
```
This will map the current system as props to the component.
# Plug points
Swagger UI exposes most of its internal logic through the plugin system.
Often, it is beneficial to override the core internals to achieve custom behavior.
### Note: Semantic Versioning
Swagger UI's internal APIs are _not_ part of our public contract, which means that they can change without the major version changing.
If your custom plugins wrap, extend, override, or consume any internal core APIs, we recommend specifying a specific minor version of Swagger UI to use in your application, because they will _not_ change between patch versions.
If you're installing Swagger UI via NPM, for example, you can do this by using a tilde:
```js
{
"dependencies": {
"swagger-ui": "~3.11.0"
}
}
```
### `fn.opsFilter`
When using the `filter` option, tag names will be filtered by the user-provided value. If you'd like to customize this behavior, you can override the default `opsFilter` function.
For example, you can implement a multiple-phrase filter:
```js
const MultiplePhraseFilterPlugin = function() {
return {
fn: {
opsFilter: (taggedOps, phrase) => {
const phrases = phrase.split(", ")
return taggedOps.filter((val, key) => {
return phrases.some(item => key.indexOf(item) > -1)
})
}
}
}
}
```
This diff is collapsed.
# Helpful scripts
Any of the scripts below can be run by typing `npm run <script name>` in the project's root directory.
### Developing
Script name | Description
--- | ---
`dev` | Spawn a hot-reloading dev server on port 3200.
`deps-check` | Generate a size and licensing report on Swagger UI's dependencies.
`lint` | Report ESLint style errors and warnings.
`lint-errors` | Report ESLint style errors, without warnings.
`lint-fix` | Attempt to fix style errors automatically.
`watch` | Rebuild the core files in `/dist` when the source code changes. Useful for `npm link` with Swagger Editor.
### Building
Script name | Description
--- | ---
`build` | Build a new set of JS and CSS assets, and output them to `/dist`.
`build-bundle` | Build `swagger-ui-bundle.js` only.
`build-core` | Build `swagger-ui.(js\|css)` only.
`build-standalone` | Build `swagger-ui-standalone-preset.js` only.
`build-stylesheets` | Build `swagger-ui.css` only.
### Testing
Script name | Description
--- | ---
`test` | Run unit tests in Node and run ESLint in errors-only mode.
`just-test` | Run unit tests in the browser with Karma.
`just-test-in-node` | Run unit tests in Node.
`e2e` | Run end-to-end tests (requires JDK and Selenium).
# Setting up a dev environment
Swagger UI includes a development server that provides hot module reloading and unminified stack traces, for easier development.
### Prerequisites
- Node.js `6.0.0` or greater
- npm `3.0.0` or greater
- git, any version
### Steps
1. `git clone https://github.com/swagger-api/swagger-ui.git`
2. `cd swagger-ui`
3. `npm install`
4. `npm run dev`
5. Wait a bit
6. Open http://localhost:3200/
## Bonus points
- Swagger UI includes an ESLint rule definition. If you use a graphical editor, consider installing an ESLint plugin, which will point out syntax and style errors for you as you code.
- The linter runs as part of the PR test sequence, so don't think you can get away with not paying attention to it!
This diff is collapsed.
# CORS
CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + JavaScript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.
You can read about CORS here: http://www.w3.org/TR/cors.
There are two cases where no action is needed for CORS support:
1. Swagger UI is hosted on the same server as the application itself (same host *and* port).
2. The application is located behind a proxy that enables the required CORS headers. This may already be covered within your organization.
Otherwise, CORS support needs to be enabled for:
1. Your Swagger docs. For Swagger 2.0 it's the `swagger.json`/`swagger.yaml` and any externally `$ref`ed docs.
2. For the `Try it now` button to work, CORS needs to be enabled on your API endpoints as well.
### Testing CORS Support
You can verify CORS support with one of three techniques:
- Curl your API and inspect the headers. For instance:
```bash
$ curl -I "https://petstore.swagger.io/v2/swagger.json"
HTTP/1.1 200 OK
Date: Sat, 31 Jan 2015 23:05:44 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
Content-Type: application/json
Content-Length: 0
```
This tells us that the petstore resource listing supports OPTIONS, and the following headers: `Content-Type`, `api_key`, `Authorization`.
- Try Swagger UI from your file system and look at the debug console. If CORS is not enabled, you'll see something like this:
```
XMLHttpRequest cannot load http://sad.server.com/v2/api-docs. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
```
Swagger UI cannot easily show this error state.
- Use the http://www.test-cors.org website to verify CORS support. Keep in mind this will show a successful result even if `Access-Control-Allow-Headers` is not available, which is still required for Swagger UI to function properly.
### Enabling CORS
The method of enabling CORS depends on the server and/or framework you use to host your application. http://enable-cors.org provides information on how to enable CORS in some common web servers.
Other servers/frameworks may provide you information on how to enable it specifically in their use case.
### CORS and Header Parameters
Swagger UI lets you easily send headers as parameters to requests. The name of these headers *MUST* be supported in your CORS configuration as well. From our example above:
```
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
```
Only headers with these names will be allowed to be sent by Swagger UI.
# `deepLinking` parameter
Swagger UI allows you to deeply link into tags and operations within a spec. When Swagger UI is provided a URL fragment at runtime, it will automatically expand and scroll to a specified tag or operation.
## Usage
👉🏼 Add `deepLinking: true` to your Swagger UI configuration to enable this functionality. This is demonstrated in [`dist/index.html`](https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html).
When you expand a tag or operation, Swagger UI will automatically update its URL fragment with a deep link to the item.
Conversely, when you collapse a tag or operation, Swagger UI will clear the URL fragment.
You can also right-click a tag name or operation path in order to copy a link to that tag or operation.
#### Fragment format
The fragment is formatted in one of two ways:
- `#/{tagName}`, to trigger the focus of a specific tag
- `#/{tagName}/{operationId}`, to trigger the focus of a specific operation within a tag
`operationId` is the explicit operationId provided in the spec, if one exists.
Otherwise, Swagger UI generates an implicit operationId by combining the operation's path and method, and escaping non-alphanumeric characters.
## FAQ
> I'm using Swagger UI in an application that needs control of the URL fragment. How do I disable deep-linking?
This functionality is disabled by default, but you can pass `deepLinking: false` into Swagger UI as a configuration item to be sure.
> Can I link to multiple tags or operations?
No, this is not supported.
> Can I collapse everything except the operation or tag I'm linking to?
Sure - use `docExpansion: none` to collapse all tags and operations. Your deep link will take precedence over the setting, so only the tag or operation you've specified will be expanded.
# Installation
## Distribution channels
### NPM Registry
We publish two modules to npm: **`swagger-ui`** and **`swagger-ui-dist`**.
**`swagger-ui`** is meant for consumption by JavaScript web projects that include module bundlers, such as Webpack, Browserify, and Rollup. Its main file exports Swagger UI's main function, and the module also includes a namespaced stylesheet at `swagger-ui/dist/swagger-ui.css`. Here's an example:
```javascript
import SwaggerUI from 'swagger-ui'
// or use require, if you prefer
const SwaggerUI = require('swagger-ui')
SwaggerUI({
dom_id: '#myDomId'
})
```
In contrast, **`swagger-ui-dist`** is meant for server-side projects that need assets to serve to clients. The module, when imported, includes an `absolutePath` helper function that returns the absolute filesystem path to where the `swagger-ui-dist` module is installed.
_Note: we suggest using `swagger-ui` when your tooling makes it possible, as `swagger-ui-dist`
will result in more code going across the wire._
The module's contents mirrors the `dist` folder you see in the Git repository. The most useful file is `swagger-ui-bundle.js`, which is a build of Swagger UI that includes all the code it needs to run in one file. The folder also has an `index.html` asset, to make it easy to serve Swagger UI like so:
```javascript
const express = require('express')
const pathToSwaggerUi = require('swagger-ui-dist').absolutePath()
const app = express()
app.use(express.static(pathToSwaggerUi))
app.listen(3000)
```
The module also exports `SwaggerUIBundle` and `SwaggerUIStandalonePreset`, so
if you're in a JavaScript project that can't handle a traditional npm module,
you could do something like this:
```js
var SwaggerUIBundle = require('swagger-ui-dist').SwaggerUIBundle
const ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "StandaloneLayout"
})
```
`SwaggerUIBundle` is equivalent to `SwaggerUI`.
### Docker
You can pull a pre-built docker image of the swagger-ui directly from Docker Hub:
```
docker pull swaggerapi/swagger-ui
docker run -p 80:8080 swaggerapi/swagger-ui
```
Will start nginx with Swagger UI on port 80.
Or you can provide your own swagger.json on your host
```
docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```
The base URL of the web application can be changed by specifying the `BASE_URL` environment variable:
```
docker run -p 80:8080 -e BASE_URL=/swagger -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```
This will serve Swagger UI at `/swagger` instead of `/`.
For more information on controlling Swagger UI through the Docker image, see the Docker section of the [Configuration documentation](configuration.md#docker).
### unpkg
You can embed Swagger UI's code directly in your HTML by using unpkg's interface:
```html
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
<!-- `SwaggerUIBundle` is now available on the page -->
```
See [unpkg's main page](https://unpkg.com/) for more information on how to use unpkg.
# Limitations
### Forbidden header names
Some header names cannot be controlled by web applications, due to security
features built into web browsers.
Forbidden headers include:
> - Accept-Charset
> - Accept-Encoding
> - Access-Control-Request-Headers
> - Access-Control-Request-Method
> - Connection
> - Content-Length
> - Cookie
> - Cookie2
> - Date
> - DNT
> - Expect
> - Host
> - Keep-Alive
> - Origin
> - Proxy-*
> - Sec-*
> - Referer
> - TE
> - Trailer
> - Transfer-Encoding
> - Upgrade
> - Via
>
> _[Forbidden header names (developer.mozilla.org)](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name)_
The biggest impact of this is that OpenAPI 3.0 Cookie parameters cannot be
controlled when running Swagger UI in a browser.
For more context, see [#3956](https://github.com/swagger-api/swagger-ui/issues/3956).
# OAuth 2.0 configuration
You can configure OAuth 2.0 authorization by calling the `initOAuth` method.
Property name | Docker variable | Description
--- | --- | ------
clientId | `OAUTH_CLIENT_ID` | Default clientId. MUST be a string
clientSecret | `OAUTH_CLIENT_SECRET` | **🚨 Never use this parameter in your production environment. It exposes cruicial security information. This feature is intended for dev/test environments only. 🚨** <br>Default clientSecret. MUST be a string
realm | `OAUTH_REALM` |realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl`. MUST be a string
appName | `OAUTH_APP_NAME` |application name, displayed in authorization popup. MUST be a string
scopeSeparator | `OAUTH_SCOPE_SEPARATOR` |scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
additionalQueryStringParams | `OAUTH_ADDITIONAL_PARAMS` |Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
useBasicAuthenticationWithAccessCodeGrant | _Unavailable_ |Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encode(client_id + client_secret)`). The default is `false`
usePkceWithAuthorizationCodeGrant | `OAUTH_USE_PKCE` | Only applies to `authorizatonCode` flows. [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636) brings enhanced security for OAuth public clients. The default is `false`
```javascript
const ui = SwaggerUI({...})
// Method can be called in any place after calling constructor SwaggerUIBundle
ui.initOAuth({
clientId: "your-client-id",
clientSecret: "your-client-secret-if-required",
realm: "your-realms",
appName: "your-app-name",
scopeSeparator: " ",
additionalQueryStringParams: {test: "hello"},
usePkceWithAuthorizationCodeGrant: true
})
```
# Detecting your Swagger UI version
At times, you're going to need to know which version of Swagger UI you use.
The first step would be to detect which major version you currently use, as the method of detecting the version has changed. If your Swagger UI has been heavily modified and you cannot detect from the look and feel which major version you use, you'd have to try both methods to get the exact version.
To help you visually detect which version you're using, we've included supporting images.
# Swagger UI 3.x
![Swagger UI 3](/docs/images/swagger-ui3.png)
Some distinct identifiers to Swagger UI 3.x:
- The API version appears as a badge next to its title.
- If there are schemes or authorizations, they'd appear in a bar above the operations.
- Try it out functionality is not enabled by default.
- All the response codes in the operations appear at after the parameters.
- There's a models section after the operations.
If you've determined this is the version you have, to find the exact version:
- Open your browser's web console (changes between browsers)
- Type `JSON.stringify(versions)` in the console and execute the call.
- The result should look similar to `swaggerUi : Object { version: "3.1.6", gitRevision: "g786cd47", gitDirty: true, … }`.
- The version taken from that example would be `3.1.6`.
Note: This functionality was added in 3.0.8. If you're unable to execute it, you're likely to use an older version, and in that case the first step would be to upgrade.
# Swagger UI 2.x and under
![Swagger UI 2](/docs/images/swagger-ui2.png)
Some distinct identifiers to Swagger UI 3.x:
- The API version appears at the bottom of the page.
- Schemes are not rendered.
- Authorization, if rendered, will appear next to the navigation bar.
- Try it out functionality is enabled by default.
- The successful response code would appear above the parameters, the rest below them.
- There's no models section after the operations.
If you've determined this is the version you have, to find the exact version:
- Navigate to the sources of the UI. Either on your disk or via the view page source functionality in your browser.
- Find an open the `swagger-ui.js`
- At the top of the page, there would be a comment containing the exact version of Swagger UI. This example shows version `2.2.9`:
```
/**
* swagger-ui - Swagger UI is a dependency-free collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API
* @version v2.2.9
* @link http://swagger.io
* @license Apache-2.0
*/
```
# `swagger-ui-react`
[![NPM version](https://badge.fury.io/js/swagger-ui-react.svg)](http://badge.fury.io/js/swagger-ui-react)
`swagger-ui-react` is a flavor of Swagger UI suitable for use in React applications.
It has a few differences from the main version of Swagger UI:
* Declares `react` and `react-dom` as peerDependencies instead of production dependencies
* Exports a component instead of a constructor function
Versions of this module mirror the version of Swagger UI included in the distribution.
## Quick start
Install `swagger-ui-react`:
```
$ npm i --save swagger-ui-react
```
Use it in your React application:
```js
import SwaggerUI from "swagger-ui-react"
import "swagger-ui-react/swagger-ui.css"
export default App = () => <SwaggerUI url="https://petstore.swagger.io/v2/swagger.json" />
```
## Props
These props map to [Swagger UI configuration options](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md) of the same name.
#### `spec`: PropTypes.object
An OpenAPI document respresented as a JavaScript object, JSON string, or YAML string for Swagger UI to display.
⚠️ Don't use this in conjunction with `url` - unpredictable behavior may occur.
#### `url`: PropTypes.string
Remote URL to an OpenAPI document that Swagger UI will fetch, parse, and display.
⚠️ Don't use this in conjunction with `spec` - unpredictable behavior may occur.
#### `onComplete`: PropTypes.func
> `(system) => void`
A callback function that is triggered when Swagger-UI finishes rendering an OpenAPI document.
Swagger UI's `system` object is passed as an argument.
#### `requestInterceptor`: PropTypes.func
> `req => req` or `req => Promise<req>`.
A function that accepts a request object, and returns either a request object
or a Promise that resolves to a request object.
#### `responseInterceptor`: PropTypes.func
> `res => res` or `res => Promise<res>`.
A function that accepts a response object, and returns either a response object
or a Promise that resolves to a response object.
#### `docExpansion`: PropTypes.oneOf(['list', 'full', 'none'])
Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). The default value is 'list'.
⚠️ This prop is currently only applied once, on mount. Changes to this prop's value will not be propagated to the underlying Swagger UI instance. A future version of this module will remove this limitation, and the change will not be considered a breaking change.
## Limitations
* Not all configuration bindings are available.
* Some props are only applied on mount, and cannot be updated reliably.
* OAuth redirection handling is not supported.
* Topbar/Standalone mode is not supported.
* Custom plugins are not supported.
We intend to address these limitations based on user demand, so please open an issue or pull request if you have a specific request.
## Notes
* The `package.json` in the same folder as this README is _not_ the manifest that should be used for releases - another manifest is generated at build-time and can be found in `./dist/`.
---
For anything else, check the [Swagger-UI](https://github.com/swagger-api/swagger-ui) repository.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment