Skip to content

Commit

Permalink
CDK: tutorial for implementing an HTTP source (#3079)
Browse files Browse the repository at this point in the history
  • Loading branch information
sherifnada committed Apr 27, 2021
1 parent e63ab84 commit 4e9f4bd
Show file tree
Hide file tree
Showing 33 changed files with 1,604 additions and 25 deletions.
10 changes: 4 additions & 6 deletions airbyte-integrations/bases/base-python/CDK-README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Airbyte Connector Development Kit (CDK)

The Airbyte Python CDK is a framework for fast development of production-grade Airbyte connectors.
The Airbyte Python CDK is a framework for rapidly developing production-grade Airbyte connectors.
The CDK currently offers helpers specific for creating Airbyte source connectors for:
* HTTP APIs (REST APIs, GraphQL, etc..)
* Singer Taps
* Generic Python sources (anything not covered by the above)
It provides an improved developer experience by providing basic implementation structure and abstracting away
low-level glue boilerplate. The CDK aims to make implementing a Source as simple as possible -
reading the Source's API, and filling in a few Python function should be all that is needed.

This document is a general introduction to the CDK. Readers should be familiar with the above linked Airbyte
Specification before proceeding.
The CDK provides an improved developer experience by providing basic implementation structure and abstracting away low-level glue boilerplate.

This document is a general introduction to the CDK. Readers should have basic familiarity with the [Airbyte Specification](https://docs.airbyte.io/architecture/airbyte-specification) before proceeding.

### The Airbyte Specification
As a quick recap, the Airbyte Specification requires an Airbyte Source to support 4 distinct operations:
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
{
"streams": [
{
"stream": {
"name": "exchange_rates",
"json_schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"base": {
"type": "string"
},
"rates": {
"type": "object",
"properties": {
"GBP": {
"type": "number"
},
"HKD": {
"type": "number"
},
"IDR": {
"type": "number"
},
"PHP": {
"type": "number"
},
"LVL": {
"type": "number"
},
"INR": {
"type": "number"
},
"CHF": {
"type": "number"
},
"MXN": {
"type": "number"
},
"SGD": {
"type": "number"
},
"CZK": {
"type": "number"
},
"THB": {
"type": "number"
},
"BGN": {
"type": "number"
},
"EUR": {
"type": "number"
},
"MYR": {
"type": "number"
},
"NOK": {
"type": "number"
},
"CNY": {
"type": "number"
},
"HRK": {
"type": "number"
},
"PLN": {
"type": "number"
},
"LTL": {
"type": "number"
},
"TRY": {
"type": "number"
},
"ZAR": {
"type": "number"
},
"CAD": {
"type": "number"
},
"BRL": {
"type": "number"
},
"RON": {
"type": "number"
},
"DKK": {
"type": "number"
},
"NZD": {
"type": "number"
},
"EEK": {
"type": "number"
},
"JPY": {
"type": "number"
},
"RUB": {
"type": "number"
},
"KRW": {
"type": "number"
},
"USD": {
"type": "number"
},
"AUD": {
"type": "number"
},
"HUF": {
"type": "number"
},
"SEK": {
"type": "number"
}
}
},
"date": {
"type": "string"
}
}
},
"supported_sync_modes": ["full_refresh"]
},
"sync_mode": "full_refresh",
"destination_sync_mode": "overwrite"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"type": "object",
"required": ["base", "date", "rates"],
"properties": {
"base": {
"type": "string"
},
"date": {
"type": "string"
},
"rates": {
"type": "object",
"properties": {
"CAD": {
"type": ["null", "number"]
},
"HKD": {
"type": ["null", "number"]
},
"ISK": {
"type": ["null", "number"]
},
"PHP": {
"type": ["null", "number"]
},
"DKK": {
"type": ["null", "number"]
},
"HUF": {
"type": ["null", "number"]
},
"CZK": {
"type": ["null", "number"]
},
"GBP": {
"type": ["null", "number"]
},
"RON": {
"type": ["null", "number"]
},
"SEK": {
"type": ["null", "number"]
},
"IDR": {
"type": ["null", "number"]
},
"INR": {
"type": ["null", "number"]
},
"BRL": {
"type": ["null", "number"]
},
"RUB": {
"type": ["null", "number"]
},
"HRK": {
"type": ["null", "number"]
},
"JPY": {
"type": ["null", "number"]
},
"THB": {
"type": ["null", "number"]
},
"CHF": {
"type": ["null", "number"]
},
"EUR": {
"type": ["null", "number"]
},
"MYR": {
"type": ["null", "number"]
},
"BGN": {
"type": ["null", "number"]
},
"TRY": {
"type": ["null", "number"]
},
"CNY": {
"type": ["null", "number"]
},
"NOK": {
"type": ["null", "number"]
},
"NZD": {
"type": ["null", "number"]
},
"ZAR": {
"type": ["null", "number"]
},
"USD": {
"type": ["null", "number"]
},
"MXN": {
"type": ["null", "number"]
},
"SGD": {
"type": ["null", "number"]
},
"AUD": {
"type": ["null", "number"]
},
"ILS": {
"type": ["null", "number"]
},
"KRW": {
"type": ["null", "number"]
},
"PLN": {
"type": ["null", "number"]
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ def addScaffoldTemplateTask(name, packageName,scaffoldParams=[]) {
}

addScaffoldTemplateTask('Python Source', 'scaffold-source-python')
addScaffoldTemplateTask('Python HTTP CDK Source', 'scaffold-source-http')
addScaffoldTemplateTask('Python HTTP API Source', 'scaffold-source-http')
// TODO: enable Singer template testing
//addScaffoldTask('source-python-singer', ['tap-exchangeratesapi'])
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ module.exports = function (plop) {
console.log(getSuccessMessage(answers.name, plopApi.renderString(config.outputPath, answers), config.message));
});

plop.setGenerator('Python HTTP CDK Source', {
description: 'Generate a Source that pulls data from a synchronous HTTP API built on the Airbyte CDK.',
plop.setGenerator('Python HTTP API Source', {
description: 'Generate a Source that pulls data from a synchronous HTTP API.',
prompts: [{type: 'input', name: 'name', message: 'Source name e.g: "google-analytics"'}],
actions: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ setup(
author_email="contact@airbyte.io",
packages=find_packages(),
install_requires=["airbyte-protocol", "base-python", "pytest==6.1.2"],
package_data={"": ["*.json"]}
package_data={"": ["*.json", "schemas/*.json", "schemas/shared/*.json"]}
)
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Tuple
import requests

from base_python import AbstractSource, HttpStream, Stream
from base_python.cdk.streams.auth.core import TokenAuthenticator
from base_python.cdk.streams.auth.token import TokenAuthenticator

"""
TODO: Most comments in this class are instructive and should be deleted after the source is implemented.
Expand Down Expand Up @@ -197,7 +197,7 @@ class Source{{properCase name}}(AbstractSource):
See https://github.com/airbytehq/airbyte/blob/master/airbyte-integrations/connectors/source-stripe/source_stripe/source.py#L232
for an example.

:param config: the user-input config object conforming the connector's spec.json
:param config: the user-input config object conforming to the connector's spec.json
:param logger: logger object
:return Tuple[bool, any]: (True, None) if the input config can be used to connect to the API successfully, (False, error) otherwise.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// TODO: This schema defines the configuration required for the source. This usually involves metadata such as database and/or authentication information.
// Delete this comment after reading.
{
"documentationUrl": "https://docsurl.com",
"connectionSpecification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "{{titleCase name}} Spec",
"type": "object",
"required": ["fix-me"],
"required": ["TODO"],
"additionalProperties": false,
"properties": {
"fix-me": {
"TODO: This schema defines the configuration required for the source. This usually involves metadata such as database and/or authentication information.": {
"type": "string",
"description": "describe me"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"documentationUrl": "https://docs.airbyte.io/integrations/sources/ratesapi-io",
"documentationUrl": "https://docs.airbyte.io/integrations/sources/exchangeratesapi",
"connectionSpecification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ratesapi.io Source Spec",
"type": "object",
"required": ["start_date", "base"],
"required": ["start_date", "currency_base"],
"additionalProperties": false,
"properties": {
"start_date": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*
!Dockerfile
!Dockerfile.test
!source_python_http_tutorial
!setup.py
!secrets
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM airbyte/integration-base-python:0.1.5

# Bash is installed for more convenient debugging.
RUN apt-get update && apt-get install -y bash && rm -rf /var/lib/apt/lists/*

ENV CODE_PATH="source_python_http_tutorial"
ENV AIRBYTE_IMPL_MODULE="source_python_http_tutorial"
ENV AIRBYTE_IMPL_PATH="SourcePythonHttpTutorial"

WORKDIR /airbyte/integration_code
COPY $CODE_PATH ./$CODE_PATH
COPY setup.py ./
RUN pip install .

LABEL io.airbyte.version=0.1.0
LABEL io.airbyte.name=airbyte/source-python-http-tutorial
Loading

0 comments on commit 4e9f4bd

Please sign in to comment.