or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

components.mdcore-spec.mdindex.mdmarshmallow.mdplugin-system.mdutils.md

plugin-system.mddocs/

0

# Plugin System

1

2

Extensible plugin architecture for integrating APISpec with web frameworks and schema libraries. Plugins provide lifecycle hooks for processing paths, operations, and components during specification generation.

3

4

## Capabilities

5

6

### BasePlugin Class

7

8

Abstract base class for creating APISpec plugins. Provides helper methods that are called during specification generation to process and transform components.

9

10

```python { .api }

11

class BasePlugin:

12

def init_spec(self, spec: APISpec) -> None:

13

"""

14

Initialize plugin with APISpec object.

15

16

Parameters:

17

- spec: APISpec object this plugin instance is attached to

18

19

Called once when plugin is registered with APISpec instance.

20

Use this to store references and initialize plugin state.

21

"""

22

```

23

24

### Schema Processing

25

26

Process schema components during registration, allowing plugins to transform or enhance schema definitions.

27

28

```python { .api }

29

def schema_helper(

30

self,

31

name: str,

32

definition: dict,

33

**kwargs: Any

34

) -> dict | None:

35

"""

36

Process schema component definition.

37

38

Parameters:

39

- name: Identifier by which schema may be referenced

40

- definition: Schema definition dictionary

41

- **kwargs: Additional keyword arguments sent to APISpec.components.schema()

42

43

Returns:

44

Modified schema definition dictionary or None

45

46

Raises:

47

- PluginMethodNotImplementedError: If method not implemented by plugin

48

"""

49

```

50

51

### Response Processing

52

53

Process response components during registration.

54

55

```python { .api }

56

def response_helper(self, response: dict, **kwargs: Any) -> dict | None:

57

"""

58

Process response component definition.

59

60

Parameters:

61

- response: Response definition dictionary

62

- **kwargs: Additional keyword arguments sent to APISpec.components.response()

63

64

Returns:

65

Modified response definition dictionary or None

66

67

Raises:

68

- PluginMethodNotImplementedError: If method not implemented by plugin

69

"""

70

```

71

72

### Parameter Processing

73

74

Process parameter components during registration.

75

76

```python { .api }

77

def parameter_helper(self, parameter: dict, **kwargs: Any) -> dict | None:

78

"""

79

Process parameter component definition.

80

81

Parameters:

82

- parameter: Parameter definition dictionary

83

- **kwargs: Additional keyword arguments sent to APISpec.components.parameter()

84

85

Returns:

86

Modified parameter definition dictionary or None

87

88

Raises:

89

- PluginMethodNotImplementedError: If method not implemented by plugin

90

"""

91

```

92

93

### Header Processing

94

95

Process header components during registration.

96

97

```python { .api }

98

def header_helper(self, header: dict, **kwargs: Any) -> dict | None:

99

"""

100

Process header component definition.

101

102

Parameters:

103

- header: Header definition dictionary

104

- **kwargs: Additional keyword arguments sent to APISpec.components.header()

105

106

Returns:

107

Modified header definition dictionary or None

108

109

Raises:

110

- PluginMethodNotImplementedError: If method not implemented by plugin

111

"""

112

```

113

114

### Path Processing

115

116

Process path definitions, allowing plugins to extract path information from framework-specific sources.

117

118

```python { .api }

119

def path_helper(

120

self,

121

path: str | None = None,

122

operations: dict | None = None,

123

parameters: list[dict] | None = None,

124

**kwargs: Any

125

) -> str | None:

126

"""

127

Process path definition and extract path string.

128

129

Parameters:

130

- path: Path to the resource

131

- operations: Dictionary mapping HTTP methods to operation objects

132

- parameters: List of parameters for the path

133

- **kwargs: Additional keyword arguments sent to APISpec.path()

134

135

Returns:

136

Path string or None. If string returned, it sets the path value.

137

138

Raises:

139

- PluginMethodNotImplementedError: If method not implemented by plugin

140

141

Note:

142

The last path helper returning a string sets the final path value.

143

Plugin registration order matters for path helpers.

144

"""

145

```

146

147

### Operation Processing

148

149

Process operation definitions within paths, allowing plugins to extract operation information from framework-specific sources.

150

151

```python { .api }

152

def operation_helper(

153

self,

154

path: str | None = None,

155

operations: dict | None = None,

156

**kwargs: Any

157

) -> None:

158

"""

159

Process operations dictionary, modifying operations in-place.

160

161

Parameters:

162

- path: Path to the resource

163

- operations: Dictionary mapping HTTP methods to operation objects

164

- **kwargs: Additional keyword arguments sent to APISpec.path()

165

166

Raises:

167

- PluginMethodNotImplementedError: If method not implemented by plugin

168

169

Note:

170

This method should modify the operations dictionary in-place.

171

"""

172

```

173

174

## Exception Handling

175

176

Plugin-specific exception for unimplemented methods.

177

178

```python { .api }

179

class PluginMethodNotImplementedError(APISpecError, NotImplementedError):

180

"""Raised when calling an unimplemented helper method in a plugin."""

181

```

182

183

## Usage Examples

184

185

### Creating a Custom Plugin

186

187

```python

188

from apispec import BasePlugin, APISpec

189

190

class CustomFrameworkPlugin(BasePlugin):

191

def init_spec(self, spec: APISpec) -> None:

192

"""Initialize plugin with spec reference."""

193

self.spec = spec

194

self.framework_routes = self.discover_routes()

195

196

def path_helper(self, path=None, operations=None, **kwargs):

197

"""Extract path from framework route object."""

198

route_obj = kwargs.get('route')

199

if route_obj:

200

return route_obj.get_path_template()

201

return path

202

203

def operation_helper(self, path=None, operations=None, **kwargs):

204

"""Extract operations from framework route handlers."""

205

route_obj = kwargs.get('route')

206

if route_obj and operations:

207

# Extract operation info from route handlers

208

for method, handler in route_obj.get_handlers().items():

209

if method.lower() in operations:

210

# Add framework-specific operation metadata

211

operations[method.lower()].update({

212

'operationId': handler.__name__,

213

'summary': getattr(handler, '__doc__', '').split('\n')[0]

214

})

215

216

def discover_routes(self):

217

"""Framework-specific route discovery logic."""

218

# Implementation depends on the framework

219

pass

220

```

221

222

### Using Plugins with APISpec

223

224

```python

225

from apispec import APISpec

226

from apispec.ext.marshmallow import MarshmallowPlugin

227

228

# Create spec with multiple plugins

229

spec = APISpec(

230

title="My API",

231

version="1.0.0",

232

openapi_version="3.0.2",

233

plugins=[

234

CustomFrameworkPlugin(),

235

MarshmallowPlugin()

236

]

237

)

238

239

# Plugins process components and paths during registration

240

spec.components.schema("User", schema=UserSchema) # MarshmallowPlugin processes this

241

spec.path("/users", route=user_route_obj) # CustomFrameworkPlugin processes this

242

```

243

244

### Framework Integration Plugin

245

246

```python

247

class FlaskPlugin(BasePlugin):

248

def path_helper(self, path=None, operations=None, **kwargs):

249

"""Extract path from Flask view function."""

250

view_function = kwargs.get('view_function')

251

if view_function:

252

# Get Flask route rules for this view

253

rules = [rule for rule in current_app.url_map.iter_rules()

254

if rule.endpoint == view_function.__name__]

255

if rules:

256

return rules[0].rule

257

return path

258

259

def operation_helper(self, path=None, operations=None, **kwargs):

260

"""Extract operations from Flask view function."""

261

view_function = kwargs.get('view_function')

262

if view_function and operations:

263

# Parse docstring for OpenAPI spec

264

from apispec.yaml_utils import load_operations_from_docstring

265

doc_operations = load_operations_from_docstring(view_function.__doc__ or '')

266

operations.update(doc_operations)

267

268

# Usage with Flask

269

@app.route('/users/<int:user_id>')

270

def get_user(user_id):

271

"""Get user by ID.

272

---

273

get:

274

parameters:

275

- name: user_id

276

in: path

277

schema:

278

type: integer

279

responses:

280

200:

281

description: User found

282

"""

283

pass

284

285

# Register with APISpec

286

spec.path(view_function=get_user)

287

```

288

289

### Schema Processing Plugin

290

291

```python

292

class SchemaValidationPlugin(BasePlugin):

293

def schema_helper(self, name, definition, **kwargs):

294

"""Add validation metadata to schema definitions."""

295

if definition and isinstance(definition, dict):

296

# Add schema validation rules

297

definition = definition.copy()

298

definition.setdefault('additionalProperties', False)

299

300

# Add pattern validation for string fields

301

if 'properties' in definition:

302

for prop_name, prop_def in definition['properties'].items():

303

if prop_def.get('type') == 'string' and 'email' in prop_name.lower():

304

prop_def['format'] = 'email'

305

306

return definition

307

return None

308

```