API spec annotations
When liblab generates a Terraform provider from your API spec, it needs to know which endpoints are Terraform resources and which are data sources, amongst other things. This is done by annotating your API spec with special attributes.
These attributes need to be set in addition to the Terraform configuration options in the liblab config file.
attributes
attribute | Type | Applies to | description |
---|---|---|---|
x-liblab-resource | string | Endpoint + Method | Marks an endpoint as a Terraform resource operation |
x-liblab-datasource | string | Endpoint + Method | Marks an endpoint as a Terraform data source operation |
x-liblab-map-to | string | Parameter | Maps a parameter to a field in a schema |
x-liblab-show-diff | bool | Schema property | Marks a field as showing a diff in the Terraform plan even if hideComputedDiff is true |
x-liblab-include | bool | Schema property | Marks an endpoint to be included in the underlying Go SDK |
x-liblab-plan-modifiers | object | Schema property | Marks the property for plan modification |
x-liblab-resource
This annotation marks an endpoint and HTTP method as a Terraform resource operation. The value of the operation is both the resource name, a #
as a separator, and an action. Supported actions are Create
, Read
, Update
, and Delete
.
- JSON
- YAML
"paths": {
"/soda": {
"post": {
"x-liblab-resource": "Soda#Create",
"operationId": "CreateSoda",
...
}
}
}
paths:
/soda:
post:
x-liblab-resource: "Soda#Create"
operationId: CreateSoda
...
For a resource to be generated, it is required to have resources annotated as Create
, Read
and Delete
, with Update
being optional. If you don't have a resource annotated as Update
, the provider will have the RequiresReplace
plan modifier on those resources, which disallows updates and forces the user to delete and recreate the resource.
You can chain multiple actions together on the same endpoint and method by separating them with a comma. For example:
- JSON
- YAML
"paths": {
"/soda": {
"post": {
"x-liblab-resource": "Soda#Create,Update",
"operationId": "UpsertSoda",
...
}
}
}
paths:
/soda:
post:
x-liblab-resource: "Soda#Create,Update"
operationId: UpsertSoda
...
When the resources are generated, they need to be in PascalCase so that they are exported by Go. If your resource names are not in PascalCase, liblab will convert them. For example, if you have x-liblab-resource: "soda-fountain#Create,Update"
, the resource will be generated as SodaFountain
. It is good practice to use PascalCase for the names of your resources in your API spec annotations.
x-liblab-datasource
This annotation marks an endpoint and HTTP method as a Terraform data source operation. The value of the operation is both the resource name, a #
as a separator, and an action. The only supported action is Read
as data sources are read only.
- JSON
- YAML
"paths": {
"/soda-type": {
"get": {
"x-liblab-datasource": "SodaType#Read",
...
}
}
}
paths:
/soda-type:
get:
x-liblab-datasource: "SodaType#Read"
...
x-liblab-map-to
This annotation allows mapping of endpoint parameters to values in the Terraform resource schema. The value of the annotation is the name of the field in the schema. For example:
- JSON
- YAML
"parameters": [
{
"name": "sodaId", // this is just 'id' in the schema
"in": "path",
"x-liblab-map-to": "id"
}
]
parameters:
- name: sodaId # this is just 'id' in the schema
in: path
x-liblab-map-to: id
x-liblab-show-diff
This annotation marks a field as showing a diff in the Terraform plan even if hideComputedDiff
is true
. For example:
- JSON
- YAML
"properties": {
"createdAt": {
"type": "string",
"format": "date-time",
"x-liblab-show-diff": true
}
}
properties:
createdAt:
type: string
format: "date-time",
x-liblab-show-diff: true
This field must be set to true
on fields that are computed on updates if you have hideComputedDiff
set to true
. If this is not set, Terraform will raise an error.
x-liblab-include
This annotation marks an operation to be included in the underlying Go SDK that is generated under internal/client
.
By default, only the endpoints marked with x-liblab-resource
and x-liblab-datasource
are included in the Go SDK to reduce overhead.
This is useful when using resource plan modifiers
to add custom functionality to your provider.
By default, you will have the internal Go SDK available on every resource, under the client
field.
- JSON
- YAML
"paths": {
"/pizza": {
"get": {
"x-liblab-include": true,
"operationId": "GetPizza",
...
}
}
}
paths:
pizza:
get:
x-liblab-include: true
operationId: GetPizza
...
Now you can use the internal Go SDK to call the endpoint from a resource plan modifier:
func (r *SodaResource) ModifyPlan(ctx context.Context,
req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse) {
// Call the API
someResource, err := r.client.PizzaService.GetPizza()
// Have pizza with your soda!
...
}
x-liblab-plan-modifiers
This annotation is used to indicate which custom plan modifiers should be applied to a property. For example, if you have a custom attribute plan modifier to log boolean values with this signature:
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
)
func LogBool() planmodifier.Bool {
return logBool{}
}
type logBool struct{}
func (l logBool) Description(_ context.Context) string {
return "Logs boolean values"
}
func (l logBool) MarkdownDescription(_ context.Context) string {
return "Logs boolean values"
}
func (l logBool) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
// Do some kind of logging here, such as
// logger.Log(fmt.Sprintf("%s bool value: %t", req.Path, req.PlanValue))
return
}
This can then be applied to a property in the schema like so:
- JSON
- YAML
"properties": {
"isCold": {
"type": "boolean",
"x-liblab-plan-modifiers": ["LogBool"]
}
}
properties:
isCold:
type: boolean
x-liblab-plan-modifiers: [LogBool]