提交 5f99a08b authored 作者: vipcxj's avatar vipcxj

补完文档, 文档加载自动化

上级 cd77cb12
......@@ -16375,9 +16375,9 @@
"integrity": "sha512-H0nT+KHADICdFgflNZ0A6+EBcExajxY8XM100tKOT5Oidhdo/0bAi26ffBhraEls4FIi8Lm4917tMq8LIWN7Qg=="
},
"react-async-wrapper": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/react-async-wrapper/-/react-async-wrapper-0.1.0.tgz",
"integrity": "sha512-Bd/Azo0X1Qd+KCUUAOi9+H2y7YqX9XV3gJkd5H1uBgA7ZSr/9HIdIj/1VnIuwojLgnOPDHt6aqEBs7mfgIJFHw==",
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/react-async-wrapper/-/react-async-wrapper-0.1.2.tgz",
"integrity": "sha512-rUsqvpgVWLZaPnbai6oJu5sQcgpr1lgCCarAuFTzPd6wTlUecotU96+dYCdfVDpibTXwxsnzEAvn3fb2k1UpXA==",
"requires": {
"is-promise": "2.1.0"
}
......@@ -16647,7 +16647,7 @@
"requires": {
"hoist-non-react-statics": "2.5.0",
"invariant": "2.2.4",
"react-async-wrapper": "0.1.0"
"react-async-wrapper": "0.1.2"
}
},
"react-router-dom": {
......
......@@ -28,7 +28,7 @@
"moment": "^2.18.1",
"prop-types": "^15.6.1",
"react": "^16.2.0",
"react-async-wrapper": "^0.1.0",
"react-async-wrapper": "^0.1.2",
"react-dom": "^16.2.0",
"react-json-view": "^1.11.4",
"react-markdown": "^3.3.0",
......
......@@ -10,7 +10,7 @@ const App = ({ children }) => {
};
App.propTypes = {
children: PropTypes.element.isRequired,
children: PropTypes.oneOfType(PropTypes.element, PropTypes.arrayOf(PropTypes.element)).isRequired,
};
export default connect()(App);
/* eslint-disable react/no-danger */
import React from 'react';
import PropTypes from 'prop-types';
class MarkDown extends React.Component {
render() {
return (
<div dangerouslySetInnerHTML={{
__html: this.props.markdown,
}}
/>
);
}
}
MarkDown.propTypes = {
markdown: PropTypes.string,
};
MarkDown.defaultProps = {
markdown: '',
};
export default MarkDown;
......@@ -20,34 +20,50 @@ POST
```
{
type: string, //登录方式
data: string, //登录方式对应的登录数据
tokenInfo: { //令牌信息
productId: string, //产品ID
deviceId: string //设备ID
type: string,
data: string,
tokenInfo: {
productId: string,
deviceId: string
},
authRequest: { //验证请求,可选
type: string, //验证方式
parameters: Map //验证参数
authRequest: {
type: string,
parameters: Map
}
}
```
> - *type*: 登录方式, 可选值为`userName`,`email`,分别表示用户名登录和邮箱登录。
> - *data*: 登录方式对应的登录数据, `userName`对应的登录数据即为用户名,`email`对应的登录数据即为邮箱地址
> - *tokenInfo*: 登录必备的信息,为权限验证所需。
> - *productId*: 产品ID,表示要登录的产品。
> - *deviceId*: 设备ID,一条可以用来唯一标识客户端的字符串,生成规则不限,只要保证唯一性和不变性即可。
> - *authRequest*: 验证请求,为了简化接口,登录的同时也可以一起进行验证。
- *type* - **string** 登录方式, 可选值为`userName``email`,分别表示用户名登录和邮箱登录。
- *data* - **string** 登录方式对应的登录数据, `userName`对应的登录数据即为用户名,`email`对应的登录数据即为邮箱地址
- *tokenInfo* - **object** 登录必备的信息,为权限验证所需。
- *productId* - **string** 产品ID,表示要登录的产品。
- *deviceId* - **string** 设备ID,一条可以用来唯一标识客户端的字符串,生成规则不限,只要保证唯一性和不变性即可。
- *authRequest* - **object** 验证请求,为了简化接口,登录的同时也可以一起进行验证。
前提是事先知道对应用户需要用哪种方式进行验证。因为用户所需的验证方式是后台可配置,
不是一成不变的,所以不建议登录验证同时进行的api调用方式。
> - *type*: 验证方式。可选值为`password`,表示密码登录
> - *parameters*: 验证参数。`password`对应的验证参数为
- *type* - **string** 验证方式。可选值为`password`,表示密码登录
- *parameters* - **object** 验证参数。`password`对应的验证参数为
`{ cipher: string }`,表示用户密码。
- **Content-Type**:
application/json
- *tokenId* - **string** 未加密的原始token字符串,该token在服务器存在内存中,
若超过30分钟没有使用该token,该token将失效。
- *authResponse* - **object** 验证响应,请求体中包含`authRequest`字段时,响应体中才会有此字段。
- *type* - **string** 验证类型,与请求体中`authRequest.type`值相同。
- *status* - **string** 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
`authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。
以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。
- *data* - **any** 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements* - **object** 剩余的验证需求。
- *requirements* - **[object]** 若干个验证需求,逻辑关系为和。
若为空数组,表示所有验证需求均已满足,即全部验证成功。
- *authTypes*: - **[string]** 若干个验证方式,逻辑关系为或,
只要其中一个验证方式验证成功,该验证条件即满足。
- *remainedAuthRequirements* - **object**`authResponse.remainedAuthRequirements`
不同之处在于请求体中不需要包含`authRequest`,该字段也存在。
```
{
tokenId: string,
......@@ -68,21 +84,7 @@ application/json
}
}
```
> - *tokenId*: 未加密的原始token字符串,该token在服务器存在内存中,
若超过30分钟没有使用该token,该token将失效。
> - *authResponse*: 验证响应,请求体中包含`authRequest`字段时,响应体中才会有此字段。
- *type*: 验证类型,与请求体中`authRequest.type`值相同。
- *status*: 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
`authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。
以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。
- *data*: 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements*: 剩余的验证需求。
- *requirements*: 若干个验证需求,逻辑关系为和。
若为空数组,表示所有验证需求均已满足,即全部验证成功。
- *authTypes*: 若干个验证方式,逻辑关系为或,
只要其中一个验证方式验证成功,该验证条件即满足。
> - *remainedAuthRequirements*: 同`authResponse.remainedAuthRequirements`。
不同之处在于请求体中不需要包含`authRequest`,该字段也存在。
- **note**:
获取后的token,不能直接使用,需要使用公钥进行非对称加密。加密方式如下:
......@@ -121,10 +123,10 @@ application/json
}
}
```
- *tkId*: 加密后的令牌
- *request*: 验证请求
- *type*: 验证方式。可选值为`password`,表示密码登录
- *parameters*: 验证参数。`password`对应的验证参数为
- *tkId* - **string** 加密后的令牌
- *request* -**object** 验证请求
- *type* - **string** 验证方式。可选值为`password`,表示密码登录
- *parameters* - **object** 验证参数。`password`对应的验证参数为
`{ cipher: string }`,表示用户密码。
- **Content-Type**:
......@@ -142,15 +144,15 @@ application/json
}
}
```
- *type*: 验证类型,与请求体中`authRequest.type`值相同。
- *status*: 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
- *type* - **string** 验证类型,与请求体中`authRequest.type`值相同。
- *status* - **string** 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
`authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。
以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。
- *data*: 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements*: 剩余的验证需求。
- *requirements*: 若干个验证需求,逻辑关系为和。
- *data* - **any** 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements* - **[object]** 剩余的验证需求。
- *requirements* - **[object]** 若干个验证需求,逻辑关系为和。
若为空数组,表示所有验证需求均已满足,即全部验证成功。
- *authTypes*: 若干个验证方式,逻辑关系为或,
- *authTypes* - **[string]** 若干个验证方式,逻辑关系为或,
只要其中一个验证方式验证成功,该验证条件即满足。
## 登出
......@@ -163,8 +165,9 @@ POST
- **Accept**:
application/json
`empty` (只包含前置说明中提到的token,即`{ token: string }`, 之后不再重复说明。)
- `empty` - 只包含前置说明中提到的token,即`{ token: string }`, 之后不再重复说明。
- **Content-Type**:
application/json
`null` (并不是真正的空,仅仅是如前置说明中提到那样,`data`字段为`null`, 之后不再重复说明。)
`null` - 并不是真正的空,仅仅是如前置说明中提到那样,`data`字段为`null`, 之后不再重复说明。
.markdown {
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
width: 100%;
color:#444;
font-family:Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif;
font-size:12px;
line-height:1.5em;
padding:1em;
background:#fefefe;
a{ color: #0645ad; text-decoration:none;}
a:visited{ color: #0b0080; }
a:hover{ color: #06e; }
a:active{ color:#faa700; }
a:focus{ outline: thin dotted; }
a:hover, a:active{ outline: 0; }
::-moz-selection{background:rgba(255,255,0,0.3);color:#000}
::selection{background:rgba(255,255,0,0.3);color:#000}
a::-moz-selection{background:rgba(255,255,0,0.3);color:#0645ad}
a::selection{background:rgba(255,255,0,0.3);color:#0645ad}
p{
margin:1em 0;
}
img{
max-width:100%;
}
h1,h2,h3,h4,h5,h6{
font-weight:normal;
color:#111;
line-height:1em;
}
h4,h5,h6{ font-weight: bold; }
h1{ font-size:2.5em; }
h2{ font-size:2em; }
h3{ font-size:1.5em; }
h4{ font-size:1.2em; }
h5{ font-size:1em; }
h6{ font-size:0.9em; }
blockquote{
color:#666666;
margin:0;
padding-left: 3em;
border-left: 0.5em #EEE solid;
}
hr { display: block; height: 2px; border: 0; border-top: 1px solid #aaa;border-bottom: 1px solid #eee; margin: 1em 0; padding: 0; }
pre, code, kbd, samp { color: #000; font-family: monospace, monospace; _font-family: 'courier new', monospace; font-size: 0.98em; }
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
b, strong { font-weight: bold; }
dfn { font-style: italic; }
ins { background: #ff9; color: #000; text-decoration: none; }
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
ul, ol { margin: 1em 0; padding: 0 0 0 2em; }
li p:last-child { margin:0 }
dd { margin: 0 0 0 2em; }
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
}
th { border-bottom: 1px solid black; }
td { vertical-align: top; }
@media only screen and (min-width: 480px) {
font-size:14px;
}
@media only screen and (min-width: 768px) {
font-size:16px;
}
@media print {
* { background: transparent !important; color: black !important; filter:none !important; -ms-filter: none !important; }
font-size:12pt; max-width:100%;
a, a:visited { text-decoration: underline; }
hr { height: 1px; border:0; border-bottom:1px solid black; }
a[href]:after { content: " (" attr(href) ")"; }
abbr[title]:after { content: " (" attr(title) ")"; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
pre, blockquote { border: 1px solid #999; padding-right: 1em; page-break-inside: avoid; }
tr, img { page-break-inside: avoid; }
img { max-width: 100% !important; }
@page :left { margin: 15mm 20mm 15mm 10mm; }
@page :right { margin: 15mm 10mm 15mm 20mm; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3 { page-break-after: avoid; }
}
}
import React from 'react';
import { AsyncComponent } from 'react-async-wrapper';
import ReactMarkdown from 'react-markdown';
export default (match) => {
const linkBase = `${match.url}/dynamic-interface`;
const pathBase = `${match.path}/dynamic-interface`;
return [
['addFamily', '新增两清'],
['updateFamily', '修改两清'],
['removeFamily', '删除两清'],
].map(([name, showName]) => ({
name,
showName,
link: `${linkBase}/${name}`,
path: `${pathBase}/${name}`,
component: props => (
<AsyncComponent asyncComponent={
() => import(`./${name}.md`).then(md => p => (
<div style={{
padding: '1em',
background: '#fafafa',
}}
>
<ReactMarkdown {...p} {...props} className="markdown-body" source={md} />
</div>
))
}
/>
),
}));
};
......@@ -7,6 +7,29 @@
不过一般情况下,进入生产环境配置好的接口不会轻易改动,
除非有bug。
## 验证前置条件
调用动态接口可能需要满足某些状态条件,使用这个api来事先进行检测。
改api如果检测满足前置条件,则没有返回值,如果不满足条件`errorCode`则不为0,
`errorCode`含义依赖于具体配置,另外`message`字段也可能包含错误信息,
`data`字段可能包含特定的错误数据。
- **URL**
/api/interface/user/{name}/invoke/validateState
- *name* - 动态接口的名称,可以认为是动态接口的唯一标识符。
- **Method**:
GET
- **query parameter**
-
- **Content-Type**:
application/json
- `null`
## 调用动态接口
执行动态接口,调用此接口,服务端仍然会进行前置条件验证。
- **URL**:
/api/interface/user/{name}/invoke
- *name* - 动态接口的名称,可以认为是动态接口的唯一标识符。
......
......@@ -9,9 +9,7 @@ import mdIndex from './index.md';
import mdAuth from './auth.md';
import mdDomain from './domain.md';
import mdDyInt from './dynamic-interface/index.md';
import mdDyAddFamily from './dynamic-interface/addFamily.md';
import mdDyUpdateFamily from './dynamic-interface/updateFamily.md';
import mdDyRemoveFamily from './dynamic-interface/removeFamily.md';
import createPages from './dynamic-interface';
const md = mdString => props => (
<div style={{
......@@ -26,6 +24,7 @@ const md = mdString => props => (
class DocMainPage extends React.Component {
render() {
const { match } = this.props;
const pages = createPages(match);
return (
<div className={styles.main} ref={(node) => { this.container = node && node.parentElement; }}>
<Affix target={() => this.container}>
......@@ -42,9 +41,11 @@ class DocMainPage extends React.Component {
<li>
<Link to={`${match.url}/dynamic-interface`}>动态接口</Link>
<ul>
<li><Link to={`${match.url}/dynamic-interface/addFamily`}>新增两清</Link></li>
<li><Link to={`${match.url}/dynamic-interface/updateFamily`}>更新两清</Link></li>
<li><Link to={`${match.url}/dynamic-interface/removeFamily`}>删除两清</Link></li>
{
pages.map(page => (
<li key={page.name}><Link to={page.link}>{ page.showName }</Link></li>
))
}
</ul>
</li>
</ul>
......@@ -55,15 +56,11 @@ class DocMainPage extends React.Component {
<Route path={`${match.path}/auth`} component={md(mdAuth)} />
<Route path={`${match.path}/domain`} component={md(mdDomain)} />
<Route path={`${match.path}/dynamic-interface`} exact component={md(mdDyInt)} />
<Route path={`${match.path}/dynamic-interface/addFamily`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/updateFamily`} component={md(mdDyUpdateFamily)} />
<Route path={`${match.path}/dynamic-interface/removeFamily`} component={md(mdDyRemoveFamily)} />
<Route path={`${match.path}/dynamic-interface/addHouse`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/updateHouse`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/removeHouse`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/addPeople`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/updatePeople`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/removePeople`} component={md(mdDyAddFamily)} />
{
pages.map(page => (
<Route key={page.name} path={page.path} component={page.component} />
))
}
</Switch>
</div>
</div>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论