# CRUD Example

A Terraform provider is a plugin that extends Terraform, allowing it to manage external resources such as cloud services. It serves as a mediator between Terraform and external APIs, using the [Terraform Plugin Protocol](https://developer.hashicorp.com/terraform/plugin/terraform-plugin-protocol) for communication.

Terraform providers, built with the [terraform-plugin-framework](https://github.com/hashicorp/terraform-plugin-framework), include:

1. **Resources** and **Data Sources**: described using a Terraform Type Schema, which is a `map[string]Attribute`, where an Attribute could be _Primitive_, _Composite_, or _List_.
2. **Create**, **Read**, **Update** and **Delete** methods: the interface through which the provider interacts with an external resource (usually an API) to reconcile a desired terraform specification with the actual state of the resource.
3. **Plan Validators**: defined to enable the validation of a desired specification at Plan-time, without making API calls to the external resource.
4. **Plan Modifiers**: defined to enable custom semantics around the Terraform Type Schema, and how it is reconciled with the external state to make a Plan.
5. **Resource imports**: defined to enable Terraform Specifications to be generated from existing resources.

## A simple CRUD example

Let's explore how to define a resource and map API operations to Terraform methods using annotations for CRUD actions.

### Defining a Resource

Use `x-speakeasy-entity` to define a resource that you want to use terraform to manage.

```yaml filename="openapi.yaml"
/drinks:
  post:
    x-speakeasy-entity-operation: Drink#create
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Drink"
    responses:
      "200":
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Drink"
/drinks/{id}:
  parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
  get:
    x-speakeasy-entity-operation: Drink#read
    responses:
      "200":
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Drink"
  post:
    x-speakeasy-entity-operation: Drink#update
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Drink"
    responses:
      "200":
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Drink"
  delete:
    x-speakeasy-entity-operation: Drink#delete
    responses:
      "202":
        description: OK
components:
  schemas:
    Drink:
      x-speakeasy-entity: Drink
      type: object
      properties:
        name:
          description: The name of the drink.
          type: string
          examples:
            - Old Fashioned
            - Manhattan
            - Negroni
        type:
          $ref: "#/components/schemas/DrinkType"
        price:
          description: The price of one unit of the drink in US cents.
          type: number
          examples:
            - 1000 # $10.00
            - 1200 # $12.00
            - 1500 # $15.00
      required:
        - name
        - price
```

### Mapping API Operations to Resources Methods

An OpenAPI specification tracks a large list of [`Operation` objects](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#operationObject).

For a Terraform Provider generated by Speakeasy, the key element is the [the `x-speakeasy-entity-operation` annotation](/docs/terraform/customize-terraform/entity-mapping). This annotation clarifies the purpose of each operation in terms of how it affects the associated remote entity.

```yaml filename="openapi.yaml"
/drinks:
  post:
    x-speakeasy-entity-operation: Drink#create
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Drink"
    responses:
      "200":
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Drink"
/drinks/{id}:
  parameters:
    - name: id
      in: path
      required: true
      schema:
        type: string
  get:
    x-speakeasy-entity-operation: Drink#read
    responses:
      "200":
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Drink"
  post:
    x-speakeasy-entity-operation: Drink#update
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Drink"
    responses:
      "200":
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Drink"
  delete:
    x-speakeasy-entity-operation: Drink#delete
    responses:
      "202":
        description: OK
components:
  schemas:
    Drink:
      x-speakeasy-entity: Drink
      type: object
      properties:
        name:
          description: The name of the drink.
          type: string
          examples:
            - Old Fashioned
            - Manhattan
            - Negroni
        id:
          description: The ID of the drink
          readOnly: true
          type: string
        type:
          $ref: "#/components/schemas/DrinkType"
        price:
          description: The price of one unit of the drink in US cents.
          type: number
          examples:
            - 1000 # $10.00
            - 1200 # $12.00
            - 1500 # $15.00
      required:
        - name
        - price
```

## Managing Complex API Semantics with Speakeasy

APIs can have unique semantics not fully described by OpenAPI specs. To address this we have:

1. **Inference Rules**: Automatically derive most API semantics from the OpenAPI spec, with the exception of the `x-speakeasy-entity-operation` annotation.
2. **OpenAPI Extensions**: For more complex cases, use extensions to provide detailed configurations. These extensions are documented in the [Terraform Extensions](/docs/terraform/extensions/) section of this documentation.
3. **Support**: Our engineering team continually updates inference rules and extensions to accommodate new API patterns.

Read more in our [documentation here](/docs/create-terraform), or [view more examples here](/guides).
