github.com/anuvu/tyk@v2.9.0-beta9-dl-apic+incompatible/coprocess/README.md (about)

     1  # Coprocess - PoC
     2  
     3  This feature makes it possible to write Tyk middleware using your favorite languages.
     4  
     5  ## Proto files
     6  
     7  To change the proto files and update the bindings, see proto/ and
     8  proto/update_bindings.sh.
     9  
    10  ## Python support
    11  
    12  [Python](https://www.python.org/) support is available, more notes [here](python/README.md).
    13  
    14  ## Lua support
    15  
    16  [Lua](https://www.lua.org/) support is available as well. Notes [here](lua/README.md).
    17  
    18  ## gRPC support
    19  
    20  Tyk provides support for [gRPC](http://www.grpc.io/), you may use any of the gRPC supported languages (e.g. Ruby, Java, etc.). Check the [gRPC support README](grpc/README.md).
    21  
    22  ## ID Extractor & auth cache
    23  
    24  The ID extractor is a very useful mechanism that will let you cache your authentication IDs and prevent certain requests from hitting your CP backend. It takes a set of rules from your API configuration (the rules are set per API).
    25  
    26  A sample usage will look like this:
    27  
    28  ```json
    29  "custom_middleware": {
    30    "pre": [
    31      {
    32        "name": "MyPreMiddleware",
    33        "require_session": false
    34      }
    35    ],
    36    "id_extractor": {
    37      "extract_from": "header",
    38      "extract_with": "value",
    39      "extractor_config": {
    40        "header_name": "Authorization"
    41      }
    42    },
    43    "driver": "grpc"
    44  },
    45  ```
    46  
    47  Tyk provides a set of ID extractors that aim to cover the most common use cases, a very simple one is the **value extractor**.
    48  
    49  ## Interoperability
    50  
    51  This feature implements an in-process message passing mechanism, based on [Protocol Buffers](https://developers.google.com/protocol-buffers/), any supported languages should provide a function to receive, unmarshal and process this kind of messages.
    52  
    53  The main interoperability task is achieved by using [cgo](https://golang.org/cmd/cgo/) as a bridge between a supported language -like Python- and the Go codebase.
    54  
    55  Your C bridge function must accept and return a `CoProcessMessage` data structure like the one described in [`api.h`](api.h), where `p_data` is a pointer to the serialized data and `length` indicates the length of it.
    56  
    57  ```c
    58  struct CoProcessMessage {
    59    void* p_data;
    60    int length;
    61  };
    62  ```
    63  
    64  The unpacked data will hold the actual `CoProcessObject` data structure, where `HookType` represents the hook type (see below), `Request` represents the HTTP request and `Session` is the Tyk session data.
    65  
    66  The `Spec` field holds the API specification data, like organization ID, API ID, etc.
    67  
    68  
    69  ```go
    70  type CoProcessObject struct {
    71  	HookType string
    72  	Request  CoProcessMiniRequestObject
    73  	Session  SessionState
    74  	Metadata map[string]string
    75  	Spec     map[string]string
    76  }
    77  ```
    78  
    79  ## Coprocess Dispatcher
    80  
    81  `coprocess.Dispatcher` describes a very simple interface for implementing the dispatcher logic, the required methods are: `Dispatch`, `DispatchEvent` and `Reload`.
    82  
    83  `Dispatch` accepts a pointer to a `struct CoProcessObject` (as described above) and must return an object of the same type. This method will be called for every configured hook, on every request. Traditionally this method will perform a single function call on the target language side (like `Python_DispatchHook` in `coprocess_python`), and the corresponding logic will be handled from there (mostly because different languages have different ways of loading, referencing or calling middlewares).
    84  
    85  `DispatchEvent` provides a way of dispatching Tyk events to a target language. This method doesn't return any variables but does receive a JSON-encoded object containing the event data. For extensibility purposes, this method doesn't use Protocol Buffers, the input is a `[]byte`, the target language will take this (as a `char`) and perform the JSON decoding operation.
    86  
    87  `Reload` is called when triggering a hot reload, this method could be useful for reloading scripts or modules in the target language.
    88  
    89  ## Coprocess Dispatcher - Hooks
    90  
    91  This component is in charge of dispatching your HTTP requests to the custom middlewares, in the right order. The dispatcher follows the standard middleware chain logic and provides a simple mechanism for "hooking" your custom middleware behavior, the supported hooks are:
    92  
    93  **Pre:** gets executed before any authentication information is extracted from the header or parameter list of the request.
    94  
    95  **Post:** gets executed after the authentication, validation, throttling, and quota-limiting middleware has been executed, just before the request is proxied upstream. Use this to post-process a request before sending it to your upstream API.
    96  
    97  **PostKeyAuth:** gets executed right after the autentication process.
    98  
    99  **CustomAuthCheck:** gets executed as a custom authentication middleware, instead of the standard ones provided by Tyk. Use this to provide your own authentication mechanism.
   100  
   101  ## Coprocess Gateway API
   102  
   103  [`coprocess_api.go`](../coprocess_api.go) provides a bridge between the gateway API and C, any function that needs to be exported should have the `export` keyword:
   104  
   105  ```go
   106  //export TykTriggerEvent
   107  func TykTriggerEvent( CEventName *C.char, CPayload *C.char ) {
   108    eventName := C.GoString(CEventName)
   109    payload := C.GoString(CPayload)
   110  
   111    FireSystemEvent(tykcommon.TykEvent(eventName), EventMetaDefault{
   112      Message: payload,
   113    })
   114  }
   115  ```
   116  
   117  You should also expect a header file declaration of this function in [`api.h`](api.h), like this:
   118  
   119  ```c
   120  #ifndef TYK_COPROCESS_API
   121  #define TYK_COPROCESS_API
   122  extern void TykTriggerEvent(char* event_name, char* payload);
   123  #endif
   124  ```
   125  
   126  The language binding will include this header file (or declare the function inline) and perform the necessary steps to call it with the appropriate arguments (like a `ffi` mechanism could do). As a reference, this is how this could be achieved if you're building a [Cython](http://cython.org/) module:
   127  
   128  ```python
   129  cdef extern:
   130    void TykTriggerEvent(char* event_name, char* payload);
   131  
   132  def call():
   133    event_name = 'my event'.encode('utf-8')
   134    payload = 'my payload'.encode('utf-8')
   135    TykTriggerEvent( event_name, payload )
   136  ```
   137  
   138  ## Basic usage
   139  
   140  The intended way of using a Coprocess middleware is to specify it as part of an API definition:
   141  
   142  ```json
   143  "custom_middleware": {
   144    "pre": [
   145        {
   146            "name": "MyPreMiddleware",  
   147            "require_session": false
   148        },
   149        {
   150            "name": "AnotherPreMiddleware",
   151            "require_session": false
   152        }
   153    ],
   154    "post": [
   155      {
   156        "name": "MyPostMiddleware",
   157        "require_session": false
   158      }
   159    ],
   160    "post_key_auth": [
   161      {
   162        "name": "MyPostKeyAuthMiddleware",
   163        "require_session": true
   164      }
   165    ],
   166    "auth_check": {
   167      "name": "MyAuthCheck"
   168    },
   169    "driver": "python"
   170  }
   171  ```
   172  
   173  It's important to note that all hook types support chaining except the custom auth check (`auth_check`).
   174  
   175  
   176  
   177  ## Build notes
   178  
   179  It's possible to use a [build tag](https://golang.org/pkg/go/build/#hdr-Build_Constraints):
   180  
   181  ```
   182  go build -tags 'coprocess python'
   183  ```
   184  
   185  ```
   186  go build -tags 'coprocess somelanguage'
   187  ```
   188  
   189  Each language should implement a ```CoProcessInit``` function, this will be called from the main function when the ```coprocess``` build tag is used.
   190  
   191  Using the ```coprocess``` build tag with no language tag will fail.
   192  
   193  A standard build is still possible:
   194  
   195  ```
   196  go build
   197  ```
   198  
   199  ```coprocess_dummy.go``` provides a dummy ```CoProcessInit``` function that will be called if you perform a standard Tyk build. This file will be ignored when using the ```coprocess``` build tag, as we expect it to be implemented by a language.
   200  
   201  ## Tests
   202  
   203  You must use the `coprocess` build tag to run the tests:
   204  
   205  ```
   206  go test -tags 'coprocess'
   207  go test -run CoProcess -tags 'coprocess'
   208  ```
   209  
   210  ## References
   211  
   212  [Trello note](https://trello.com/c/6QNWnF2n/265-coprocess-handlers-middleware-replacements-and-hooks)