Tyk Gateway with OpenAPI Architecture: Comprehensive Guide for Free Tyk & PostgREST Setup

February 16, 2024

Reverse proxy

Recently, in one of my projects, I have been working on an API solution providing access to data through REST endpoints. Since data has been structured in a relational database (Postgres) and there is a requirement to be compliant with OpenAPI specification, I was naturally inclined towards choosing PostgREST as API server solution. That would provide quite flexible methods of interacting with the underlying dataset without writing much (if any) code for endpoints. Additionally, OAS compliance is available out of the box.

While a PostgREST instance would cover majority of our needs, some functionality would be quite challenging to implement with a single PostgREST instance. To leave some room for future expansions, I have chosen to use Tyk gateway to be my reverse proxy so that it orchestrates routing the requests to a correct upstream API node. It's available in open-source version, and while lion's share of their documentation is focused on paid Tyk Dashboard, from the functionality perspective, open-source Tyk gateway is complete.

In this article, I'm sharing experience of how to use advantages of OpenAPI specification for configuring a functional API gateway. Also, I will demonstrate how to overcome challenges that occur when doing so for PostgREST (or other OAS-based) instances.

As a bonus, I'm showing the process using an example of two separate REST APIs. A solution that fully benefits from using an API gateway.

Your use case might be different but the target architecture could be similar.

Vision

Solution diagram

To leverage the advantages of conformity with OpenAPI specification (especially, predefined API schema), I decided to use OAS definitions as the source of truth for publishing API capabilities to external parties and to the API gateway. Luckily, Tyk gateway has recently started supporting OpenAPI specification as API definition language. But, unfortunately, I haven't found how to make Tyk gateway serve the merged OAS definition. So, there is a separate process for serving a unified API definition using a standalone Swagger instance. See the deployment diagram above.

I'm not covering the separate Swagger instance in this article but taking a look at openapi-merge-cli might give you an idea how to get a single OAS to serve.

The process of setting up such a solution and the challenges inherent in the process are described below.

Solution

Let's consider this example: we store data about the orders placed in our application in one Postgres database while master data of the corporate partners of ours is stored in another. For those two we want to create separate PostgREST API instances. We want to provide centralised access to the both instances of our data API so that from the user standpoint there is no difference where data is coming from.

When there is a request GET /transactions/orders coming to API gateway, it should behave like this:

Use case 1

and when a request GET /partners/companies is coming, it should work like that:

Use case 2

We will achieve it by doing the following things:

  1. Start two Postgres databases and two PostgREST instances
  2. Get available OpenAPI specification for the instances
  3. Convert the provided OpenAPI specifications from version 2 to version 3
  4. Start Tyk gateway
  5. Import OpenAPI specifications of version 3 into Tyk gateway
  6. Check how it works

Start Postgres databases and PostgREST instances

As PostgREST setup is very nicely described in the official documentation, I'm not explaining it here in detail. If you want to play with the overall solution on a good example, please, follow the instructions on PostgREST website. Otherwise, feel free to experiment with your OpenAPI compliant server or use the sample application I pushed to GitHub.

Please note that Postgres databases require some configuration to be PostgREST-ready. Check out the initialisation script if you want to see how the sample application is prepared.

If you are going to bring your own OpenAPI-compliant server, check the version of the specification. You can easily verify the version by checking either swagger or openapi value in the root of your OAS definition.

If you're on the version 3, feel free jump straight to "Import OAS 3.0 specification" section. Otherwise, follow the conversion steps below.

Get available OpenAPI specification for instances

PostgREST doesn’t support the static generation of OAS because it learns the schema of the database at the moment of startup. So, if specification needs to be extracted, at least one PostgREST instance should be up and running to introspect the database and return OAS definition.

While I referred to PostgREST documentation in the first step, here, I want to explicitly mention that by default the OpenAPI schema considers permissions and presents available endpoints only. To get the whole schema, you need to change openapi-mode for the PostgREST instance to ignore-privileges.

If you've done it right, you should be able to access the schema of PostgREST server at the root path. Detailed information is available in documentation.

OAS in a browser

Convert PostgREST OAS from version 2.0 to 3.0.0

As I mentioned in the beginning, PostgREST currently provides OpenAPI specification of version 2 while Tyk supports versions 3.0.x. It's not a big problem because OAS 2 can be converted to OAS 3. It can be done with an official Swagger Converter. The converter can be started locally in a Docker container but it's also available online - https://converter.swagger.io/.

Outdated OAS version is a recognized issue of PostgREST. As of February'24, the work on making PostgREST providing OAS of version 3 is in progress in a separate repository.

For simplicity, let's use the online version of the converter.

What you need to do is to copy OAS 2 specification and use it in [POST] /convert. If you're using Swagger interface, just click "Try it out" and paste specification as body of the request.

Swagger Converter input

If you hit "Execute", the converter will respond with the specification of version 3.0.1.

Swagger Converter output

This version of specification is perfectly compatible with Tyk gateway. Convert specifications for both instances and it will be good to import to Tyk.

Specification examples for version 2.0 and converted to 3.0.1 can be found in the sample code.

Prepare Tyk gateway

The best way to start a local instance of Tyk is using the Docker image. How it's done is explained by official examples of Tyk with Docker Compose but for the purpose of this experiment you might take the trivial Docker Compose setup from the sample Git repository that I have prepared.

Please, note that not the entire definition is shown in the snippet! Navigate to the source to see the whole configuration.

For our case, no special setup is needed but ensure that unauthenticated access is not blocked. Auth is not in the scope of this tutorial.

Import PostgREST as OAS to Tyk gateway

Now, when we have OAS of version 3.0.1, it can be statically imported as API definition to Tyk.

I want to note that it's possible to import OAS dynamically by calling the dedicated Tyk API endpoint. But to simplify the deployment process and to be able to version gateway as a whole with Git I do this import statically.

Another possible option might be Tyk Sync but it's in early access now so I'm not considering it for production while it's not strictly necessary.

We will create the files in the apps folder and provide this folder as a volume to Tyk gateway container to be available at app_path from the Tyk config.

You need to create two Tyk API definitions per upstream API - one is classic Tyk API definition to store overall API configuration (such as auth, rate limitation and so on) and one for OAS definition with available endpoints.

For classic Tyk API definition, here is the sample configuration (apps/postgrest1.json):

The points of interest here are:
  • api_id must match the one in the respective OAS definition
  • is_oas is set to true
  • proxy.listen_path and proxy.target_url specify at what subpath to receive the requests for the upstream API and at what URL to redirect to

proxy.target_url is set as an environment variable. In the sample Docker Compose setup, it's passed to Tyk gateway as a secret. If you are interested in how it's done, check out this recipe in Tyk docs.

For Tyk OAS API definition, documentation is not very clear which is understandable for a feature which is still pretty new. To understand how to work with it, read the following paragraph carefully.

For the respective OAS part, we need to take the OAS definition of version 3, add additional information for Tyk by placing a configuration object x-tyk-gateway in the root of OAS JSON and save this file next to classic Tyk API definition. In our case, it's postgrest1-oas.json.

You need to copy some information that you have placed in the classic definition earlier.
  • x-tyk-api-gateway.info.id should match api_id
  • x-tyk-api-gateway.upstream.url should match proxy.target_url
  • x-tyk-api-gateway.server.listen_path should match proxy.listen_path

The same should be repeated for the second set of API endpoints that are provided by the second PostgREST instance.

That's basically it. Congratulations! We can check how it works now.

Try it out

If you followed the example and used docker-compose setup from my repo, the gateway is running on the port 8888. You might give it a try.

curl --request GET --url http://localhost:8888/transactions/orders

and

curl --request GET --url http://localhost:8888/partners/companies

should provide you with data that is saved to the database in the initialisation script.

If you see some response there, awesome! You've made it working. Now, you might do something special with the configuration to get something that fits your needs the most.

[
	{
		"createdAt": "2024-02-11T16:56:07.810486+00:00",
		"id": 1,
		"orderNumber": "1",
		"status": "Placed",
		"updatedAt": "2024-02-11T16:56:07.810486+00:00"
	},
	{
		"createdAt": "2024-02-11T16:56:23.915413+00:00",
		"id": 2,
		"orderNumber": "2",
		"status": "Delivered",
		"updatedAt": "2024-02-11T16:56:23.915413+00:00"
	}
]

Summary

If you have reached this point, I'm really grateful for you. Your choice of technologies for your next project opens endless possibilities for something special.

With PostgREST, you might create scalable and configurable API access to your database. Just check what you might do with JWT issued by an IdP. Having RBAC and ABAC for users without any user table - that sounds nice, doesn't it?

With Tyk, you have a great opportunity to be future-proof with a Gartner's leader solution. Rate limiting, onboarding new APIs easily, JWT validation before even going to an upstream API. These will be very much welcome in your next API project. And with support of static API definitions and versioning you might be ambitious enough to target multiple nines.

And if you're compliant with OpenAPI, developers integrating with your API will appreciate your system. It's not a straightforward thing merging multiple OASs and serving it as a single Swagger but it's also not overly challenging. While the result is exciting.

As usual, it would be awesome to hear about your vision of this design and about what immediate improvements or enhancements you are tempted to try in your version of such a setup.

Good luck. It will be fun.