|
| 1 | +--- |
| 2 | +type: docs |
| 3 | +title: "How to: Implement pluggable components" |
| 4 | +linkTitle: "Pluggable components" |
| 5 | +weight: 1100 |
| 6 | +description: "Learn how to author and implement pluggable components" |
| 7 | +--- |
| 8 | + |
| 9 | +In this guide, you'll learn why and how to implement a [pluggable component]({{< ref pluggable-components-overview >}}). To learn how to configure and register a pluggable component, refer to [How to: Register a pluggable component]({{< ref pluggable-components-registration.md >}}) |
| 10 | + |
| 11 | +## Implement a pluggable component |
| 12 | + |
| 13 | +In order to implement a pluggable component, you need to implement a gRPC service in the component. Implementing the gRPC service requires three steps: |
| 14 | + |
| 15 | +### Find the proto definition file |
| 16 | + |
| 17 | +Proto definitions are provided for each supported service interface (state store, pub/sub, bindings). |
| 18 | + |
| 19 | +Currently, the following component APIs are supported: |
| 20 | + |
| 21 | +- State stores |
| 22 | +- Pub/sub |
| 23 | +- Bindings |
| 24 | + |
| 25 | +| Component | Type | gRPC definition | Built-in Reference Implementation | Docs | |
| 26 | +| :---------: | :--------: | :--------------: | :----------------------------------------------------------------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 27 | +| State Store | `state` | [state.proto] | [Redis](https://github.com/dapr/components-contrib/tree/master/state/redis) | [concept]({{< ref "state-management-overview" >}}), [howto]({{< ref "howto-get-save-state" >}}), [api spec]({{< ref "state_api" >}}) | |
| 28 | +| Pub/sub | `pubsub` | [pubsub.proto] | [Redis](https://github.com/dapr/components-contrib/tree/master/pubsub/redis) | [concept]({{< ref "pubsub-overview" >}}), [howto]({{< ref "howto-publish-subscribe" >}}), [api spec]({{< ref "pubsub_api" >}}) | |
| 29 | +| Bindings | `bindings` | [bindings.proto] | [Kafka](https://github.com/dapr/components-contrib/tree/master/bindings/kafka) | [concept]({{< ref "bindings-overview" >}}), [input howto]({{< ref "howto-triggers" >}}), [output howto]({{< ref "howto-bindings" >}}), [api spec]({{< ref "bindings_api" >}}) | |
| 30 | + |
| 31 | +Below is a snippet of the gRPC service definition for pluggable component state stores ([state.proto]): |
| 32 | + |
| 33 | +```protobuf |
| 34 | +// StateStore service provides a gRPC interface for state store components. |
| 35 | +service StateStore { |
| 36 | + // Initializes the state store component with the given metadata. |
| 37 | + rpc Init(InitRequest) returns (InitResponse) {} |
| 38 | + // Returns a list of implemented state store features. |
| 39 | + rpc Features(FeaturesRequest) returns (FeaturesResponse) {} |
| 40 | + // Ping the state store. Used for liveness purposes. |
| 41 | + rpc Ping(PingRequest) returns (PingResponse) {} |
| 42 | + |
| 43 | + // Deletes the specified key from the state store. |
| 44 | + rpc Delete(DeleteRequest) returns (DeleteResponse) {} |
| 45 | + // Get data from the given key. |
| 46 | + rpc Get(GetRequest) returns (GetResponse) {} |
| 47 | + // Sets the value of the specified key. |
| 48 | + rpc Set(SetRequest) returns (SetResponse) {} |
| 49 | +
|
| 50 | +
|
| 51 | + // Deletes many keys at once. |
| 52 | + rpc BulkDelete(BulkDeleteRequest) returns (BulkDeleteResponse) {} |
| 53 | + // Retrieves many keys at once. |
| 54 | + rpc BulkGet(BulkGetRequest) returns (BulkGetResponse) {} |
| 55 | + // Set the value of many keys at once. |
| 56 | + rpc BulkSet(BulkSetRequest) returns (BulkSetResponse) {} |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +The interface for the `StateStore` service exposes a total of 9 methods: |
| 61 | + |
| 62 | +- 2 methods for initialization and components capability advertisement (Init and Features) |
| 63 | +- 1 method for health-ness or liveness check (Ping) |
| 64 | +- 3 methods for CRUD (Get, Set, Delete) |
| 65 | +- 3 methods for bulk CRUD operations (BulkGet, BulkSet, BulkDelete) |
| 66 | + |
| 67 | +### Create service scaffolding |
| 68 | + |
| 69 | +Use [protocol buffers and gRPC tools](https://grpc.io) to create the necessary scaffolding for the service. Learn more about these tools via [the gRPC concepts documentation](https://grpc.io/docs/what-is-grpc/core-concepts/). |
| 70 | + |
| 71 | +These tools generate code targeting [any gRPC-supported language](https://grpc.io/docs/what-is-grpc/introduction/#protocol-buffer-versions). This code serves as the base for your server and it provides: |
| 72 | +- Functionality to handle client calls |
| 73 | +- Infrastructure to: |
| 74 | + - Decode incoming requests |
| 75 | + - Execute service methods |
| 76 | + - Encode service responses |
| 77 | + |
| 78 | +The generated code is incomplete. It is missing: |
| 79 | + |
| 80 | +- A concrete implementation for the methods your target service defines (the core of your pluggable component). |
| 81 | +- Code on how to handle Unix Socket Domain integration, which is Dapr specific. |
| 82 | +- Code handling integration with your downstream services. |
| 83 | + |
| 84 | +Learn more about filling these gaps in the next step. |
| 85 | + |
| 86 | +### Define the service |
| 87 | + |
| 88 | +Provide a concrete implementation of the desired service. Each component has a gRPC service definition for its core functionality which is the same as the core component interface. For example: |
| 89 | + |
| 90 | +- **State stores** |
| 91 | + |
| 92 | + A pluggable state store **must** provide an implementation of the `StateStore` service interface. |
| 93 | + |
| 94 | + In addition to this core functionality, some components might also expose functionality under other **optional** services. For example, you can add extra functionality by defining the implementation for a `QueriableStateStore` service and a `TransactionalStateStore` service. |
| 95 | + |
| 96 | +- **Pub/sub** |
| 97 | + |
| 98 | + Pluggable pub/sub components only have a single core service interface defined ([pubsub.proto]). They have no optional service interfaces. |
| 99 | + |
| 100 | +- **Bindings** |
| 101 | + |
| 102 | + Pluggable input and output bindings have a single core service definition on [bindings.proto]. They have no optional service interfaces. |
| 103 | + |
| 104 | +After generating the above state store example's service scaffolding code using gRPC and protocol buffers tools, you can define concrete implementations for the 9 methods defined under `service StateStore`, along with code to initialize and communicate with your dependencies. |
| 105 | + |
| 106 | +This concrete implementation and auxiliary code are the **core** of your pluggable component. They define how your component behaves when handling gRPC requests from Dapr. |
| 107 | + |
| 108 | +## Next steps |
| 109 | + |
| 110 | +- Get started with developing .NET pluggable component using this [sample code](https://github.com/dapr/samples/tree/master/pluggable-components-dotnet-template) |
| 111 | +- [Review the pluggable components overview]({{< ref pluggable-components-overview.md >}}) |
| 112 | +- [Learn how to register your pluggable component]({{< ref pluggable-components-registration >}}) |
0 commit comments