How to configure a gRPC server using Tyk

Here at Tyk, API management is our business, and our business is simple; offer the consumer the most significant amount of APIM value with the least amount of complexity. This includes providing customers with the tooling required to handle 99 percent of your use cases and providing an extensible framework for those that might be unique to your business logic.

Transformations are included with Tyk 

Take, for example, transformations. Whether you’re using Tyk Open Source or Tyk Pro, our extensive plugins (including transformations) are provided to you; batteries included- at no extra cost. Tyk’s transformations are powered by Go templates and the sprig library, which offers powerful template functions. Things such as iterators, conditionals and data manipulations are supported natively.

So why would you want to reinvent the wheel with transformations through plugins? You may have core business logic in transformations implemented in various programming languages.  

Perhaps your transformations need to leverage machine learning libraries such as NumPy or Tensorflow. Regardless of the reasoning, we’re here to enable your success. Tyk can act as a gRPC passthrough or a gRPC client and make outbound calls to your gRPC services.  

This guide will take you through configuring a gRPC server which you can leverage to add additional logic to your API requests. Any gRPC-supported language will work as we provide the Protobuf definitions. However, the focus of this guide will be a Python implementation of a gRPC server. 

For example, as illustrated in Figure 1, an API consumer can make an API request to a Microservice (or service) managed by Tyk. A gRPC plugin is specified in the API definition in Tyk-Gateway (client), which contacts the gRPC server running on the host system.There are many stages in the request middleware chain; you can add custom logic through plugins; for example, Figure 1 depicts the logic executing at the “response” stage. If you attach a debugger to the gRPC server, you can intercept the request and debug and develop your plugin.

Figure 1: An API consumer can make an API request to a microservice managed by Tyk. During the request lifecycle, the Tyk-Gateway acts as a gRPC client that can contact a gRPC server to layer on custom logic.

We have two possibilities for a Tyk install; this guide will cover instructions for both open-source and licensed installations. 

NOTE: This guide is only tested on OSX (INTEL CPU).

1. Tyk open source Instructions:

 

1.1) Ensure you have the following dependencies on your system

This guide assumes you have Docker, Docker-Compose and Python 3 installed on your host system. On OSX systems, you need Docker Desktop. You will additionally need to install the following Python packages:

pip3 install grpcio
pip3 install grpcio-tools
brew install protobuf

 

1.2) Clone and deploy open source Tyk-Gateway

In this example, we will clone a dockerised version of the open source Tyk-Gateway:

git clone https://github.com/TykTechnologies/tyk-gateway-docker

Navigate into the directory cd tyk-gateway-docker

Ensure that you update the config file tyk.standalone.conf with the values outlined in this documentation link. In summary, the two most important configurations are enable_coprocess and coprocess_grpc_server. Since our gateway will be running within Docker and our gRPC server on the host, we instruct the gateway to reach out to our gRPC server on the host through host.docker.internal..

"coprocess_options": {

    "enable_coprocess": true,

    "coprocess_grpc_server": "tcp://host.docker.internal:5555"

  },

Reference 1: Sample configuration options for coprocess_options.

Now with the options configured, the gateway can be launched with a simple:
`docker-compose up`. You can validate that the gateway has successfully deployed with a curl command:

curl http://localhost:8080/hello

Your output should look similar to this:

{"status":"pass","version":"4.1.0","description":"Tyk GW","details":{"redis":{"status":"pass","componentType":"datastore","time":"2022-10-05T19:10:52Z"}}}

 

1.3) Clone Tyk repository, Generate Protobuf definitions and deploy gRPC server

Now that we have an open source Tyk-Gateway running, it’s time to spin up a gRPC server. We provide a few gRPC servers on the Tyk Github repository.

git clone https://github.com/TykTechnologies/tyk.git

Navigate to `tyk/coprocess/proto’ and run “./update_bindings.sh”

This will generate the protobuf bindings. These definitions allow Tyk-Gateway (client) to exchange data with your gRPC server seamlessly. Now the server file needs to be updated with the correct import statement, and it can be properly launched.

Edit the following `tyk/coprocess/bindings/python/sample_server.py` and replace it with the sample server code here.

sample_server.py
import coprocess_object_pb2, coprocess_object_pb2_grpc
from coprocess_session_state_pb2 import SessionState

import grpc, time, json, gzip

_ONE_DAY_IN_SECONDS = 60 * 60 * 24

from concurrent import futures

def MyPreMiddleware(coprocess_object):
coprocess_object.request.set_headers["MyPreMiddleware"] = "MyPreMiddleware"
return coprocess_object

def MyPostMiddleware(coprocess_object):
body = coprocess_object.response.body
json_body = json.loads(body)
json_body['Transform'] = 'Custom Field'

coprocess_object.response.body = json.dumps(json_body)
coprocess_object.response.raw_body=json.dumps(json_body).encode('utf-8')
coprocess_object.response.headers['Content-Length'] = str(len(coprocess_object.response.raw_body))

return coprocess_object

def MyResponseMiddleware(coprocess_object):
# Unzip Response
gzip_decoded_body = gzip.decompress(coprocess_object.response.raw_body)
json_body = json.loads(str(gzip_decoded_body, 'utf-8'))
ids = list()

# Extract IDs
for item in json_body:
ids.append(item['id'])

# Format Response
coprocess_object.response.body = json.dumps(ids)
coprocess_object.response.raw_body = json.dumps(ids).encode('utf-8')
coprocess_object.response.headers['Content-Length'] = str(len(coprocess_object.response.raw_body))
coprocess_object.response.headers['Content-Encoding'] = ''
return coprocess_object

def MyAuthCheck(coprocess_object):
valid_token = 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
request_token = coprocess_object.request.headers["Authorization"]

if request_token == valid_token:
new_session = SessionState()
new_session.rate = 1000.0
new_session.per = 1.0
coprocess_object.metadata["token"] = "mytoken"
coprocess_object.session.CopyFrom(new_session)

else:
coprocess_object.request.return_overrides.response_code = 401
coprocess_object.request.return_overrides.response_error = 'Not authorized (Python middleware)'

return coprocess_object

class MyDispatcher(coprocess_object_pb2_grpc.DispatcherServicer):
def Dispatch(self, coprocess_object, context):
if coprocess_object.hook_name == "MyPreMiddleware":
coprocess_object = MyPreMiddleware(coprocess_object)

if coprocess_object.hook_name == "MyPostMiddleware":
coprocess_object = MyPostMiddleware(coprocess_object)

if coprocess_object.hook_name == "MyAuthCheck":
coprocess_object = MyAuthCheck(coprocess_object)

if coprocess_object.hook_name == "MyResponseMiddleware":
coprocess_object = MyResponseMiddleware(coprocess_object)

return coprocess_object

def DispatchEvent(self, event_wrapper, context):
event = json.loads(event_wrapper.payload)
return coprocess_object_pb2_grpc.EventReply()

def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
coprocess_object_pb2_grpc.add_DispatcherServicer_to_server(
MyDispatcher(), server)
server.add_insecure_port('[::]:5555')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)

if __name__ == '__main__':
serve()

 

This sample server includes an extra function called MyResponseMiddleware which performs a body transform on the upstream JsonPlaceholder to extract all IDs from a json payload.

Now that this is imported, we can launch the python3 server.

cd ./tyk/coprocess/bindings/python

python3 sample_server.py]```

 

1.4) Create an API with a gRPC plugin enabled 

Make a POST request to the gateway’s /tyk/apis endpoint to create an API with gRPC enabled. See Reference 2 for a complete example. The reference example generates a new API definition that reverses proxies to jsonplaceholder.typicode.com and has a reference to a gRPC plugin. The listening path of this API definition is /extract-json-values-grpc-server/.

RESP=`curl https://gist.githubusercontent.com/JRWu/bbabf7bbf65bef868b277a24dd5bcb64/raw/5020ee151bbedc754c256219f279ddbef240ca1d/tyk_apidef_bodytransform_grpc.json`

curl -X POST -H "Content-Type: application/json" -H "X-Tyk-Authorization: foo" -d $RESP http://localhost:8080/tyk/apis

curl -X GET -H "X-Tyk-Authorization: foo" http://localhost:8080/tyk/reload

Reference 2: Making a post request to the /tyk/apis endpoint to create an API definition regarding a gRPC plugin.

 

1.5) Test out the endpoint 

In Reference 4, you can now make a GET request against your new API, and since it reverse proxies to jsonplaceholder.typicode.com, the /users endpoint will return the ID of your request. Please see Reference 3 for the original untransformed response. Our gRPC server injects custom logic at the “response” stage in the Request Middleware Chain. This custom logic allows us to intercept the response from our upstream and manipulate the data, such as extracting all user IDs into an array for a response. Optionally, follow Step 1.6 to attach a debugger to your gRPC server and intercept the API requests for live debugging.  

 

1.6) Attaching a debugger to the gRPC server 

You’ll notice that the process for the gRPC server in Step 1.3 is simply running an instance of sample_server.py from the command line. As this process runs on your host machine, it is possible to attach a debugger. Any IDE with a Python debugger is sufficient. However, in my example, I will be using Pycharm by Jetbrains. 

Figure 2 illustrates the configuration of a Run/Debug configuration within my IDE, and when selecting the “Debug selected configuration” option illustrated by the red box in Figure 2, sample_server.py will launch with a debugger attached. 

Creating a breakpoint in the gRPC server code, as illustrated in Figure 3, and simply making a request to an API endpoint with the gRPC plugin enabled will trigger the IDE to capture the request. As highlighted in Figure 3, the full coprocess_object is available for you to inspect.

Figure 2: Configuration of a Run/Debug Configuration in PyCharm for intercepting API requests sent to the gRPC server.

Figure 3: Setting a breakpoint in the method MyResponseMiddleware, and intercepting an API request.

A sample GET request to the jsonplaceholder

 

curl https://jsonplaceholder.typicode.com/users

# Reponse

[

>  {

    "id": 1,

    "name": "Leanne Graham",

    "username": "Bret",

    "email": "[email protected]",

    "address": {

      "street": "Kulas Light",

      "suite": "Apt. 556",

      "city": "Gwenborough",

      "zipcode": "92998-3874",

      "geo": {

        "lat": "-37.3159",

        "lng": "81.1496"

      }

},

    "phone": "1-770-736-8031 x56442",

    "website": "hildegard.org",

    "company": {

      "name": "Romaguera-Crona",

      "catchPhrase": "Multi-layered client-server neural-net",

      "bs": "harness real-time e-markets"

    }

  },

  {

    "id": 2,

    "name": "Ervin Howell",

    "username": "Antonette",

    "email": "[email protected]",

    "address": {

      "street": "Victor Plains",

      "suite": "Suite 879",

      "city": "Wisokyburgh",

      "zipcode": "90566-7771",

      "geo": {

        "lat": "-43.9509",

        "lng": "-34.4618"

      }

    },

    "phone": "010-692-6593 x09125",

    "website": "anastasia.net",

    "company": {

      "name": "Deckow-Crist",

      "catchPhrase": "Proactive didactic contingency",

      "bs": "synergize scalable supply-chains"

    }

  },

…

]

 

Reference 3: Expand the accordion above to see a sample GET request to the jsonplaceholder upstream on the /users endpoint. This response returns an array of json objects, each with an id field.

 

curl localhost:8080/extract-json-values-grpc-server/users                                                      

# Response

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Reference 4: A sample GET request to our Tyk-managed endpoint and a transformed response containing only the users’ IDs.

2. Tyk Pro Instructions 

 

2.1 Install dependencies

The dependencies for Tyk Pro are the same as Tyk Open Source. Follow the steps outlined in 1.1).

 

2.2 Install Tyk Pro 

Here we will use a dockerized version of Tyk-Pro.

git clone https://github.com/TykTechnologies/tyk-pro-docker-demo.git

Navigate into the directory

cd tyk-pro-docker-demo

Ensure that you obtain a licence key for the Tyk Dashboard from our website and follow the repository’s instructions for how to load the licence key through environment variables. 

This repository leverages environment variables instead of configuration files, so you must update the two environment variables in the cons/tyk_analytics.env file to the following values illustrated in Reference 4. Since our gateway will be running within Docker and our gRPC server on the host, we instruct the gateway to reach out to our gRPC server on the host through host.docker.internal.

TYK_GW_COPROCESSOPTIONS_ENABLECOPROCESS=true
TYK_GW_COPROCESSOPTIONS_COPROCESSGRPCSERVER=tcp://host.docker.internal:5555

Reference 5: The two environment variables need to be set to instruct the gateway to use coprocess and where the gRPC server is running.

Now with the options configured, the gateway can be launched with a simple `docker-compose up`. You can validate that the gateway has successfully deployed with a curl command:

curl http://localhost:8080/hello

Navigate to the Dashboard at localhost:3000 and fill in the values to bootstrap your Tyk installation. 

 

2.3 Clone Tyk repository, generate protobuf definitions and deploy gRPC server

Same as step 1.3, follow the steps outlined in 1.3.

 

2.4 Create an API with a gRPC plugin enabled

Creating an API through the Tyk dashboard APIs or leveraging the GUI is possible. In this example, we will navigate to the APIs tab on the left-hand side and select Import API. You can paste in the API definition found here to generate an API that reverse proxies to httpbin.org and refers to a gRPC plugin located within it.

 

API definition
{
    "api_id": "22c41d3bd44f4764543a704c8934ad0c",
    "jwt_issued_at_validation_skew": 0,
    "upstream_certificates": {},
    "use_keyless": true,
    "enable_coprocess_auth": false,
    "base_identity_provided_by": "",
    "custom_middleware": {
      "pre": [],
      "post": [],
      "post_key_auth": [],
      "auth_check": {
        "name": "",
        "path": "",
        "require_session": false,
        "raw_body_only": false
      },
      "response": [
        {
          "name": "MyResponseMiddleware",
          "path": "",
          "require_session": false,
          "raw_body_only": false
        }
      ],
      "driver": "grpc",
      "id_extractor": {
        "extract_from": "",
        "extract_with": "",
        "extractor_config": {}
      }
    },
    "disable_quota": false,
    "custom_middleware_bundle": "",
    "cache_options": {
      "cache_timeout": 60,
      "enable_cache": true,
      "cache_all_safe_requests": false,
      "cache_response_codes": [],
      "enable_upstream_cache_control": false,
      "cache_control_ttl_header": "",
      "cache_by_headers": []
    },
    "enable_ip_blacklisting": false,
    "tag_headers": [],
    "jwt_scope_to_policy_mapping": {},
    "tags_disabled": false,
    "pinned_public_keys": {},
    "expire_analytics_after": 0,
    "domain": "",
    "openid_options": {
      "providers": [],
      "segregate_by_client": false
    },
    "jwt_policy_field_name": "",
    "enable_proxy_protocol": false,
    "jwt_default_policies": [],
    "active": true,
    "jwt_expires_at_validation_skew": 0,
    "config_data": {},
    "notifications": {
      "shared_secret": "",
      "oauth_on_keychange_url": ""
    },
    "jwt_client_base_field": "",
    "auth": {
      "disable_header": false,
      "auth_header_name": "Authorization",
      "cookie_name": "",
      "name": "",
      "validate_signature": false,
      "use_param": false,
      "signature": {
        "algorithm": "",
        "header": "",
        "use_param": false,
        "param_name": "",
        "secret": "",
        "allowed_clock_skew": 0,
        "error_code": 0,
        "error_message": ""
      },
      "use_cookie": false,
      "param_name": "",
      "use_certificate": false
    },
    "check_host_against_uptime_tests": false,
    "auth_provider": {
      "name": "",
      "storage_engine": "",
      "meta": {}
    },
    "blacklisted_ips": [],
    "graphql": {
      "schema": "",
      "enabled": false,
      "engine": {
        "field_configs": [],
        "data_sources": []
      },
      "type_field_configurations": [],
      "execution_mode": "proxyOnly",
      "proxy": {
        "auth_headers": {}
      },
      "subgraph": {
        "sdl": ""
      },
      "supergraph": {
        "subgraphs": [],
        "merged_sdl": "",
        "global_headers": {},
        "disable_query_batching": false
      },
      "version": "2",
      "playground": {
        "enabled": false,
        "path": ""
      }
    },
    "hmac_allowed_clock_skew": -1,
    "dont_set_quota_on_create": false,
    "uptime_tests": {
      "check_list": [],
      "config": {
        "expire_utime_after": 0,
        "service_discovery": {
          "use_discovery_service": false,
          "query_endpoint": "",
          "use_nested_query": false,
          "parent_data_path": "",
          "data_path": "",
          "cache_timeout": 60
        },
        "recheck_wait": 0
      }
    },
    "enable_jwt": false,
    "do_not_track": false,
    "name": "ExtractJsonValuesgRPCServer",
    "slug": "extract-json-values-grpc-server",
    "is_oas": false,
    "analytics_plugin": {
      "enable": false,
      "plugin_path": "",
      "func_name": ""
    },
    "oauth_meta": {
      "allowed_access_types": [],
      "allowed_authorize_types": [],
      "auth_login_redirect": ""
    },
    "CORS": {
      "enable": true,
      "max_age": 24,
      "allow_credentials": false,
      "exposed_headers": [],
      "allowed_headers": [
        "Origin",
        "Accept",
        "Content-Type",
        "X-Requested-With",
        "Authorization"
      ],
      "options_passthrough": false,
      "debug": false,
      "allowed_origins": [
        "*"
      ],
      "allowed_methods": [
        "GET",
        "POST",
        "HEAD"
      ]
    },
    "event_handlers": {
      "events": {}
    },
    "proxy": {
      "target_url": "https://jsonplaceholder.typicode.com",
      "service_discovery": {
        "endpoint_returns_list": false,
        "cache_timeout": 0,
        "parent_data_path": "",
        "query_endpoint": "",
        "use_discovery_service": false,
        "_sd_show_port_path": false,
        "target_path": "",
        "use_target_list": false,
        "use_nested_query": false,
        "data_path": "",
        "port_data_path": ""
      },
      "check_host_against_uptime_tests": false,
      "transport": {
        "ssl_insecure_skip_verify": false,
        "ssl_min_version": 0,
        "proxy_url": "",
        "ssl_ciphers": []
      },
      "target_list": [],
      "preserve_host_header": false,
      "strip_listen_path": true,
      "enable_load_balancing": false,
      "listen_path": "/extract-json-values-grpc-server/",
      "disable_strip_slash": true
    },
    "expiration": "",
    "client_certificates": [],
    "use_basic_auth": false,
    "version_data": {
      "not_versioned": true,
      "default_version": "",
      "versions": {
        "Default": {
          "name": "Default",
          "expires": "",
          "paths": {
            "ignored": [],
            "white_list": [],
            "black_list": []
          },
          "use_extended_paths": true,
          "extended_paths": {
            "ignored": [],
            "white_list": [],
            "black_list": [],
            "transform": [],
            "transform_response": [],
            "transform_jq": [],
            "transform_jq_response": [],
            "transform_headers": [],
            "transform_response_headers": [],
            "hard_timeouts": [],
            "circuit_breakers": [],
            "url_rewrites": [],
            "virtual": [],
            "size_limits": [],
            "method_transforms": [],
            "track_endpoints": [],
            "do_not_track_endpoints": [],
            "validate_json": [],
            "internal": []
          },
          "global_headers": {
            "accept-encoding": "gzip"
          },
          "global_headers_remove": [
            "accept-encoding"
          ],
          "global_response_headers": {},
          "global_response_headers_remove": [],
          "ignore_endpoint_case": false,
          "global_size_limit": 0,
          "override_target": ""
        }
      }
    },
    "jwt_scope_claim_name": "",
    "use_standard_auth": false,
    "session_lifetime": 0,
    "hmac_allowed_algorithms": [],
    "disable_rate_limit": false,
    "definition": {
      "enabled": false,
      "name": "",
      "default": "",
      "location": "header",
      "key": "x-api-version",
      "strip_path": false,
      "strip_versioning_data": false,
      "versions": {}
    },
    "use_oauth2": false,
    "jwt_source": "",
    "jwt_signing_method": "",
    "session_lifetime_respects_key_expiration": false,
    "jwt_not_before_validation_skew": 0,
    "use_go_plugin_auth": false,
    "jwt_identity_base_field": "",
    "allowed_ips": [],
    "request_signing": {
      "is_enabled": false,
      "secret": "",
      "key_id": "",
      "algorithm": "",
      "header_list": [],
      "certificate_id": "",
      "signature_header": ""
    },
    "org_id": "5e9d9544a1dcd60001d0ed20",
    "domain_disabled": false,
    "enable_ip_whitelisting": false,
    "global_rate_limit": {
      "rate": 0,
      "per": 0
    },
    "protocol": "",
    "enable_context_vars": false,
    "tags": [],
    "basic_auth": {
      "disable_caching": false,
      "cache_ttl": 0,
      "extract_from_body": false,
      "body_user_regexp": "",
      "body_password_regexp": ""
    },
    "listen_port": 0,
    "session_provider": {
      "name": "",
      "storage_engine": "",
      "meta": {}
    },
    "auth_configs": {
      "authToken": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      },
      "basic": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      },
      "coprocess": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      },
      "hmac": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      },
      "jwt": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      },
      "oauth": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      },
      "oidc": {
        "disable_header": false,
        "auth_header_name": "Authorization",
        "cookie_name": "",
        "name": "",
        "validate_signature": false,
        "use_param": false,
        "signature": {
          "algorithm": "",
          "header": "",
          "use_param": false,
          "param_name": "",
          "secret": "",
          "allowed_clock_skew": 0,
          "error_code": 0,
          "error_message": ""
        },
        "use_cookie": false,
        "param_name": "",
        "use_certificate": false
      }
    },
    "strip_auth_data": false,
    "certificate_pinning_disabled": false,
    "id": "630f58f02b7536000141565e",
    "upstream_certificates_disabled": false,
    "certificates": [],
    "enable_signature_checking": false,
    "use_openid": false,
    "internal": false,
    "jwt_skip_kid": false,
    "enable_batch_request_support": false,
    "enable_detailed_recording": false,
    "scopes": {
      "jwt": {
        "scope_claim_name": "",
        "scope_to_policy": {}
      },
      "oidc": {
        "scope_claim_name": "",
        "scope_to_policy": {}
      }
    },
    "response_processors": [],
    "use_mutual_tls_auth": false
  }

Figure 4: Importing the API definition defined here through the Tyk dashboard. Or expand the accordion below to access the code.

 

2.5) Test out the endpoint 

Same as section 1.5) please see section 1.5).

 

2.6) Attaching a debugger to the gRPC server 

Same as section 1.6) please see section 1.6).

Tyk and gRPC transformation, complete!

Congratulations! You’ve successfully configured a gRPC server which you can leverage to add additional logic to your API requests – for both open-source and licensed installations. 

As illustrated in Reference 4, you’ve now taken a response from your upstream and transformed it into your gRPC server. Not only have we demonstrated the power of gRPC plugins, but we have also explored only a fraction of the extensibility of Tyk. 

Much like Golang plugins, gRPC plugins provide hooks into all stages of the request middleware. Please visit our
documentation linked here
for further details. 

For further support and direction on custom plugins and the Tyk ecosystem, please check out our community forums, where our dedicated team members will help guide you through everything Tyk. As we are founded on open-source principles, we actively encourage contribution and collaboration through our Github! Please feel free to raise an issue or pull request and our product team will be happy to take a look!