AWS APIGateway × OpenAPI (2. Proxy)
2022-07-26
I have been working on a library that integrates an OpenAPI definition with a REST API definition on the CDK. This is the second blog post of the series that will walk you through the development of the library.
Background
In the first blog post of this series, we left the following challenge,
How can we achieve compatibility with
RestApi
?
Since it is too hard not to reuse RestApi
, I am going to write a subclass for it.
Defining interfaces
Before extending the AWS Cloud Development Kit (CDK) API, let us define minimal interfaces. Please note that I have excerpted and modified the interfaces and code shown in the following sections from my library for simplicity. You can find their full definitions in my GitHub repository.
IRestApiWithSpec
IRestApiWithSpec
is the extension of IRestApi
.
IResourceWithSpec
IResourceWithSpec
is the extension of Resource
*.
* To correctly extend IResource.addResource
, IResourceWithSpec
has to implement Resource
rather than IResource
.
On the other hand, IRestApiWithSpec.root
has to implement IResource
instead of Resource
, so the definition root: IResourceWithSpec
in IRestApiWithSpec
is too specific.
However, it should not matter because the public interface of Resource
, and IResource
are the same as far as I know.
ResourceOptionsWithSpec
ResourceOptionsWithSpec
is the extension of ResourceOptions
.
MethodOptionsWithSpec
MethodOptionsWithSpec
is the extension of MethodOptions
.
BasePrameterObject
is borrowed from an external library OpenApi3-TS[1].
I initially intended to override the definition of MethodOptions.requestParameters
like the following (see the example in the last blog post),
requestParameters?:;
But this attempt has failed because it would make MethodOptionsWithSpec
unassignable to MethodOptions
.
So I have introduced a new property requestParameterSchemas
as a workaround.
Extending RestApi
Extending RestApi
is straightforward.
Just use the language feature (extends
) and override properties of RestApi
.
I omit the details of RestApiWithSpecProps
for simplicity.
Please refer to my GitHub repository if you are interested in it.
Here, the question is how to implement root
.
Wrapping root
of the superclass (RestApi
) sounds good.
So how do we wrap it?
Write a wrapper class that just forwards most requests to root
of RestApi
?
That will involve a lot of boilerplate.
Then Proxy
should better meet our needs.
Proxying root
Writing a Proxy
for root
is fairly easy.
All you have to do is implement the get
function of a handler object.
// root: IResource
;
Unfortunately, TypeScript does not recognize the proxied object as IResourceWithSpec
in the above code and ends up with an error.
Because the default TypeScript definition of the Proxy
constructor is something like the following,
declare global
To address this issue, we can extend the definition of the Proxy
constructor so that it can produce a type different from that of target
.
This StackOverflow post[2] exactly answers it.
So adding the following declaration solves the TypeScript error.
declare global
Extending Resource
Every time we create a Resource
, we have to wrap it with a Proxy
as described in the section "Proxying root."
So I have introduced a factory method augmentResource
that can wrap any existing IResource
with the features of IResourceWithSpec
.
This factory method can also be applied to root
.
The above code has been simplified; you can find the actual definition in my GitHub repository.
Wrap-up
In this blog post, I have introduced Proxy
to facilitate the extension of the CDK API.
I also have shown a trick to circumvent a TypeScript error about Proxy
.
In an upcoming blog post, we will tackle the challenge of when we should output an OpenAPI definition file.
Reference
-
TypeScript bindings of the OpenAPI 3 specification itself.
-
How to use Proxy
with a different type than T as argument? - Answer