Hooks
Hooks are a way to add custom code to your SDK or Terraform provider to hook into the API invocation lifecycle. This document will guide you through extending the liblab generated SDK with your custom logic using our Hooks framework.
TypeScript v1 TypeScript v2 Python v1 Python v2 Java v1 Java v2 C# Go Terraform PHP ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
What are Hooks?
In some use cases, you need to extend the SDK created by liblab, and add your own custom code into the SDK at the generation process. Examples of such use cases include custom authentication or auditing requirements, or providing Terraform plan modifiers.
liblab can extend your SDKs in each of the languages generated, using our Hooks framework. The SDK hooks framework lets you hook in your code into three events in the API invocation lifecycle:
- Before Request: Code implemented in this section will run before the request. You can use the request object and update the request itself before it goes out to your API.
- After Response: Code implemented in this section will run after the call returns from your API. You can use the request objects to get context for the API call made and the response object for the response provided.
- On Error: Code implemented in this section will run in case of an API call error. You can use the request objects to get context for the API call and the exception object for information about the error that accrued.
Happy path
Error path
For Terraform you can hook into the terraform plan
command to modify the plan before it is applied. You can read more on this in our Terraform provider hooks and custom plan modifiers documentation.
When working with hooks, you can implement only the ones your code needs, before request, after response, or on error. The following code block provides examples for each hook across all supported programming languages.
- TypeScript v1
- TypeScript v2
- Python v1
- Python v2
- Java v1
- Java v2
- C#
- Go
- PHP
export default class CustomHook implements Hook {
async beforeRequest(request: Request): Promise<void> {
// Your code goes here
}
async afterResponse(request: Request, response: Response): Promise<void> {
// Your code goes here
}
async onError(error: Exception): Promise<void> {
// Your code goes here
}
}
export class CustomHook implements Hook {
public async beforeRequest(request: HttpRequest, params: Map<string, string>): Promise<HttpRequest> {
// Your code goes here
}
public async afterResponse(request: HttpRequest, response: HttpResponse<any>, params: Map<string, string>): Promise<HttpResponse<any>> {
// Your code goes here
}
public async onError(request: HttpRequest, response: HttpResponse<any>, params: Map<string, string>): Promise<HttpError> {
// Your code goes here
}
}
class CustomHook:
def before_request(self, request: Request, **kwargs):
# Your code goes here
def after_response(self, request: Request, response: Response, **kwargs):
# Your code goes here
def on_error(self, error: Exception, request: Request, response: Response, **kwargs):
# Your code goes here
class CustomHook:
def before_request(self, request: Request, **kwargs):
# Your code goes here
def after_response(self, request: Request, response: Response, **kwargs):
# Your code goes here
def on_error(self, error: Exception, request: Request, response: Response, **kwargs):
# Your code goes here
Java v1 uses the okhttp3 library.
package com.liblab.hook;
import java.util.Map;
import okhttp3.Request;
import okhttp3.Response;
public class CustomHook implements Hook {
@Override
public Request beforeRequest(Request request, Map<String, String> additionalParameters) {
return request;
}
@Override
public Response afterResponse(
Request request, Response response, Map<String, String> additionalParameters) {
return response;
}
@Override
public void onError(
Request request, Exception exception, Map<String, String> additionalParameters) {}
}
Java v2 uses the okhttp3 library.
package com.liblab.hook;
import java.util.Map;
import okhttp3.Request;
import okhttp3.Response;
public class CustomHook implements Hook {
@Override
public Request beforeRequest(Request request, Map<String, String> additionalParameters) {
return request;
}
@Override
public Response afterResponse(
Request request, Response response, Map<String, String> additionalParameters) {
return response;
}
@Override
public void onError(
Request request, Exception exception, Map<String, String> additionalParameters) {}
}
public class CustomHook : IHook
{
public async Task<HttpRequestMessage> BeforeRequestAsync(HttpRequestMessage request)
{
}
public async Task<HttpResponseMessage> AfterResponseAsync(HttpResponseMessage response)
{
}
public async Task OnErrorAsync(HttpResponseMessage response)
{
}
}
type Hook interface {
BeforeRequest(req Request) Request
AfterResponse(req Request, resp Response) Response
OnError(req Request, resp ErrorResponse) ErrorResponse
}
class CustomHook implements HookInterface
{
public function beforeRequest(RequestInterface &$request): void
{
// Your code goes here
}
public function afterResponse(RequestInterface $request, ResponseInterface &$response): void
{
// Your code goes here
}
public function onError(RequestInterface $request, Exception $exception): void
{
// Your code goes here
}
}
When generating both a Terraform provider and a standalone Go SDK, the hooks are not shared between the Go SDK created for the Terraform provider and the standalone Go SDK.
Add hooks to your liblab project
To add the hooks framework, run the following command:
liblab hooks add
This generates a hooks
folder that you can modify to extend the SDK. To ensure it's included in the SDK, the hooks
folder must be located in the same directory as your liblab configuration file. Inside the hooks
folder, you'll find subfolders for each language specified in your configuration file:
.
├── hooks
│ ├── go
│ ├── csharp
│ ├── java
│ ├── python
│ ├── terraform
│ ├── php
│ └── typescript
├── customPlanModifiers // hooks that are triggered on the `terraform plan` command
│ ├── attributes
│ └── resources
└── liblab.config.json
Each folder contains a complete code project where you can add your custom hook code. This code is sent to liblab when the SDK is generated. The presence of the hooks
folder is all liblab requires to include hooks in your SDK.
To add hooks for a single language, run the following command:
liblab hooks add --language=<language>
If you are creating hooks for a Terraform provider, you will get an additional folder called customPlanModifiers
which contains the hooks for the internal Go SDK that is used by the Terraform provider. Access the Terraform provider hooks and custom plan modifiers documentation for additional information.
Hooks can be written for the underlying Go SDK that is used by the Terraform provider by updating the code in the hooks/terraform
folder. These hooks are written in the same way as writing hooks for the Go SDK.
You can read more about adding hooks in our CLI hooks documentation.
Implement hooks
In the hooks
folder, you will find hooks code for each of the programming languages you have generated.
- TypeScript v1
- TypeScript v2
- Python v1
- Python v2
- Java v1
- Java v2
- C#
- Go
- PHP
typescript
├── src
│ └── index.ts
├── tests
│ └── hook.spec.ts
├── package-lock.json
├── package.json
├── prettier.config.js
├── tsconfig.eslint.json
└── tsconfig.json
typescript
├── src
│ └── hook.ts
│ └── custom-hook.ts
python
├── src
│ └── hook.py
├── test
│ └── test_hook.py
└── requirements.txt
python
├── src
│ └── hook.py
├── test
│ └── test_hook.py
└── requirements.txt
java
├── src
│ ├── main/java/com/liblab
│ │ └── hook
│ │ ├── CustomHook.java
│ │ └── Hook.java
│ └── test/java/com/liblab
│ └── hook
│ └── CustomHookTest.java
└── pom.xml
java
├── src
│ ├── main/java/com/liblab
│ │ └── hook