github.com/craicoverflow/tyk@v2.9.6-rc3+incompatible/coprocess/python/README.md (about) 1 # Coprocess (Python) 2 3 This feature makes it possible to write Tyk middleware using [Python](https://www.python.org/), the current binding supports Python 3.x. 4 The purpose of this README is to provide an overview of the architecture and a few implementation notes. 5 6 ## Usage 7 8 You'll need to build Tyk with specific build tags, see build notes below. 9 10 Basically `go build -tags 'coprocess python'`. 11 12 ### Setting up custom Python middleware 13 14 The custom middleware should be specified in your API definition file, under `custom_middleware` (see [coprocess_app_sample.json](../../apps/coprocess_app_sample.json)): 15 16 ```json 17 "custom_middleware": { 18 "pre": [ 19 { 20 "name": "MyPreMiddleware", 21 "require_session": false 22 } 23 ], 24 "post": [ 25 { 26 "name": "MyPostMiddleware", 27 "require_session": false 28 } 29 ], 30 "driver": "python" 31 } 32 ``` 33 34 You can chain multiple hook functions when the hook type is Pre, Post or PostAuthCheck. 35 36 Tyk will load all the modules inside `middleware/python`. 37 38 The "name" field represents the name of a Python function, a sample Python middleware matching the sample definition above will look like (see [middleware/python](../../middleware/python)): 39 40 ```python 41 from tyk.decorators import * 42 43 @Pre 44 def MyPreMiddleware(request, session, spec): 45 print("my_middleware: MyPreMiddleware") 46 return request, session 47 48 @Post 49 def MyPreMiddleware(request, session, spec): 50 print("my_middleware: MyPreMiddleware") 51 return request, session 52 ``` 53 54 ### Authenticating an API with Python 55 56 See example: https://tyk.io/docs/customise-tyk/plugins/rich-plugins/python/custom-auth-python-tutorial/ 57 58 ### Writing events handlers with Python 59 60 It's also possible to write a Tyk event listener with Python. The first step is to set a custom event handler inside your API definition (see [coprocess_app_sample_protected.json](../../apps/coprocess_app_sample_protected.json)): 61 62 ```json 63 ... 64 "event_handlers": { 65 "events": { 66 "AuthFailure": [ 67 { 68 "handler_name": "cp_dynamic_handler", 69 "handler_meta": { 70 "name": "my_handler" 71 } 72 } 73 ] 74 } 75 }, 76 ... 77 ``` 78 79 In the above sample we're setting an event handler for `AuthFailure` events, an event that's triggered everytime a failed authentication occurs. 80 81 The `handler_name` must be `cp_dynamic_handler`. 82 83 The `name` field inside `handler_meta` refers to a Python function name that can be written inside `event_handlers` (see [event_handlers/my_handler.py](../../event_handlers/my_handler.py)): 84 85 ```python 86 from tyk.decorators import Event 87 88 @Event 89 def my_handler(event, spec): 90 print("-- my_handler:") 91 print(" Event:", event) 92 print(" Spec:", spec) 93 ``` 94 95 This function will be called when the specified event occurs, Tyk will pass a Python object like this: 96 97 ```json 98 { 99 "TimeStamp": "2016-08-19 11:13:31.537047694 -0400 PYT", 100 "Meta":{ 101 "Path":"/coprocess-auth-tyk-api-test/", 102 "Origin":"127.0.0.1", 103 "Message":"Auth Failure", 104 "OriginatingRequest":"R0VUIC9jb3Byb2Nlc3MtYXV0aC10eWstYXBpLXRlc3QvIEhUVFAvMS4xDQpIb3N0OiAxMjcuMC4wLjE6ODA4MA0KVXNlci1BZ2VudDogY3VybC83LjQzLjANCkFjY2VwdDogKi8qDQpBdXRob3JpemF0aW9uOiAxDQoNCg==", 105 "Key":"" 106 }, 107 "Type": "AuthFailure" 108 } 109 ``` 110 111 The above handler can be tested by sending a HTTP request to the protected Coprocess API, with an invalid authorization header: 112 113 ``` 114 curl http://127.0.0.1:8080/coprocess-auth-tyk-api-test/ -H 'Authorization: invalidtoken' 115 ``` 116 117 ## Build requirements 118 119 * [Python 3.x](https://www.python.org/) 120 * [Go](https://golang.org) 121 * [Cython](http://cython.org/) (required if you need to modify and re-compile the gateway API binding) 122 * [protobuf](https://pypi.python.org/pypi/protobuf/3.0.0) (Python module): `pip3 install protobuf` 123 * [grpc](https://www.grpc.io/) (gRPC module): `pip3 install grpcio` 124 125 ## Build steps 126 127 To build Tyk with the Coprocess + Python support, use: 128 129 ``` 130 go build -tags 'coprocess python' 131 ``` 132 133 To compile the gateway API binding (assuming you're on the repository root): 134 135 ```sh 136 cd coprocess/python 137 ./cythonize gateway 138 ``` 139 140 This will "cythonize" `gateway.pyx`, generating `gateway.c` and `gateway.h`. 141 142 To compile some other binding (where `mybinding.pyx` is your Cython input file): 143 144 ```sh 145 cd coprocess/python 146 ./cythonize mybinding 147 ``` 148 149 [cythonize](cythonize) is a helper script for compiling Python source files with Cython and patching the resulting source with the specific build tags used by this Coprocess feature. 150 This is important in order to keep Tyk build-able when a standard build is needed (and make the Go compiler ignore C binding files based on the specified build tags). 151 152 The top of a standard Cython binding file will look like this: 153 ``` 154 /* Generated by Cython 0.24.1 */ 155 156 /* BEGIN: Cython Metadata 157 { 158 "distutils": { 159 "depends": [] 160 }, 161 "module_name": "gateway" 162 } 163 END: Cython Metadata */ 164 ``` 165 166 After running `cythonize` the binding will have the correct build tags, and will be ignored if you don't build Tyk with these (`go build -tags 'coprocess python'`): 167 168 ``` 169 // +build coprocess 170 // +build python 171 172 /* Generated by Cython 0.24.1 */ 173 174 /* BEGIN: Cython Metadata 175 { 176 "distutils": { 177 "depends": [] 178 }, 179 "module_name": "gateway" 180 } 181 END: Cython Metadata */ 182 ``` 183 184 After re-compiling a binding, the C source code will change and you may want to build Tyk again. 185 186 ## CPython 187 188 [Python](https://www.python.org/) has a very popular and well-documented [C API](https://docs.python.org/3/c-api/index.html), this coprocess feature makes a heavy use of it. 189 190 ## Built-in modules 191 192 All the standard Python modules are available and it's also possible to load additional ones, if you add them to your local Python installation (for example, using pip). 193 194 ### Coprocess Gateway API 195 196 There's a Python binding for the [Coprocess Gateway API](../README.md), this is written using the Cython syntax, it's basically a single file: [`gateway.pyx`](tyk/gateway.pyx). 197 198 This binding exposes some functions, like a storage handler that allows you to get/set Redis keys: 199 200 ```python 201 from tyk.decorators import * 202 from gateway import TykGateway as tyk 203 204 @Pre 205 def SetKeyOnRequest(request, session, spec): 206 tyk.store_data( "my_key", "expiring_soon", 15 ) 207 val = tyk.get_data("cool_key") 208 return request, session 209 ``` 210 211 ### Cython bindings 212 213 Cython takes a `.pyx` file and generates a C source file (`.c`) with its corresponding header (`.h`), after this process, we use these two files as part of the `cgo` build process. This approach has been used as an alternative to `cffi`, which introduced an additional step into the setup, requiring the user to install the module first. 214 215 So in practice, we don't use the `.pyx` files directly (and they aren't required at runtime!). When the build process is over, the bindings are part of the Tyk binary and can be loaded and accessed from Go code. 216 217 The bindings [declare an initialization function](tyk/gateway.h) that should be called after the Python interpreter is invoked, this will load the actual module and make it possible to import it using `import mymodule`. This is how [`gateway.pyx`](tyk/gateway.pyx) and its functions become available. 218 219 ### Middleware and wrappers 220 221 There are [quick wrappers](tyk/) for the HTTP request and session objects, written in Python, the idea is to provide an idiomatic way of writing middleware: 222 223 ```python 224 from tyk.decorators import * 225 226 @Pre 227 def AppendHeader(request, session, spec): 228 request.add_header("custom_header", "custom_value") 229 return request, session 230 ``` 231 232 The decorators provide a simple way of indicating when it's the right moment to execute your handlers, a handler that is decorated with `Pre` will be called before any authentication occurs, `Post` will occur after authentication and will have access to the `session` object. 233 You may find more information about Tyk middleware [here](https://tyk.io/docs/tyk-api-gateway-v1-9/javascript-plugins/middleware-scripting/).