コンテンツにスキップ

プラグイン

プラグインはオブジェクトを返す関数です。より具体的には、そのオブジェクトには Swagger UI の機能を拡張および変更する関数とコンポーネントが含まれる場合があります。

注意: セマンティックバージョニング

Swagger UI の内部 API は、当社の公開契約の一部では**ありません**。つまり、メジャーバージョン変更なしに変更される可能性があります。

カスタムプラグインが内部コア API をラップ、拡張、オーバーライド、または使用する場合、アプリケーションで使用する Swagger UI の特定のマイナーバージョンを指定することをお勧めします。これは、パッチバージョン間では**変更されない**ためです。

例えば、NPM 経由で Swagger UI をインストールしている場合、チルダを使用することでこれを行うことができます。

1
{
2
"dependencies": {
3
"swagger-ui": "~3.11.0"
4
}
5
}

フォーマット

プラグインの戻り値には、これらのいずれかのキーを含めることができます。stateKey は状態の一部を表す名前です。

1
{
2
statePlugins: {
3
[stateKey]: {
4
actions,
5
reducers,
6
selectors,
7
wrapActions,
8
wrapSelectors
9
}
10
},
11
components: {},
12
wrapComponents: {},
13
rootInjects: {},
14
afterLoad: (system) => {},
15
fn: {},
16
}

システムはプラグインに提供されます

normal 状態の名前空間の下に doStuff アクションを公開するプラグイン NormalPlugin があると仮定しましょう。

1
const ExtendingPlugin = function(system) {
2
return {
3
statePlugins: {
4
extending: {
5
actions: {
6
doExtendedThings: function(...args) {
7
// you can do other things in here if you want
8
return system.normalActions.doStuff(...args)
9
}
10
}
11
}
12
}
13
}
14
}

ご覧のとおり、各プラグインには構築中の system への参照が渡されます。NormalPluginExtendingPlugin の前にコンパイルされる限り、これは問題なく機能します。

プラグインシステムには依存関係管理が組み込まれていないため、他のプラグインに依存するプラグインを作成する場合、依存されるプラグインが**後で**ロードされるようにすることはあなたの責任です。

インターフェース

アクション

1
const MyActionPlugin = () => {
2
return {
3
statePlugins: {
4
example: {
5
actions: {
6
updateFavoriteColor: (str) => {
7
return {
8
type: "EXAMPLE_SET_FAV_COLOR",
9
payload: str
10
}
11
}
12
}
13
}
14
}
15
}
16
}

アクションが定義されると、システム参照を取得できる場所であればどこでも使用できます。

1
// elsewhere
2
system.exampleActions.updateFavoriteColor("blue")

アクションインターフェースは、Swagger UI システムの状態の一部に新しい Redux アクションクリエーターを作成できるようにします。

このアクションクリエーター関数は、コンテナーコンポーネントに exampleActions.updateFavoriteColor として公開されます。このアクションクリエーターが呼び出されると、戻り値(Flux Standard Action であるべきです)は、次のセクションで定義する example リデューサーに渡されます。

Redux のアクションの概念の詳細については、Redux Actions ドキュメントを参照してください。

リデューサー

リデューサーは状態(Immutable.js マップ)とアクションを受け取り、新しい状態を返します。

リデューサーは、この場合 EXAMPLE_SET_FAV_COLOR のように、それが処理するアクションタイプ名の下にシステムに提供されなければなりません。

1
const MyReducerPlugin = function(system) {
2
return {
3
statePlugins: {
4
example: {
5
reducers: {
6
"EXAMPLE_SET_FAV_COLOR": (state, action) => {
7
// you're only working with the state under the namespace, in this case "example".
8
// So you can do what you want, without worrying about /other/ namespaces
9
return state.set("favColor", action.payload)
10
}
11
}
12
}
13
}
14
}
15
}

セレクター

セレクターは、名前空間の状態にアクセスして、状態からデータを取得または派生させます。

これらはロジックを一か所に保つ簡単な方法であり、状態データをコンポーネントに直接渡すよりも推奨されます。

1
const MySelectorPlugin = function(system) {
2
return {
3
statePlugins: {
4
example: {
5
selectors: {
6
myFavoriteColor: (state) => state.get("favColor")
7
}
8
}
9
}
10
}
11
}

また、Reselect ライブラリを使用してセレクターをメモ化することもできます。Reselect はセレクター呼び出しを自動的にメモ化するため、頻繁に使用されるセレクターにはこれをお勧めします。

1
import { createSelector } from "reselect"
2
3
const MySelectorPlugin = function(system) {
4
return {
5
statePlugins: {
6
example: {
7
selectors: {
8
// this selector will be memoized after it is run once for a
9
// value of `state`
10
myFavoriteColor: createSelector((state) => state.get("favColor"))
11
}
12
}
13
}
14
}
15
}

セレクターが定義されると、システム参照を取得できる場所であればどこでも使用できます。

1
system.exampleSelectors.myFavoriteColor() // gets `favColor` in state for you

コンポーネント

システムに統合するコンポーネントのマップを提供できます。

提供するコンポーネントのキー名に注意してください。これらの名前を使用して、他の場所でコンポーネントを参照する必要があるためです。

1
class HelloWorldClass extends React.Component {
2
render() {
3
return <h1>Hello World!</h1>
4
}
5
}
6
7
const MyComponentPlugin = function(system) {
8
return {
9
components: {
10
HelloWorldClass: HelloWorldClass
11
// components can just be functions, these are called "stateless components"
12
HelloWorldStateless: () => <h1>Hello World!</h1>,
13
}
14
}
15
}
1
// elsewhere
2
const HelloWorldStateless = system.getComponent("HelloWorldStateless")
3
const HelloWorldClass = system.getComponent("HelloWorldClass")

また、常に null を返すステートレスコンポーネントを作成することで、不要なコンポーネントを「キャンセル」することもできます。

1
const NeverShowInfoPlugin = function(system) {
2
return {
3
components: {
4
info: () => null
5
}
6
}
7
}

システムにコンポーネントが存在しない場合に警告を発生させたくない場合は、config.failSilently を使用できます。

getComponent 引数の順序に注意してください。以下の例では、ブール値 false はコンテナーの存在を指し、3 番目の引数は欠落しているコンポーネントの警告を抑制するために使用される設定オブジェクトです。

1
const thisVariableWillBeNull = getComponent("not_real", false, { failSilently: true })

ラップアクション

ラップアクションを使用すると、システム内のアクションの動作をオーバーライドできます。

これらは (oriAction, system) => (...args) => result のシグネチャを持つ関数ファクトリです。

ラップアクションの最初の引数は、ラップされるアクションである oriAction です。oriAction を呼び出すのはあなたの責任です。呼び出さない場合、元のアクションは実行されません。

このメカニズムは、組み込みの動作を条件付きでオーバーライドしたり、アクションをリッスンしたりするのに役立ちます。

1
// FYI: in an actual Swagger UI, `updateSpec` is already defined in the core code
2
// it's just here for clarity on what's behind the scenes
3
const MySpecPlugin = function(system) {
4
return {
5
statePlugins: {
6
spec: {
7
actions: {
8
updateSpec: (str) => {
9
return {
10
type: "SPEC_UPDATE_SPEC",
11
payload: str
12
}
13
}
14
}
15
}
16
}
17
}
18
}
19
20
// this plugin allows you to watch changes to the spec that is in memory
21
const MyWrapActionPlugin = function(system) {
22
return {
23
statePlugins: {
24
spec: {
25
wrapActions: {
26
updateSpec: (oriAction, system) => (str) => {
27
// here, you can hand the value to some function that exists outside of Swagger UI
28
console.log("Here is my API definition", str)
29
return oriAction(str) // don't forget! otherwise, Swagger UI won't update
30
}
31
}
32
}
33
}
34
}
35
}

ラップセレクター

ラップセレクターを使用すると、システム内のセレクターの動作をオーバーライドできます。

これらは (oriSelector, system) => (state, ...args) => result のシグネチャを持つ関数ファクトリです。

このインターフェースは、コンポーネントに流れるデータを制御するのに役立ちます。コアコードでは、API 定義のバージョンに基づいてセレクターを無効にするためにこれを使用しています。

1
import { createSelector } from 'reselect'
2
3
// FYI: in an actual Swagger UI, the `url` spec selector is already defined
4
// it's just here for clarity on what's behind the scenes
5
const MySpecPlugin = function(system) {
6
return {
7
statePlugins: {
8
spec: {
9
selectors: {
10
url: createSelector(
11
state => state.get("url")
12
)
13
}
14
}
15
}
16
}
17
}
18
19
const MyWrapSelectorsPlugin = function(system) {
20
return {
21
statePlugins: {
22
spec: {
23
wrapSelectors: {
24
url: (oriSelector, system) => (state, ...args) => {
25
console.log('someone asked for the spec url!!! it is', state.get('url'))
26
// you can return other values here...
27
// but let's just enable the default behavior
28
return oriSelector(state, ...args)
29
}
30
}
31
}
32
}
33
}
34
}

ラップコンポーネント

ラップコンポーネントを使用すると、システムに登録されたコンポーネントをオーバーライドできます。

ラップコンポーネントは、(OriginalComponent, system) => props => ReactElement のシグネチャを持つ関数ファクトリです。React コンポーネントクラスを提供したい場合は、(OriginalComponent, system) => ReactClass も機能します。

1
const MyWrapBuiltinComponentPlugin = function(system) {
2
return {
3
wrapComponents: {
4
info: (Original, system) => (props) => {
5
return <div>
6
<h3>Hello world! I am above the Info component.</h3>
7
<Original {...props} />
8
</div>
9
}
10
}
11
}
12
}

以下に、ラップされるコンポーネントのコードサンプルを含む別の例を示します。

1
///// Overriding a component from a plugin
2
3
// Here's our normal, unmodified component.
4
const MyNumberDisplayPlugin = function(system) {
5
return {
6
components: {
7
NumberDisplay: ({ number }) => <span>{number}</span>
8
}
9
}
10
}
11
12
// Here's a component wrapper defined as a function.
13
const MyWrapComponentPlugin = function(system) {
14
return {
15
wrapComponents: {
16
NumberDisplay: (Original, system) => (props) => {
17
if(props.number > 10) {
18
return <div>
19
<h3>Warning! Big number ahead.</h3>
20
<Original {...props} />
21
</div>
22
} else {
23
return <Original {...props} />
24
}
25
}
26
}
27
}
28
}
29
30
// Alternatively, here's the same component wrapper defined as a class.
31
const MyWrapComponentPlugin = function(system) {
32
return {
33
wrapComponents: {
34
NumberDisplay: (Original, system) => class WrappedNumberDisplay extends React.component {
35
render() {
36
if(props.number > 10) {
37
return <div>
38
<h3>Warning! Big number ahead.</h3>
39
<Original {...props} />
40
</div>
41
} else {
42
return <Original {...props} />
43
}
44
}
45
}
46
}
47
}
48
}

rootInjects

rootInjects インターフェースを使用すると、システムのトップレベルに値を注入できます。

このインターフェースはオブジェクトを受け取り、実行時にトップレベルのシステムオブジェクトとマージされます。

1
const MyRootInjectsPlugin = function(system) {
2
return {
3
rootInjects: {
4
myConstant: 123,
5
myMethod: (...params) => console.log(...params)
6
}
7
}
8
}

afterLoad

afterLoad プラグインメソッドを使用すると、プラグインが登録された後にシステムへの参照を取得できます。

このインターフェースは、バインドされたセレクターまたはアクションによって駆動されるメソッドをアタッチするためにコアコードで使用されます。また、プラグインが既に準備ができていることを必要とするロジック(例えば、リモートエンドポイントから初期データをフェッチして、プラグインが作成するアクションに渡すなど)を実行するためにも使用できます。

this にバインドされたプラグインコンテキストは文書化されていませんが、バインドされたアクションをトップレベルメソッドとしてアタッチする方法の例を以下に示します。

1
const MyMethodProvidingPlugin = function() {
2
return {
3
afterLoad(system) {
4
// at this point in time, your actions have been bound into the system
5
// so you can do things with them
6
this.rootInjects = this.rootInjects || {}
7
this.rootInjects.myMethod = system.exampleActions.updateFavoriteColor
8
},
9
statePlugins: {
10
example: {
11
actions: {
12
updateFavoriteColor: (str) => {
13
return {
14
type: "EXAMPLE_SET_FAV_COLOR",
15
payload: str
16
}
17
}
18
}
19
}
20
}
21
}
22
}

fn

fn インターフェースを使用すると、ヘルパー関数をシステムに追加して他の場所で使用できます。

1
import leftPad from "left-pad"
2
3
const MyFnPlugin = function(system) {
4
return {
5
fn: {
6
leftPad: leftPad
7
}
8
}
9
}
© . This site is unofficial and not affiliated with Swagger.