Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 101 additions & 7 deletions content/resources/custom/rest_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,82 @@ title = "Create a RESTful custom resource"
weight = 50
+++

<!--
UNRELEASED FEATURES — TO DO BEFORE PUBLISHING
==============================================
Two new DSL methods — `rest_api_endpoint` and `rest_identity_property` — are implemented
in the codebase but not yet available in the stable Chef Infra Client release (v19.2.12).
The sections below that document these methods have been commented out until they ship.

When the next release is published, do the following to restore the full documentation:

1. RESTORE the "Option 1: rest_api_endpoint (recommended)" subsection
(under "## Configure the API endpoint").
Also restore the intro sentence:
"You can configure an API endpoint using either the `rest_api_endpoint` method
or by using Train transport."
replacing the current single-option sentence.

2. RESTORE the "### Why `rest_api_endpoint` is the better choice" subsection
and comparison table (under "## Configure the API endpoint").

3. RESTORE the "## Basic example" section, which shows both methods together.

4. RESTORE the `#### rest_api_endpoint` method reference under "### Methods".

5. RESTORE the `#### rest_identity_property` method reference under "### Methods".
Also restore this sentence in the `rest_api_document` method description:
"If you set `rest_identity_property` instead, `rest_api_document` is autogenerated
and you don't need to set it manually."

6. RESTORE the "### Create a REST resource using `rest_api_endpoint` and
`rest_identity_property`" example under "## Examples".

7. RESTORE the "### Create a custom mapping function with rest_property_map" example
under "## Examples". (The example class uses `rest_identity_property`.)
Also restore the cross-reference link in the `rest_property_map` method description:
"- [Create a custom mapping function](#create-a-custom-mapping-function-with-rest_property_map)"

8. RESTORE the "### Cloud resource with complex mapping" example under "## Examples".

9. RESTORE the "### Query-based resource selection" example under "## Examples".

10. RESTORE the "### Handle paginated API responses" example under "## Examples".

11. RESTORE the "#### Issue: Request going to the wrong URL" troubleshooting item
under "## Troubleshooting".

12. UPDATE the "### Custom headers and authentication" example (under "## More features")
by adding `rest_api_endpoint "https://api.example.com"` back into the class definition,
before `rest_api_collection`. The full class should read:

class Chef::Resource::ApiResource < Chef::Resource
use "core::rest_resource"

rest_api_endpoint "https://api.example.com"
rest_api_collection "/api/v1/resources"
rest_api_document "/api/v1/resources/{id}"
...

13. UPDATE the "### Create a REST resource using the Train transport endpoint" example
(under "## Examples") as follows:
- Restore the original intro sentence:
"The following `api_user` resource omits `rest_api_endpoint`. The base URL is
provided instead by the Chef target mode Train transport. Note that
`rest_api_document` must now be set manually because `rest_identity_property`
can't generate it without a base endpoint."
- Restore the code comment inside the class:
"# No rest_api_endpoint---base URL comes from the Train transport"

14. UPDATE the "### Train transport endpoint" section intro sentence
(under "## Configure the API endpoint") to restore the original:
"Configure the base URL in the Chef target mode transport (Train). The resource
then uses relative paths only, and Train prepends its configured endpoint.
Set the transport endpoint using either a Policyfile or a knife configuration file.
With the endpoint's base URL configured, define the resource's relative paths:"
The existing text under this heading also includes the code comment change from step 13.
-->

The REST resource DSL is a base resource class in Chef Infra Client that allows you to create custom resources that interact with RESTful APIs.
Instead of writing HTTP request handling code from scratch, you can extend this resource to create custom resources that automatically handle API interactions, JSON mapping, and state management.

Expand All @@ -33,8 +109,9 @@ The REST custom resource DSL has the following requirements:

## Configure the API endpoint

You can configure an API endpoint using either the `rest_api_endpoint` method or by using Train transport.
You can configure an API endpoint using Train transport.

<!--
### Option 1: `rest_api_endpoint` (recommended)

Set the base URL directly on the resource class using `rest_api_endpoint`. The resource is then fully self-describing---everything a developer needs to understand what API it talks to lives in one place.
Expand Down Expand Up @@ -64,6 +141,7 @@ GET https://api.example.com/api/v1/users
GET https://api.example.com/api/v1/users/jdoe
POST https://api.example.com/api/v1/users
```
-->

### Train transport endpoint

Expand All @@ -79,7 +157,7 @@ class Chef::Resource::ApiUser < Chef::Resource
resource_name :api_user
provides :api_user

# No rest_api_endpoint: base URL comes from the Train transport
# Base URL comes from the Train transport
rest_api_collection "/api/v1/users"
rest_api_document "/api/v1/users/{username}"

Expand All @@ -90,6 +168,7 @@ class Chef::Resource::ApiUser < Chef::Resource
end
```

<!--
### Why `rest_api_endpoint` is the better choice

When using the Train transport approach, the endpoint is invisible from the resource definition. A developer reading the resource has no way to know which API it targets without searching through Chef configuration files. If a cookbook needs to talk to two different REST APIs, you would need two separate transport configurations.
Expand All @@ -103,7 +182,9 @@ When using the Train transport approach, the endpoint is invisible from the reso
| Each resource can target a different API | Yes | All resources share one transport |
| Resource is self-contained | Yes | Split across two files |
| Easy to test independently | Yes | Requires transport mock |
-->

<!--
## Basic example

This example does the following:
Expand Down Expand Up @@ -157,6 +238,7 @@ api_user "jdoe" do
action :delete
end
```
-->

## Methods and actions

Expand All @@ -167,6 +249,7 @@ The `rest_resource` has the following methods and actions.
The REST resource provides several DSL methods for configuring API interactions.
These methods are called within your custom resource class definition.

<!--
#### `rest_api_endpoint`

This method sets the base URL of the REST API. When set, it's prepended to the collection and document paths to form the complete request URL, making the resource fully self-contained and independent of the Train transport endpoint.
Expand Down Expand Up @@ -207,6 +290,7 @@ rest_api_collection "/api/v1/users"
rest_identity_property :username
# Equivalent to: rest_api_document "/api/v1/users/{username}"
```
-->

#### `rest_api_collection`

Expand Down Expand Up @@ -243,7 +327,7 @@ Parameters:
- `path` (String): URL pattern with optional `{template}` placeholders matching property names
- `first_element_only` (Boolean): If `true`, extracts the first element from an array response. Default is `false`.

If you set `rest_identity_property` instead, `rest_api_document` is autogenerated and you don't need to set it manually.
<!-- If you set `rest_identity_property` instead, `rest_api_document` is autogenerated and you don't need to set it manually. -->

For example:

Expand Down Expand Up @@ -373,7 +457,6 @@ For example:
See the following examples for more information:

- [Use JMESPath expressions to map data](#use-jmespath-expressions-to-map-data-in-a-json-structure)
- [Create a custom mapping function](#create-a-custom-mapping-function-with-rest_property_map)

### Actions

Expand Down Expand Up @@ -424,7 +507,6 @@ Override the `rest_headers` method in your action class to add custom headers su
class Chef::Resource::ApiResource < Chef::Resource
use "core::rest_resource"

rest_api_endpoint "https://api.example.com"
rest_api_collection "/api/v1/resources"
rest_api_document "/api/v1/resources/{id}"

Expand Down Expand Up @@ -503,6 +585,7 @@ end

## Examples

<!--
### Create a REST resource using `rest_api_endpoint` and `rest_identity_property`

The following `api_user` custom resource is fully self-contained.
Expand Down Expand Up @@ -554,10 +637,11 @@ api_user "alice" do
action :configure
end
```
-->

### Create a REST resource using the Train transport endpoint

The following `api_user` resource omits `rest_api_endpoint`. The base URL is provided instead by the Chef target mode Train transport. Note that `rest_api_document` must now be set manually because `rest_identity_property` can't generate it without a base endpoint.
The following `api_user` resource uses the Chef target mode Train transport to provide the base URL. The resource uses relative paths only, and Train prepends its configured endpoint.

```ruby
class Chef::Resource::ApiUser < Chef::Resource
Expand All @@ -566,7 +650,7 @@ class Chef::Resource::ApiUser < Chef::Resource
resource_name :api_user
provides :api_user

# No rest_api_endpoint---base URL comes from the Train transport
# Base URL comes from the Train transport
rest_api_collection "/api/v1/users"
rest_api_document "/api/v1/users/{username}"

Expand Down Expand Up @@ -707,6 +791,7 @@ rest_property_map({
}
```

<!--
### Create a custom mapping function with rest_property_map

For complex transformations that JMESPath can't handle, use custom mapping functions by specifying a symbol in the property map.
Expand Down Expand Up @@ -778,7 +863,9 @@ api_project "mobile-app" do
action :configure
end
```
-->

<!--
### Cloud resource with complex mapping

This resource and recipe create and manage a virtual machine through a cloud provider's REST API.
Expand Down Expand Up @@ -861,7 +948,9 @@ cloud_server "web-01" do
action :configure
end
```
-->

<!--
### Query-based resource selection

This example demonstrates how to use query parameters to identify a unique resource when the API doesn't support path-based resource selection. It also shows how to use `rest_identity_map` when the JSON field names differ from the URI template variable names.
Expand Down Expand Up @@ -907,7 +996,9 @@ dns_record "www.example.com" do
action :configure
end
```
-->

<!--
### Handle paginated API responses

This example demonstrates how to handle paginated API responses in a custom REST resource.
Expand Down Expand Up @@ -966,6 +1057,7 @@ class Chef::Resource::TeamMember < Chef::Resource
end
end
```
-->

## Troubleshooting

Expand Down Expand Up @@ -1018,6 +1110,7 @@ rest_property_map({
})
```

<!--
#### Issue: Request going to the wrong URL

If you are using `rest_api_endpoint`, confirm that the value doesn't include a trailing slash and that `rest_api_collection` starts with `/`. The two are concatenated directly:
Expand All @@ -1027,6 +1120,7 @@ rest_api_endpoint "https://api.example.com" # no trailing slash
rest_api_collection "/api/v1/users" # leading slash required
# Result: https://api.example.com/api/v1/users
```
-->

## Additional resources

Expand Down
Loading