dapr apim integration sample

This commit is contained in:
Mark Chmarny 2020-09-21 11:24:23 -07:00
parent 6d4d960c9f
commit 4918cfeb7f
26 changed files with 1387 additions and 0 deletions

16
dapr-apim-integration/.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependencies
vendor
bin

View File

@ -0,0 +1,653 @@
# Dapr & Azure API Management Integration Demo
Dapr integration with [Azure API Management](https://azure.microsoft.com/en-us/services/api-management/) (APIM) using self-hosted gateway on Kubernetes.
![APIM Self-hosted Gateway Overview](img/overview-diagram.png)
In this demo we will walk through the configuration of API Management service and its self-hosted gateway on Kubernetes. To illustrate the Dapr integration we will also review three Dapr use-cases:
* Invocation of a specific Dapr service method
* Publishing content to a Pub/Sub topic
* Binding invocation with request content transformation
In addition, we will overview the use of APIM tracing to debug your configuration.
> While you can accomplish everything we show here in Azure portal, to make this demo easier to reliably reproduce, we will be using only the Azure CLI and APIs.
## Prerequisite
* [Azure account](https://azure.microsoft.com/en-us/free/)
* [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
* [Kubernetes cluster with Dapr](https://github.com/dapr/docs/blob/v0.9.0/getting-started/environment-setup.md#installing-dapr-on-a-kubernetes-cluster)
* [Helm](https://helm.sh/docs/intro/install/)
> Note, this demo has been only tested with v0.10 release of Dapr
## Terminology
You will see a few different APIs being used throughout this demo. At one point we are even going to use one API to manage another (API inception?). Here is short summary to help you keep all these APIs straight. Hope it helps:
* [Azure API](https://docs.microsoft.com/en-us/rest/api/apimanagement/) - this is the API provided by Azure to manage its service (yes, including the API Management Service)
* [API in APIM](https://docs.microsoft.com/en-us/azure/api-management/edit-api) - is the API which we will define in APIM service. Its operations will be used by the users
* [Dapr API](https://github.com/dapr/docs/tree/master/reference/api#dapr-api-reference) - are the RESTful HTTP APIs defined by Dapr which developers interact with building applications
## Setup
To make this demo easier to reproduce, start by exporting the name for your new Azure API Management (APIM) service.
> Note, the name of your API Management service instance has to be globally unique!
```shell
export APIM_SERVICE_NAME="dapr-apim-demo"
```
In addition also export the Azure [Subscription ID](https://docs.bitnami.com/azure/faq/administration/find-subscription-id/) and [Resource Group](https://docs.bitnami.com/azure/faq/administration/find-deployment-resourcegroup-id/) where you want to create that service.
```shell
export AZ_SUBSCRIPTION_ID="your-subscription-id"
export AZ_RESOURCE_GROUP="your-resource-group"
```
## Azure API Management
We will start by configuring the Azure API Management service.
### Service Creation
Create service instance:
> The `publisher-email` and `publisher-name` are only required to receive system notifications e-mails.
```shell
az apim create --name $APIM_SERVICE_NAME \
--subscription $AZ_SUBSCRIPTION_ID \
--resource-group $AZ_RESOURCE_GROUP \
--publisher-email "you@your-domain.com" \
--publisher-name "Your Name"
```
> Note, depending on the SKU and resource group configuration, this operation may take 15+ min. While this running, consider quick read on [API Management Concepts](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#-apis-and-operations)
### API Configuration
Each [API operation](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#-apis-and-operations) defined in APIM will map to one Dapr API. To define these mappings you will use OpenAPI format defined in [apim/api.yaml](./apim/api.yaml) file. You will need to update the OpenAPI file with the name of the APIM service created above:
```yaml
servers:
- url: http://<YOUR-APIM-SERVICE-NAME>.azure-api.net
- url: https://<YOUR-APIM-SERVICE-NAME>.azure-api.net
```
When finished, import that OpenAPI definition fle into APIM service instance:
```shell
az apim api import --path / \
--api-id dapr \
--subscription $AZ_SUBSCRIPTION_ID \
--resource-group $AZ_RESOURCE_GROUP \
--service-name $APIM_SERVICE_NAME \
--display-name "Demo Dapr Service API" \
--protocols http https \
--subscription-required true \
--specification-path apim/api.yaml \
--specification-format OpenApi
```
> Notice the `subscription-required` parameter is set to `true` which means that all invocations against the `dapr` API will need a subscription key. We cover how to obtain the subscription key later.
### Azure API Token
Export the Azure management API token to use through this demo.
```shell
export AZ_API_TOKEN=$(az account get-access-token --resource=https://management.azure.com --query accessToken --output tsv)
```
> If you receive an error later that your token expired, just re-run this command
### Policy Management
APIM [Policies](https://docs.microsoft.com/en-us/azure/api-management/api-management-key-concepts#--policies) are sequentially executed on each request. We will start by defining "global" policy to throttle all operation invocations on our API, then add individual policies for each operation to add specific options.
#### Global Policy
APIM policies are defined inside of inbound, outbound, and backend elements. In our case to apply policy that will rate-limit all requests on all operations (before they are forwarded to Dapr API), we will place the global policy within the `inbound` section.
> Note, the rate limit quota we defined here is being shared across all the replicas of self-hosted gateway. In default configuration, where there are 2 replicas, this policy would actually be half of the permitted calls per minute.
```xml
<policies>
<inbound>
<rate-limit-by-key
calls="120"
renewal-period="60"
increment-condition="@(context.Response.StatusCode == 200)"
counter-key="@(context.Request.IpAddress)" />
</inbound>
...
</policies>
```
Apply that [policy](apim/policy-all.json) to all operations submit it to the Azure management API.
```shell
curl -i -X PUT \
-d @apim/policy-all.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/policies/policy?api-version=2019-12-01"
```
If everything goes well, the management API will return the created policy.
#### Echo Service Policy
The Dapr service invocation handles all the service discovery, so to invoke a specific method on any Dapr service users follow this API:
```http
POST/GET/PUT/DELETE /v1.0/invoke/<appId>/method/<method-name>
```
To enable users to invoke the `echo` method on Dapr service with ID of `echo-service` we will create a policy that inherits the global policy (`<base />`) first, to ensure only authorize service invocation are passed to the backend Dapr API. Then to "map" the invocation we set `dapr` as the "backend-id" and define the Dapr service and method attributes to specific service ID and method name.
```xml
<policies>
<inbound>
<base />
<set-backend-service
backend-id="dapr"
dapr-app-id="echo-service"
dapr-method="echo" />
</inbound>
...
</policies>
```
To apply [this policy](apim/policy-echo.json) to the `echo` operation on our API, submit it to the Azure management API:
```shell
curl -i -X PUT \
-d @apim/policy-echo.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/echo/policies/policy?api-version=2019-12-01"
```
If everything goes well, the management API will return the created policy. Additional information about Dapr Service Invocation in APIM are available [here](https://aka.ms/apim/dapr/invoke).
Also, since the external mapping of the API user invocations to Dapr is done in APIM policy, it can be easily re-mapped to any other version as the API implementation evolves over time.
![](img/backend-policy.png)
#### Message Topic Policy
In addition to Dapr service invocation, APIM can also be used to publish to Dapr Pub/Sub API:
```http
POST /v1.0/publish/<pubsubname>/<topic>
```
To expose the `messages` topic configured in the `demo-events` component we will start by inheriting the global policy like before, and then set the publish policy to format the request that will be passed to the Dapr Pub/Sub API:
```xml
<policies>
<inbound>
<base />
<publish-to-dapr
topic="@("demo-events/messages")"
response-variable-name="pubsub-response"
>@(context.Request.Body.As<string>())</publish-to-dapr>
<return-response
response-variable-name="pubsub-response" />
</inbound>
...
</policies>
```
To apply [this policy](apim/policy-message.json) to the `message` operation on our API, submit it to the Azure management API:
```shell
curl -i -X PUT \
-d @apim/policy-message.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/message/policies/policy?api-version=2019-12-01"
```
If everything goes well, the management API will return the created policy. Additional information about Dapr Pub/Sub support in APIM are available [here](https://aka.ms/apim/dapr/pubsub).
#### Save Binding Policy
In our final case, we are going to overview exposing the Dapr binding API.
```http
POST/PUT /v1.0/bindings/<name>
```
In contrast to the previous policies, rather than just forwarding the original request content, we are going to create a brand new request based on the content of the original request and mapping it to the format expected by Dapr API. This capability comes handy when your API needs to stay the same while the backing service evolves API evolves over time. Consider the payload expected by Dapr binding API:
```json
{
"data": "",
"metadata": {
"": "",
"": ""
},
"operation": ""
}
```
The policy will first define a `key` variable that will be generated using system guid. Once defined, that variable can be used later on in the policy. To accommodate the binding format expected by Dapr, the policy will then set `operation` attribute in APIM `invoke-dapr-binding` policy, and set `metadata` items to:
* `source` which will be a static value indicating the record came from `APIM`
* `client-ip` which will be set to the client request IP
* `key` which will be set to the value of the variable defined above
Finally, for `data`, we simply use the original content of the client request.
```xml
<policies>
<inbound>
<base />
<set-variable name="key"
value="@{ return Guid.NewGuid().ToString(); }" />
<invoke-dapr-binding
name="demo-binding"
operation="create"
response-variable-name="binding-response">
<metadata>
<item key="source">APIM</item>
<item key="client-ip">@( context.Request.IpAddress )</item>
<item key="key">@( (string)context.Variables["key"] )</item>
</metadata>
<data>@( context.Request.Body.As<string>() )</data>
</invoke-dapr-binding>
<return-response response-variable-name="binding-response" />
</inbound>
...
</policies>
```
To apply [this policy](apim/policy-save.json) to the `save` operation on our API, submit it to the Azure management API:
```shell
curl -i -X PUT \
-d @apim/policy-save.json \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/apis/dapr/operations/save/policies/policy?api-version=2019-12-01"
```
> Note, the support in APIM for bindings is still rolling out across Azure regions. You can safely skip this section and just demo service invocation and topic publishing if you receive an error that `invoke-dapr-binding` is not recognize.
If everything goes well, the management API will return the created policy. Additional information about Dapr Binding support in APIM are available [here](https://aka.ms/apim/dapr/bind).
### Gateway Configuration
To create a self-hosted gateway which will be then deployed to the Kubernetes cluster, first, we need to create the `demo-apim-gateway` object in APIM:
```shell
curl -i -X PUT -d '{"properties": {"description": "Dapr Gateway","locationData": {"name": "Virtual"}}}' \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway?api-version=2019-12-01"
```
And then map that gateway to the previously created API:
```shell
curl -i -X PUT -d '{ "properties": { "provisioningState": "created" } }' \
-H "Content-Type: application/json" \
-H "If-Match: *" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway/apis/dapr?api-version=2019-12-01"
```
If everything goes well, the API returns JSON of the created objects.
## Kubernetes
Switching now to the Kubernetes cluster...
### Dependencies
To showcase the ability to expose Dapr pub/sub and binding APIs in APIM, we are going to need [Dapr components](https://github.com/dapr/docs/tree/master/concepts#components) configured on the cluster.
> Note, while Dapr supports some 75+ different components, to keep things simple in this demo we will use Redis as both pub/sub and binding backing service
Start with adding the Redis repo to your Helm charts:
```shell
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
```
And install Redis and wait for the deployment to complete:
> Note, for simplicity, we are deploying everything into the `default` namespace.
```shell
helm install redis bitnami/redis
kubectl rollout status statefulset.apps/redis-master
kubectl rollout status statefulset.apps/redis-slave
```
### Dapr Components
Dapr's modular design means that we can easily extend its functionality using [components](https://github.com/dapr/docs/tree/master/concepts#components). The specific implementation for these components which can be any number of the readily available Dapr building blocks is done in configuration. That means that it's also easy to swap or reconfigure them at runtime without the need to modify your code.
![](img/dapr-building-blocks.png)
To create the binding component to point to the above created Redis cluster the configuration looks like this:
```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: demo-events
spec:
type: pubsub.redis
metadata:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
- name: allowedTopics
value: "messages"
```
Notice we are using the secret created by Redis for password so that our configuration doesn't include any secure information. We also specify that only the `messages` topic should be supported in this case.
To apply these component configurations run:
```shell
kubectl apply -f k8s/pubsub.yaml
kubectl apply -f k8s/binding.yaml
```
### Dapr Services
To deploy your application as a Dapr service all you need to do is augment your Kubernetes deployment template with few Dapr annotations.
```yaml
annotations:
dapr.io/enabled: "true"
dapr.io/id: "event-subscriber"
dapr.io/port: "8080"
```
> To learn more about Kubernetes sidecar configuration see [Dapr docs](https://github.com/dapr/docs/blob/master/concepts/configuration/README.md#kubernetes-sidecar-configuration).
For this demo we will use pre-build Docker images of two applications: [gRPC Echo Service](src/grpc-echo-service) and [HTTP Event Subscriber](src/http-event-subscriber). The Kubernetes deployment files for both of these are located here:
* [k8s/echo-service.yaml](k8s/echo-service.yaml)
* [k8s/event-subscriber.yaml](k8s/event-subscriber.yaml)
Deploy both of these and check that it is ready:
```shell
kubectl apply -f k8s/echo-service.yaml
kubectl apply -f k8s/event-subscriber.yaml
kubectl get pods -l demo=dapr-apim -w
```
> Service is ready when its status is `Running` and the ready column is `2/2` (Dapr and our echo service containers both started)
```shell
NAME READY STATUS RESTARTS AGE
echo-service-668986b998-v2ssp 2/2 Running 0 10m
event-subscriber-7d68b67d9d-5v7bf 2/2 Running 0 10m
```
To make sure that the event subscriber connects to the Redis service you can query the service logs
```shell
kubectl logs -l app=event-subscriber -c daprd | grep demo-events
```
You should see entries containing:
```shell
app responded with subscriptions [{demo-events messages /messages map[]}]
app is subscribed to the following topics: [messages] through pubsub=demo-events
subscribing to topic=messages on pubsub=demo-events
```
### Self-hosted APIM Gateway
To connect the [self-hosted gateway](https://docs.microsoft.com/en-us/azure/api-management/how-to-deploy-self-hosted-gateway-kubernetes) to [APIM service on Kubernetes](https://docs.microsoft.com/en-us/azure/api-management/api-management-kubernetes), we will need to create a secret with the APIM gateway key. Start by getting the key which your gateway will use to connect to from APIM:
> Note, the maximum validity for access tokens is 30 days. Update the below `expiry` parameter to be withing 30 days from today
```shell
curl -i -X POST -d '{ "keyType": "primary", "expiry": "2020-10-10T00:00:01Z" }' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/gateways/demo-apim-gateway/generateToken?api-version=2019-12-01"
```
Copy the content of `value` from the response and create a secret:
```shell
kubectl create secret generic demo-apim-gateway-token --type Opaque --from-literal value="GatewayKey paste-the-key-here"
```
> Make sure the secret includes the `GatewayKey` and a space ` ` as well as the value of your token (e.g. `GatewayKey a1b2c3...`)
Now, create a config map containing the APIM service endpoint that will be used to configure your self-hosted gateway:
```shell
kubectl create configmap demo-apim-gateway-env --from-literal \
"config.service.endpoint=https://${APIM_SERVICE_NAME}.management.azure-api.net/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}?api-version=2019-12-01"
```
And finally, deploy the gateway and check that it's ready:
```shell
kubectl apply -f k8s/gateway.yaml
kubectl get pods -l app=demo-apim-gateway
```
> Note, the self-hosted gateway is deployed with 2 replicas to ensure availability during upgrades.
Make sure both instances have status `Running` and container is ready `2/2` (gateway container + Dapr side-car).
```shell
NAME READY STATUS RESTARTS AGE
demo-apim-gateway-6dfb968f5c-cb4t7 2/2 Running 0 26s
demo-apim-gateway-6dfb968f5c-gxrrq 2/2 Running 0 26s
```
To check on the gateway logs:
```shell
kubectl logs -l app=demo-apim-gateway -c demo-apim-gateway
```
## Usage (API Test)
With APIM configured and self-hosted gateway deployed we are ready to test. Start by capturing the cluster load balancer ingress IP:
```shell
export GATEWAY_IP=$(kubectl get svc demo-apim-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
```
### API Subscription Key
All of the APIs we defined in this demo are protected with subscription key. To invoke them, we will first need a subscription key:
```shell
curl -i -H POST -d '{}' -H "Authorization: Bearer ${AZ_API_TOKEN}" \
"https://management.azure.com/subscriptions/${AZ_SUBSCRIPTION_ID}/resourceGroups/${AZ_RESOURCE_GROUP}/providers/Microsoft.ApiManagement/service/${APIM_SERVICE_NAME}/subscriptions/master/listSecrets?api-version=2019-12-01"
```
The response will include both the primary and secondary keys. Copy one of them and export so we can use it for the rest of the demo:
```shell
export AZ_API_SUB_KEY="your-api-subscription-key"
```
### Service Invocation
To invoke the backing gRPC service over Dapr API exposed by APIM run:
```shell
curl -i -X POST -d '{ "message": "hello" }' \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
-H "Ocp-Apim-Trace: true" \
"http://${GATEWAY_IP}/echo"
```
If everything is configured correctly, you should see the response from your backing Dapr service:
```json
{ "message": "hello" }
```
In addition, you can also check the `echo-service` logs:
```shell
kubectl logs -l app=echo-service -c service
```
### Message Publishing
To post a message to the Dapr Pub/Sub API exposed on APIM run:
```shell
curl -i -X POST \
-d '{ "content": "hello" }' \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
-H "Ocp-Apim-Trace: true" \
"http://${GATEWAY_IP}/message"
```
If everything is configured correctly, you will see `200` status code in the header, indicating the message was successfully delivered to the Dapr API.
You can also check the `event-subscriber` logs:
```shell
kubectl logs -l app=event-subscriber -c service
```
There should be an entry similar to this:
```shell
event - PubsubName:demo-events, Topic:messages, ID:24f0e6f0-ab29-4cd6-8617-6c6c36ac1171, Data: map[message:hello]
```
### Binding Invocation
To save a record into database using the Dapr binding API exposed by APIM run:
```shell
curl -i -X POST \
-d '{"city":"PDX","time":"1600171062","metric":"aqi","value": 457}' \
-H "Content-Type: application/json" \
-H "Ocp-Apim-Subscription-Key: ${AZ_API_SUB_KEY}" \
-H "Ocp-Apim-Trace: true" \
"http://${GATEWAY_IP}/save"
```
If everything is configured correctly, you will see `200` status code in the header indicating the binding was successfully triggered on the Dapr API and our record successfully saved into the DB.
### Debugging
Notice in each one of our API invocations we have been including the `Ocp-Apim-Trace: true` header parameter. APIM provides an ability to trace requests across the policy execution chain which is helpful in debugging your policy. The response of each one fo the above invocation includes the `Ocp-Apim-Trace-Location` header parameter. Just paste the value of that parameter into your browser to see the full trace stack in JSON. The trace can get pretty long so here are few Dapr-specific snippets:
```json
...
{
"source": "request-forwarder",
"timestamp": "2020-09-11T11:15:52.9405903Z",
"elapsed": "00:00:00.1382166",
"data": {
"message": "Request is being forwarded to the backend service. Timeout set to 300 seconds",
"request": {
"method": "POST",
"url": "http://localhost:3500/v1.0/publish/demo-events/messages"
}
}
},
{
"source": "publish-to-dapr",
"timestamp": "2020-09-11T11:15:53.1899121Z",
"elapsed": "00:00:00.3875400",
"data": {
"response": {
"status": {
"code": 200,
"reason": "OK"
},
"headers": [
{
"name": "Server",
"value": "fasthttp"
},
{
"name": "Date",
"value": "Fri, 11 Sep 2020 11:15:52 GMT"
},
{
"name": "Content-Length",
"value": "0"
},
{
"name": "Traceparent",
"value": "00-5b1f0bdfc2191742a4635a906359a7aa-196f5df2e977b00a-01"
}
]
}
}
}
...
```
## Updating Dapr Components
If you updated components after deploying the gateway you will need to restart the deployments:
```shell
kubectl rollout restart deployment/event-subscriber
kubectl rollout status deployment/event-subscriber
kubectl rollout restart deployment/demo-apim-gateway
kubectl rollout status deployment/demo-apim-gateway
```
To check if the components were registered correctly in Dapr, inspect the `daprd` logs in `demo-apim-gateway` pod for `demo-events` and `demo-binding`:
```shell
kubectl logs -l app=demo-apim-gateway -c daprd --tail=200
```
## Summary
This demo illustrated how to setup the APIM service and deploy the self-hosted gateway into your cluster. Using this gateway you can mange access to any number of Dapr services hosted on Kubernetes. You can find out more about all the features of APIM (e.g. Discovery, Caching, Logging etc.) [here](https://azure.microsoft.com/en-us/services/api-management/).
## Cleanup
```shell
kubectl delete -f k8s/gateway.yaml
kubectl delete secret demo-apim-gateway-token
kubectl delete configmap demo-apim-gateway-env
kubectl delete -f k8s/echo-service.yaml
kubectl delete -f k8s/event-subscriber.yaml
kubectl delete -f k8s/pubsub.yaml
kubectl delete -f k8s/binding.yaml
az apim delete --name $APIM_SERVICE_NAME --no-wait --yes
```

View File

@ -0,0 +1,50 @@
openapi: 3.0.1
info:
title: dapr
version: '1.0'
servers:
- url: http://dapr-apim-demo.azure-api.net
- url: https://dapr-apim-demo.azure-api.net
paths:
/echo:
post:
summary: Echo Service
description: Invoke service using Dapr API
operationId: echo
requestBody:
content:
application/json:
example:
message: hello
responses:
'200':
description: ''
/message:
post:
summary: Message Topic
description: Post to topic using Dapr API
operationId: message
requestBody:
content:
application/json:
example:
content: hello
responses:
'200':
description: ''
/save:
post:
summary: DB Binding
description: DB binding using Dapr API
operationId: save
requestBody:
content:
application/json:
example:
city: PDX,
time: 1600171062
metric: aqi
value: 457
responses:
'200':
description: ''

View File

@ -0,0 +1,6 @@
{
"properties": {
"format": "xml",
"value": "<policies><inbound><rate-limit-by-key calls=\"120\" renewal-period=\"60\" increment-condition=\"@(context.Response.StatusCode == 200)\" counter-key=\"@(context.Request.IpAddress)\" /></inbound><backend><forward-request /></backend><outbound /><on-error /></policies>"
}
}

View File

@ -0,0 +1,6 @@
{
"properties": {
"format": "xml",
"value": "<policies><inbound><base /><set-backend-service backend-id=\"dapr\" dapr-app-id=\"echo-service\" dapr-method=\"echo\" /></inbound><backend><base /></backend><outbound></outbound><on-error><base /></on-error></policies>"
}
}

View File

@ -0,0 +1,6 @@
{
"properties": {
"format": "xml",
"value": "<policies><inbound><base /><publish-to-dapr topic=\"@(&quot;demo-events/messages&quot;)\" response-variable-name=\"pubsub-response\">@( context.Request.Body.As&lt;string&gt;() )</publish-to-dapr><return-response response-variable-name=\"pubsub-response\" /></inbound><backend /><outbound><base /></outbound><on-error><base /></on-error></policies>"
}
}

View File

@ -0,0 +1,6 @@
{
"properties": {
"format": "xml",
"value": "<policies><inbound><base /><set-variable name=\"key\" value=\"@{ return Guid.NewGuid().ToString(); }\" /><invoke-dapr-binding name=\"demo-binding\" operation=\"create\" response-variable-name=\"binding-response\"><metadata><item key=\"source\">APIM</item><item key=\"client-ip\">@( context.Request.IpAddress )</item><item key=\"key\">@( (string)context.Variables[\"key\"] )</item></metadata><data>@( context.Request.Body.As&lt;string&gt;() )</data></invoke-dapr-binding><return-response response-variable-name=\"binding-response\" /></inbound><backend /><outbound><base /></outbound><on-error><base /></on-error></policies>"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

View File

@ -0,0 +1,13 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: demo-binding
spec:
type: bindings.redis
metadata:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password

View File

@ -0,0 +1,35 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-service
labels:
app: echo-service
demo: dapr-apim
spec:
replicas: 1
selector:
matchLabels:
app: echo-service
template:
metadata:
labels:
app: echo-service
demo: dapr-apim
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "echo-service"
dapr.io/app-protocol: "grpc"
dapr.io/app-port: "60002"
dapr.io/config: "tracing"
dapr.io/log-as-json: "true"
dapr.io/log-level: "debug"
spec:
containers:
- name: service
image: mchmarny/grpc-echo-service:v0.14.0
imagePullPolicy: Always
ports:
- containerPort: 60002
env:
- name: ADDRESS
value: ":60002"

View File

@ -0,0 +1,36 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: event-subscriber
labels:
app: event-subscriber
demo: dapr-apim
spec:
selector:
matchLabels:
app: event-subscriber
template:
metadata:
labels:
app: event-subscriber
demo: dapr-apim
annotations:
dapr.io/enabled: "true"
dapr.io/id: "event-subscriber"
dapr.io/port: "8080"
dapr.io/config: "tracing"
dapr.io/log-as-json: "true"
dapr.io/log-level: "debug"
spec:
containers:
- name: service
image: mchmarny/http-event-subscriber:v0.14.0
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
- name: PUBSUB_NAME
value: "demo-events"
- name: TOPIC_NAME
value: "messages"

View File

@ -0,0 +1,71 @@
# NOTE: Before deploying to a production environment, please review the documentation -> https://aka.ms/self-hosted-gateway-production
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-apim-gateway
spec:
replicas: 2
selector:
matchLabels:
app: demo-apim-gateway
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 25%
template:
metadata:
labels:
app: demo-apim-gateway
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "demo-apim-gateway"
dapr.io/config: "tracing"
dapr.io/log-as-json: "true"
dapr.io/log-level: "debug"
spec:
terminationGracePeriodSeconds: 60
containers:
- name: demo-apim-gateway
image: mcr.microsoft.com/azure-api-management/gateway:beta
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8081
readinessProbe:
httpGet:
path: /internal-status-0123456789abcdef
port: http
scheme: HTTP
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 3
successThreshold: 1
env:
- name: config.service.auth
valueFrom:
secretKeyRef:
name: demo-apim-gateway-token
key: value
envFrom:
- configMapRef:
name: demo-apim-gateway-env
---
apiVersion: v1
kind: Service
metadata:
name: demo-apim-gateway
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8081
selector:
app: demo-apim-gateway

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: demo-events
spec:
type: pubsub.redis
metadata:
- name: redisHost
value: redis-master.default.svc.cluster.local:6379
- name: redisPassword
secretKeyRef:
name: redis
key: redis-password
- name: allowedTopics
value: "messages"

View File

@ -0,0 +1,14 @@
FROM golang:1.15.0 as builder
WORKDIR /src/
COPY . /src/
ENV GO111MODULE=on
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -a -tags netgo -mod vendor -o ./service .
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /src/service .
ENTRYPOINT ["./service"]

View File

@ -0,0 +1,56 @@
RELEASE_VERSION =v0.14.0
SERVICE_NAME ?=grpc-echo-service
DOCKER_USERNAME ?=$(DOCKER_USER)
.PHONY: all
all: help
.PHONY: tidy
tidy: ## Updates the go modules and vendors all dependencies
go mod tidy
go mod vendor
.PHONY: test
test: tidy ## Tests the entire project
go test -count=1 -race ./...
.PHONY: run
run: tidy ## Runs uncompiled code in Dapr
dapr run \
--app-id $(SERVICE_NAME) \
--app-port 60002 \
--app-protocol grpc \
--dapr-http-port 3500 \
go run main.go
.PHONY: invoke
invoke: ## Invokes service through Dapr API
curl -d '{ "message": "ping" }' \
-H "Content-type: application/json" \
"http://localhost:3500/v1.0/invoke/$(SERVICE_NAME)/method/echo"
.PHONY: image
image: tidy ## Builds and publish docker image
docker build -t "$(DOCKER_USERNAME)/$(SERVICE_NAME):$(RELEASE_VERSION)" .
docker push "$(DOCKER_USERNAME)/$(SERVICE_NAME):$(RELEASE_VERSION)"
.PHONY: lint
lint: ## Lints the entire project
golangci-lint run --timeout=3m
.PHONY: tag
tag: ## Creates release tag
git tag $(RELEASE_VERSION)
git push origin $(RELEASE_VERSION)
.PHONY: clean
clean: ## Cleans up generated files
go clean
rm -fr ./bin
rm -fr ./vendor
.PHONY: help
help: ## Display available commands
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk \
'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -0,0 +1,5 @@
module github.com/dapr/samples/dapr-apim-integration
go 1.15
require github.com/dapr/go-sdk v0.10.0

View File

@ -0,0 +1,100 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dapr/go-sdk v0.10.0 h1:SzQtNf2yRNtU8xVOcuTqzyOv+NDWCrqeTdJD6TDKQHk=
github.com/dapr/go-sdk v0.10.0/go.mod h1:62T7zLYXKaIBw+aawzVBIJX2CesGeUHg9C6EWpwiKLw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed h1:WBkVNH1zd9jg/dK4HCM4lNANnmd12EHC9z+LmcCG4ns=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200808173500-a06252235341 h1:Kceb+1TNS2X7Cj/A+IUTljNerF/4wOFjlFJ0RGHYKKE=
google.golang.org/genproto v0.0.0-20200808173500-a06252235341/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,55 @@
package main
import (
"context"
"log"
"os"
"strings"
"github.com/dapr/go-sdk/service/common"
daprd "github.com/dapr/go-sdk/service/grpc"
)
var (
logger = log.New(os.Stdout, "", 0)
serviceAddress = getEnvVar("ADDRESS", ":60002")
)
func main() {
// create serving server
s, err := daprd.NewService(serviceAddress)
if err != nil {
log.Fatalf("failed to start the server: %v", err)
}
// add handler to the service
s.AddServiceInvocationHandler("echo", echoHandler)
// start the server to handle incoming events
log.Printf("starting server at %s...", serviceAddress)
if err := s.Start(); err != nil {
log.Fatalf("server error: %v", err)
}
}
func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) {
logger.Printf(
"Invocation (ContentType:%s, Verb:%s, QueryString:%s, Data:%s)",
in.ContentType, in.Verb, in.QueryString, string(in.Data),
)
// TODO: implement handling logic here
out = &common.Content{
ContentType: in.ContentType,
Data: in.Data,
}
return
}
func getEnvVar(key, fallbackValue string) string {
if val, ok := os.LookupEnv(key); ok {
return strings.TrimSpace(val)
}
return fallbackValue
}

View File

@ -0,0 +1,14 @@
FROM golang:1.15.0 as builder
WORKDIR /src/
COPY . /src/
ENV GO111MODULE=on
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -a -tags netgo -mod vendor -o ./service .
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /src/service .
ENTRYPOINT ["./service"]

View File

@ -0,0 +1,58 @@
RELEASE_VERSION =v0.14.0
SERVICE_NAME ?=http-event-subscriber
DOCKER_USERNAME ?=$(DOCKER_USER)
.PHONY: tidy test debug build run jsonevent xmlevent binevent image lint clean tag
all: help
tidy: ## Updates the go modules and vendors all dependencies
go mod tidy
go mod vendor
test: tidy ## Tests the entire project
go test -count=1 -race ./...
debug: tidy ## Runs uncompiled code in Dapr
dapr run \
--app-id $(SERVICE_NAME) \
--app-port 8080 \
--app-protocol http \
--dapr-http-port 3500 \
--components-path ./config \
--log-level debug \
go run main.go
jsonevent: ## Publishes sample JSON message to Dapr pubsub API
curl -d '{ "from": "John", "to": "Lary", "message": "hi" }' \
-H "Content-type: application/json" \
"http://localhost:3500/v1.0/publish/http-events/messages"
xmlevent: ## Publishes sample XML message to Dapr pubsub API
curl -d '<message><from>John</from><to>Lary</to></message>' \
-H "Content-type: application/xml" \
"http://localhost:3500/v1.0/publish/http-events/messages"
binevent: ## Publishes sample binary message to Dapr pubsub API
curl -d '0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40' \
-H "Content-type: application/octet-stream" \
"http://localhost:3500/v1.0/publish/http-events/messages"
image: tidy ## Builds and publishes docker image
docker build -t "$(DOCKER_USERNAME)/$(SERVICE_NAME):$(RELEASE_VERSION)" .
docker push "$(DOCKER_USERNAME)/$(SERVICE_NAME):$(RELEASE_VERSION)"
lint: ## Lints the entire project
golangci-lint run --timeout=3m
tag: ## Creates release tag
git tag $(RELEASE_VERSION)
git push origin $(RELEASE_VERSION)
clean: ## Cleans up generated files
go clean
rm -fr ./bin
rm -fr ./vendor
help: ## Display available commands
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk \
'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -0,0 +1,11 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: http-events
spec:
type: pubsub.redis
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""

View File

@ -0,0 +1,5 @@
module github.com/dapr/samples/dapr-apim-integration
go 1.15
require github.com/dapr/go-sdk v0.10.0

View File

@ -0,0 +1,96 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dapr/go-sdk v0.10.0 h1:SzQtNf2yRNtU8xVOcuTqzyOv+NDWCrqeTdJD6TDKQHk=
github.com/dapr/go-sdk v0.10.0/go.mod h1:62T7zLYXKaIBw+aawzVBIJX2CesGeUHg9C6EWpwiKLw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200808173500-a06252235341/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,60 @@
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"strings"
"github.com/dapr/go-sdk/service/common"
daprd "github.com/dapr/go-sdk/service/http"
)
var (
logger = log.New(os.Stdout, "", 0)
address = getEnvVar("ADDRESS", ":8080")
pubSubName = getEnvVar("PUBSUB_NAME", "http-events")
topicName = getEnvVar("TOPIC_NAME", "messages")
)
func main() {
// create a Dapr service
s := daprd.NewService(address)
// add some topic subscriptions
subscription := &common.Subscription{
PubsubName: pubSubName,
Topic: topicName,
Route: fmt.Sprintf("/%s", topicName),
}
if err := s.AddTopicEventHandler(subscription, eventHandler); err != nil {
logger.Fatalf("error adding topic subscription: %v", err)
}
// start the service
if err := s.Start(); err != nil && err != http.ErrServerClosed {
logger.Fatalf("error starting service: %v", err)
}
}
func eventHandler(ctx context.Context, e *common.TopicEvent) error {
logger.Printf(
"event - PubsubName:%s, Topic:%s, ID:%s, Data: %v",
e.PubsubName, e.Topic, e.ID, e.Data,
)
// TODO: do something with the cloud event data
return nil
}
func getEnvVar(key, fallbackValue string) string {
if val, ok := os.LookupEnv(key); ok {
return strings.TrimSpace(val)
}
return fallbackValue
}