Simple webhook system written in golang.
Let's start with the basic concepts, we have three main entities that we must know to start:
To run the server it is necessary to have a database available from postgresql, in this example we will consider that we have a database called hammer running in localhost with user and password equal to user.
docker run --env HAMMER_DATABASE_URL='postgres://user:pass@localhost:5432/hammer?sslmode=disable' allisson/hammer migrate # run database migrations
docker run -p 4001:4001 -p 8000:8000 -p 9000:9000 -p 50051:50051 --env HAMMER_DATABASE_URL='postgres://user:pass@localhost:5432/hammer?sslmode=disable' allisson/hammer server # run grpc/http/metrics servers
git clone https://github.com/allisson/hammer
cd hammer
cp local.env .env # and edit .env
make run-migrate # create database schema
make run-server # run the server (grpc + http)
We are using curl in the examples below.
curl -X POST 'http://localhost:8000/v1/topics' \
--header 'Content-Type: application/json' \
--data-raw '{
"topic": {
"id": "topic",
"name": "Topic"
}
}'
{
"id": "topic",
"name": "Topic",
"created_at": "2021-03-18T11:08:49.678732Z",
"updated_at": "2021-03-18T11:08:49.678732Z"
}
The max_delivery_attempts, delivery_attempt_delay and delivery_attempt_timeout are in seconds.
curl -X POST 'http://localhost:8000/v1/subscriptions' \
--header 'Content-Type: application/json' \
--data-raw '{
"subscription": {
"id": "httpbin-post",
"topic_id": "topic",
"name": "Httpbin Post",
"url": "https://httpbin.org/post",
"secret_token": "my-super-secret-token",
"max_delivery_attempts": 5,
"delivery_attempt_delay": 60,
"delivery_attempt_timeout": 5
}
}'
{
"id": "httpbin-post",
"topic_id": "topic",
"name": "Httpbin Post",
"url": "https://httpbin.org/post",
"secret_token": "my-super-secret-token",
"max_delivery_attempts": 5,
"delivery_attempt_delay": 60,
"delivery_attempt_timeout": 5,
"created_at": "2021-03-18T11:10:05.855296Z",
"updated_at": "2021-03-18T11:10:05.855296Z"
}
curl -X POST 'http://localhost:8000/v1/messages' \
--header 'Content-Type: application/json' \
--data-raw '{
"message": {
"topic_id": "topic",
"content_type": "application/json",
"data": "{\"name\": \"Allisson\"}"
}
}'
{
"id": "01F12GF6VAXGNHVXM4YT37N75A",
"topic_id": "topic",
"content_type": "application/json",
"data": "eyJuYW1lIjogIkFsbGlzc29uIn0=",
"created_at": "2021-03-18T11:10:29.738632Z"
}
The system will send a post request and the server must respond with the following status codes for the delivery to be considered successful: 200, 201, 202 and 204.
docker run --env HAMMER_DATABASE_URL='postgres://user:pass@localhost:5432/hammer?sslmode=disable' allisson/hammer worker
{"level":"info","ts":1616065862.332101,"caller":"service/worker.go:67","msg":"worker-started"}
{"level":"info","ts":1616065863.104438,"caller":"service/worker.go:36","msg":"worker-delivery-attempt-created","id":"01F12GG6NWZR03MW1MFMQDWVVF","delivery_id":"01F12GF6VM4YSX5GW8TM4781EZ","response_status_code":200,"execution_duration":749,"success":true}
make run-worker
go run cmd/worker/main.go
{"level":"info","ts":1616065862.332101,"caller":"service/worker.go:67","msg":"worker-started"}
{"level":"info","ts":1616065863.104438,"caller":"service/worker.go:36","msg":"worker-delivery-attempt-created","id":"01F12GG6NWZR03MW1MFMQDWVVF","delivery_id":"01F12GF6VM4YSX5GW8TM4781EZ","response_status_code":200,"execution_duration":749,"success":true}
Submitted payload (Compatible with JSON Event Format for CloudEvents - Version 1.0):
{
"data_base64": "eyJuYW1lIjogIkFsbGlzc29uIn0=",
"datacontenttype": "application/json",
"id": "01F12GF6VM4YSX5GW8TM4781EZ",
"messageid": "01F12GF6VAXGNHVXM4YT37N75A",
"secrettoken": "my-super-secret-token",
"source": "/v1/messages/01F12GF6VAXGNHVXM4YT37N75A",
"specversion": "1.0",
"subscriptionid": "httpbin-post",
"time": "2021-03-18T11:10:29.748978Z",
"topicid": "topic",
"type": "hammer.message.created"
}
curl -X GET http://localhost:8000/v1/deliveries/01F12GF6VM4YSX5GW8TM4781EZ
{
"id": "01F12GF6VM4YSX5GW8TM4781EZ",
"topic_id": "topic",
"subscription_id": "httpbin-post",
"message_id": "01F12GF6VAXGNHVXM4YT37N75A",
"content_type": "application/json",
"data": "eyJuYW1lIjogIkFsbGlzc29uIn0=",
"url": "https://httpbin.org/post",
"secret_token": "my-super-secret-token",
"max_delivery_attempts": 5,
"delivery_attempt_delay": 60,
"delivery_attempt_timeout": 5,
"scheduled_at": "2021-03-18T11:10:29.748978Z",
"delivery_attempts": 1,
"status": "completed",
"created_at": "2021-03-18T11:10:29.748978Z",
"updated_at": "2021-03-18T11:11:03.098648Z"
}
The execution_duration are in milliseconds.
curl -X GET http://localhost:8000/v1/delivery-attempts/01F12GG6NWZR03MW1MFMQDWVVF
{
"id": "01F12GG6NWZR03MW1MFMQDWVVF",
"delivery_id": "01F12GF6VM4YSX5GW8TM4781EZ",
"request": "POST /post HTTP/1.1\r\nHost: httpbin.org\r\nContent-Type: application/json\r\n\r\n{\"specversion\":\"1.0\",\"type\":\"hammer.message.created\",\"source\":\"/v1/messages/01F12GF6VAXGNHVXM4YT37N75A\",\"id\":\"01F12GF6VM4YSX5GW8TM4781EZ\",\"time\":\"2021-03-18T11:10:29.748978Z\",\"secrettoken\":\"my-super-secret-token\",\"messageid\":\"01F12GF6VAXGNHVXM4YT37N75A\",\"subscriptionid\":\"httpbin-post\",\"topicid\":\"topic\",\"datacontenttype\":\"application/json\",\"data_base64\":\"eyJuYW1lIjogIkFsbGlzc29uIn0=\"}",
"response": "HTTP/2.0 200 OK\r\nContent-Length: 1298\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/json\r\nDate: Thu, 18 Mar 2021 11:11:03 GMT\r\nServer: gunicorn/19.9.0\r\n\r\n{\n \"args\": {}, \n \"data\": \"{\\\"specversion\\\":\\\"1.0\\\",\\\"type\\\":\\\"hammer.message.created\\\",\\\"source\\\":\\\"/v1/messages/01F12GF6VAXGNHVXM4YT37N75A\\\",\\\"id\\\":\\\"01F12GF6VM4YSX5GW8TM4781EZ\\\",\\\"time\\\":\\\"2021-03-18T11:10:29.748978Z\\\",\\\"secrettoken\\\":\\\"my-super-secret-token\\\",\\\"messageid\\\":\\\"01F12GF6VAXGNHVXM4YT37N75A\\\",\\\"subscriptionid\\\":\\\"httpbin-post\\\",\\\"topicid\\\":\\\"topic\\\",\\\"datacontenttype\\\":\\\"application/json\\\",\\\"data_base64\\\":\\\"eyJuYW1lIjogIkFsbGlzc29uIn0=\\\"}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Accept-Encoding\": \"gzip\", \n \"Content-Length\": \"386\", \n \"Content-Type\": \"application/json\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"Go-http-client/2.0\", \n \"X-Amzn-Trace-Id\": \"Root=1-60533547-501c866f62e44ea3736dbc0c\"\n }, \n \"json\": {\n \"data_base64\": \"eyJuYW1lIjogIkFsbGlzc29uIn0=\", \n \"datacontenttype\": \"application/json\", \n \"id\": \"01F12GF6VM4YSX5GW8TM4781EZ\", \n \"messageid\": \"01F12GF6VAXGNHVXM4YT37N75A\", \n \"secrettoken\": \"my-super-secret-token\", \n \"source\": \"/v1/messages/01F12GF6VAXGNHVXM4YT37N75A\", \n \"specversion\": \"1.0\", \n \"subscriptionid\": \"httpbin-post\", \n \"time\": \"2021-03-18T11:10:29.748978Z\", \n \"topicid\": \"topic\", \n \"type\": \"hammer.message.created\"\n }, \n \"origin\": \"191.33.94.128\", \n \"url\": \"https://httpbin.org/post\"\n}\n",
"response_status_code": 200,
"execution_duration": 749,
"success": true,
"created_at": "2021-03-18T11:11:03.091808Z"
}
All environment variables is defined on file local.env.
docker build -f Dockerfile -t hammer .
Default port: 8000
curl --location --request GET 'http://localhost:8000/v1/topics'
To disable the rest api, set the environment variable HAMMER_REST_API_ENABLED to false.
export HAMMER_REST_API_ENABLED='false'
Default port: 4001
curl --location --request GET 'http://localhost:4001/metrics'
To disable prometheus metrics, set the environment variable HAMMER_METRICS_ENABLED to false.
export HAMMER_METRICS_ENABLED='false'
Default port: 9000
curl --location --request GET 'http://localhost:9000/liveness'
curl --location --request GET 'http://localhost:9000/readiness'
To disable health check, set the environment variable HAMMER_HEALTH_CHECK_ENABLED to false.
export HAMMER_HEALTH_CHECK_ENABLED='false'
Content type
Image
Digest
Size
12.3 MB
Last updated
over 5 years ago
docker pull allisson/hammer