Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Introduce c360-ingest-api #235

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
30 changes: 30 additions & 0 deletions integration-box/http/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Treasure Data Streaming Ingest API

Treasure Data Streaming Ingest API allows you to ingest data through HTTPS.

## Overview

In the multiple programming languages, this Box shows its basic usage by sequentially inserting two records:

|id|name|age|comment|object|array|
|:---:|:---:|:---:|:---:|:---:|:---:|
|1|John Doe|25|hello, world|{'lang', 'xxx'}|['hello', 'world']|
|2|Jane Doe|23|good morning|{'lang', 'xxx'}|['good', 'morning']|

## Usage

First, edit [`config.sample.json`](./config.sample.json) and rename as `config.json`.

As you can see, the `events` part of JSON payload represents single record (i.e., row) stored in Treasure Data:

```json
{
"events": [{
"column_name_1": (value_1),
"column_name_2": (value_2),
...
}, ...]
}
```

Eventually, the records will become available on your target Treasure Data table.
12 changes: 12 additions & 0 deletions integration-box/http/c/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Treasure Data HTTP ingest: C Example

## Usage

### C with libcurl

An C source code example with [libcurl](https://curl.haxx.se/libcurl/)

```
cc -lcurl curl.c
./a.out c360-ingest-api.treasuredata.com 1/123456789abcdefghijklmnopqrstuvwxyz database_name table_name '{"events":[{"name":"John"}]}'
```
94 changes: 94 additions & 0 deletions integration-box/http/c/curl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <curl/curl.h>
#include <stdlib.h>
#include <strings.h>

int main(int argc, char *argv[])
{
CURLcode ret;
CURL *hnd;
struct curl_slist *slist1;

if (argc != 6) {
fprintf(stderr, "usage: %s <endpoint> <apikey> <database> <table>\n", argv[0]);
}

/* c360-ingest-api endpoint; ex. "c360-ingest-api.treasuredata.com" */
char *endpoint = argv[1];
/* Treasure Data apikey; ex. "1234/0123456789abcdef0123456789abcdef01234567 */
char *apikey = argv[2];
/* Treasure Data database name; pattern: [0-9a-z_]{3,128} */
char *database = argv[3];
/* Treasure Data table name; pattern: [0-9a-z_]{3,128} */
char *table = argv[4];
/* payload:
* {
* "events": [
* {"key": "value", ...},
* ...
* ]
* }
*/
char *curlopt_postfields = argv[5];

char curlopt_url[1024];
{
int r = snprintf(curlopt_url, sizeof(curlopt_url), "https://%s/%s/%s", endpoint, database, table);
if (r <= 0 || 1000 < r) {
fprintf(stderr, "failed to format curlopt_url\n");
exit(1);
}
}

char authrization[128];
{
int r = snprintf(authrization, sizeof(authrization), "Authorization: TD1 %s", apikey);
if (r <= 0 || 100 < r) {
fprintf(stderr, "failed to format Authorization\n");
exit(1);
}
}

slist1 = NULL;
slist1 = curl_slist_append(slist1, "Content-Type: application/vnd.treasuredata.v1+json");
slist1 = curl_slist_append(slist1, "Accept: application/vnd.treasuredata.v1+json");
slist1 = curl_slist_append(slist1, authrization);

hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_URL, curlopt_url);
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, curlopt_postfields);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strlen(curlopt_postfields));
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.54.0");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);

/* Here is a list of options the curl code used that cannot get generated
as source easily. You may select to either not use them or implement
them yourself.

CURLOPT_WRITEDATA set to a objectpointer
CURLOPT_INTERLEAVEDATA set to a objectpointer
CURLOPT_WRITEFUNCTION set to a functionpointer
CURLOPT_READDATA set to a objectpointer
CURLOPT_READFUNCTION set to a functionpointer
CURLOPT_SEEKDATA set to a objectpointer
CURLOPT_SEEKFUNCTION set to a functionpointer
CURLOPT_ERRORBUFFER set to a objectpointer
CURLOPT_STDERR set to a objectpointer
CURLOPT_HEADERFUNCTION set to a functionpointer
CURLOPT_HEADERDATA set to a objectpointer

*/

ret = curl_easy_perform(hnd);

curl_easy_cleanup(hnd);
hnd = NULL;
curl_slist_free_all(slist1);
slist1 = NULL;

return (int)ret;
}
/**** End of sample code ****/
6 changes: 6 additions & 0 deletions integration-box/http/config.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"endpoint": "c360-ingest-api.treasuredata.com",
"apikey": "1/123456789abcdefghijklmnopqrstuvwxyz",
"database": "database_name",
"table": "table_name"
}
7 changes: 7 additions & 0 deletions integration-box/http/ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Treasure Data HTTP ingest: Ruby Example

## Usage

```
ruby http.rb
```
39 changes: 39 additions & 0 deletions integration-box/http/ruby/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env ruby
require 'json'
require 'net/http'

config_path = File.expand_path('../config.sample.json', __dir__)
config = JSON.parse(File.read(config_path))


path = "/#{config['database']}/#{config['table']}"

payload = {
events: [
{
name: 'John Doe',
age: 25,
comment: 'hello, world',
object: {lang: 'ruby'},
array: %w[hello world]
},
{
name: 'Jane Done',
age: 23,
comment: 'good morning',
object: {lang: 'ruby'},
array: %w[good morning]
},
]
}

Net::HTTP.start(config["endpoint"], 443, use_ssl: true) do |http|
headers = {
"Authorization" => "TD1 #{config["apikey"]}",
"Content-Type" => "application/vnd.treasuredata.v1+json",
"Accept" => "application/vnd.treasuredata.v1+json",
}
res = http.post(path, JSON.dump(payload), headers)
p res
puts res.body
end