-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Tutorial and documentation for config-based connectors #15027
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
Changes from 13 commits
4855a72
138bd52
637c2a7
9fabad8
ff775e3
6ebee74
ff2b602
906f915
a64c758
2099b24
8bab845
a03e6f3
d444d74
71e0a5b
a9512ab
7b36ca6
218bfd9
78599e3
c9bfb99
58567c5
76a95ae
8feb1a6
ecf9b34
990d44a
f9b1b68
945cc3e
a3349df
318e613
c54b0c4
9cc1e4b
f096296
8bd35b4
cfb4528
85d5afb
61a75b5
7e1dc95
3df5071
b074832
672eb16
6575c9d
e747b4a
d5ac31d
fdce2c6
198b421
18bc40f
f4e5ed4
83e3845
bab017b
37d1fde
1fc83fe
6944916
c317a49
096a370
ff804be
49be031
6790422
34214b4
bf9a205
74e4de8
ca0f93c
46b2ee4
9cfd223
65a966c
dd4437c
365c0dc
ebaa701
aacc30a
3b1e85f
b4498f3
306e9e5
c2d9b86
562844b
faada9a
08487f7
30d25c0
63a295c
019cc0a
117ee2f
3a00dac
b2040fc
db243a8
cc0d76c
6cbdaa0
619bf37
9a4f1c9
5337868
e4919d5
e27fade
048bddb
019aad2
cc308f2
e3cffc8
785a3e4
2db7694
2a7d5fc
eba0322
e7f0023
8353121
e6637d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,70 @@ | ||||||
# Authentication | ||||||
|
||||||
The `Authenticator` defines how to configure outgoing HTTP requests to authenticate on the API source. | ||||||
|
||||||
## Authenticators | ||||||
|
||||||
### ApiKeyAuthenticator | ||||||
|
||||||
The `ApiKeyAuthenticator` sets an HTTP header on outgoing requests. | ||||||
The following definition will set the header "Authorization" with a value "Bearer hello": | ||||||
|
||||||
``` | ||||||
authenticator: | ||||||
type: "ApiKeyAuthenticator" | ||||||
header: "Authorization" | ||||||
token: "Bearer hello" | ||||||
``` | ||||||
|
||||||
### BearerAuthenticator | ||||||
|
||||||
The `BearerAuthenticator` is a specialized `ApiKeyAuthenticator` that always sets the header "Authorization" with the value "Bearer {token}". | ||||||
The following definition will set the header "Authorization" with a value "Bearer hello" | ||||||
|
||||||
``` | ||||||
authenticator: | ||||||
type: "BearerAuthenticator" | ||||||
token: "hello" | ||||||
``` | ||||||
|
||||||
More information on bearer authentication can be found [here](https://swagger.io/docs/specification/authentication/bearer-authentication/) | ||||||
|
||||||
### BasicHttpAuthenticator | ||||||
|
||||||
The `BasicHttpAuthenticator` set the "Authorization" header with a (USER ID/password) pair, encoded using base64 as per [RFC 7617](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme). | ||||||
The following definition will set the header "Authorization" with a value "Basic <encoded credentials>" | ||||||
|
||||||
The encoding scheme is: | ||||||
|
||||||
1. concatenate the username and the password with `":"` in between | ||||||
2. Encode the resulting string in base 64 | ||||||
3. Decode the result in utf8 | ||||||
|
||||||
``` | ||||||
authenticator: | ||||||
type: "BasicHttpAuthenticator" | ||||||
username: "hello" | ||||||
password: "world" | ||||||
``` | ||||||
|
||||||
The password is optional. Authenticating with APIs using Basic HTTP and a single API key can be done as: | ||||||
|
||||||
``` | ||||||
authenticator: | ||||||
type: "BasicHttpAuthenticator" | ||||||
username: "hello" | ||||||
``` | ||||||
|
||||||
### OAuth | ||||||
|
||||||
OAuth authentication is supported through the `OAuthAuthenticator`, which requires the following parameters: | ||||||
|
||||||
alafanechere marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
- token_refresh_endpoint: The endpoint to refresh the access token | ||||||
- client_id: The client id | ||||||
- client_secret: Client secret | ||||||
- refresh_token: The token used to refresh the access token | ||||||
- scopes: The scopes to request | ||||||
- token_expiry_date: The access token expiration date | ||||||
- access_token_name: THe field to extract access token from in the response | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
- expires_in_name:The field to extract expires_in from in the response | ||||||
- refresh_request_body: The request body to send in the refresh request |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,206 @@ | ||||||
# Connector definition | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would recommend renaming this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
|
||||||
Connectors are defined as a yaml configuration describing the connector's Source. | ||||||
|
||||||
2 top-level fields are required: | ||||||
|
||||||
1. `streams`: list of streams that are part of the source | ||||||
2. `check`: component describing how to check the connection. | ||||||
|
||||||
The configuration will be validated against this JSON Schema, which defines the set of valid properties. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. soon (tm).
girarda marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
We recommend using the `Configuration Based Source` template from the template generator in `airbyte-integrations/connector-templates/generator` to generate the basic file structure. | ||||||
|
||||||
## Object instantiation | ||||||
|
||||||
This section describes the object that are to be instantiated from the YAML definition. | ||||||
|
||||||
If the component is a literal, then it is returned as is: | ||||||
|
||||||
``` | ||||||
3 | ||||||
``` | ||||||
|
||||||
will result in | ||||||
|
||||||
``` | ||||||
3 | ||||||
``` | ||||||
|
||||||
If the component is a mapping with a "class_name" field, | ||||||
an object of type "class_name" will be instantiated by passing the mapping's other fields to the constructor | ||||||
|
||||||
``` | ||||||
{ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldu this just be written as YAML to stay consistsent? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, done |
||||||
"class_name": "fully_qualified.class_name", | ||||||
"a_parameter: 3, | ||||||
"another_parameter: "hello" | ||||||
} | ||||||
``` | ||||||
|
||||||
will result in | ||||||
|
||||||
``` | ||||||
fully_qualified.class_name(a_parameter=3, another_parameter="helo" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
``` | ||||||
|
||||||
If the component definition is a mapping with a "type" field, | ||||||
the factory will lookup the [CLASS_TYPES_REGISTRY](https://github.com/airbytehq/airbyte/blob/master/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/class_types_registry.py) and replace the "type" field by "class_name" -> CLASS_TYPES_REGISTRY[type] | ||||||
and instantiate the object from the resulting mapping | ||||||
|
||||||
If the component definition is a mapping with neither a "class_name" nor a "type" field, | ||||||
the factory will do a best-effort attempt at inferring the component type by looking up the parent object's constructor type hints. | ||||||
If the type hint is an interface present in [DEFAULT_IMPLEMENTATIONS_REGISTRY](https://github.com/airbytehq/airbyte/blob/master/airbyte-cdk/python/airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py, | ||||||
then the factory will create an object of its default implementation. | ||||||
|
||||||
If the component definition is a list, then the factory will iterate over the elements of the list, | ||||||
instantiate its subcomponents, and return a list of instantiated objects. | ||||||
|
||||||
If the component has subcomponents, the factory will create the subcomponents before instantiating the top level object | ||||||
|
||||||
``` | ||||||
{ | ||||||
"type": TopLevel | ||||||
"param": | ||||||
{ | ||||||
"type": "ParamType" | ||||||
"k": "v" | ||||||
} | ||||||
} | ||||||
``` | ||||||
|
||||||
will result in | ||||||
|
||||||
``` | ||||||
TopLevel(param=ParamType(k="v")) | ||||||
``` | ||||||
|
||||||
Parameters can be passed down from a parent component to its subcomponents using the $options key. | ||||||
This can be used to avoid repetitions. | ||||||
|
||||||
``` | ||||||
outer: | ||||||
$options: | ||||||
MyKey: MyValue | ||||||
inner: | ||||||
k2: v2 | ||||||
``` | ||||||
|
||||||
This the example above, if both outer and inner are types with a "MyKey" field, both of them will evaluate to "MyValue". | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what happens if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added clarification with an example |
||||||
|
||||||
The value can also be used for string interpolation: | ||||||
|
||||||
``` | ||||||
outer: | ||||||
$options: | ||||||
MyKey: MyValue | ||||||
inner: | ||||||
k2: "MyKey is {{ options.MyKey }}" | ||||||
``` | ||||||
|
||||||
In this example, outer.inner.k2 will evaluate to "MyValue" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given the interpolation this would evaluate to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, fixed. |
||||||
|
||||||
More details on object instantiation can be found [here](https://airbyte-cdk.readthedocs.io/en/latest/api/airbyte_cdk.sources.declarative.parsers.html?highlight=factory#airbyte_cdk.sources.declarative.parsers.factory.DeclarativeComponentFactory). | ||||||
|
||||||
## References | ||||||
|
||||||
Strings can contain references to values previously defined. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit |
||||||
The parser will dereference these values to produce a complete ConnectionDefinition | ||||||
|
||||||
References can be defined using a *ref(<arg>) string. | ||||||
|
||||||
``` | ||||||
key: 1234 | ||||||
reference: "*ref(key)" | ||||||
``` | ||||||
|
||||||
will produce the following definition: | ||||||
|
||||||
``` | ||||||
key: 1234 | ||||||
reference: 1234 | ||||||
``` | ||||||
|
||||||
This also works with objects: | ||||||
|
||||||
``` | ||||||
key_value_pairs: | ||||||
k1: v1 | ||||||
k2: v2 | ||||||
same_key_value_pairs: "*ref(key_value_pairs)" | ||||||
``` | ||||||
|
||||||
will produce the following definition: | ||||||
|
||||||
``` | ||||||
key_value_pairs: | ||||||
k1: v1 | ||||||
k2: v2 | ||||||
same_key_value_pairs: | ||||||
k1: v1 | ||||||
k2: v2 | ||||||
``` | ||||||
|
||||||
The $ref keyword can be used to refer to an object and enhance it with addition key-value pairs | ||||||
|
||||||
``` | ||||||
key_value_pairs: | ||||||
k1: v1 | ||||||
k2: v2 | ||||||
same_key_value_pairs: | ||||||
$ref: "*ref(key_value_pairs)" | ||||||
k3: v3 | ||||||
``` | ||||||
|
||||||
will produce the following definition: | ||||||
|
||||||
``` | ||||||
key_value_pairs: | ||||||
k1: v1 | ||||||
k2: v2 | ||||||
same_key_value_pairs: | ||||||
k1: v1 | ||||||
k2: v2 | ||||||
k3: v3 | ||||||
``` | ||||||
|
||||||
References can also point to nested values. | ||||||
Nested references are ambiguous because one could define a key containing with `.` | ||||||
in this example, we want to refer to the limit key in the dict object: | ||||||
|
||||||
``` | ||||||
dict: | ||||||
limit: 50 | ||||||
limit_ref: "*ref(dict.limit)" | ||||||
``` | ||||||
|
||||||
will produce the following definition: | ||||||
|
||||||
``` | ||||||
dict | ||||||
limit: 50 | ||||||
limit-ref: 50 | ||||||
``` | ||||||
|
||||||
whereas here we want to access the `nested.path` value. | ||||||
|
||||||
``` | ||||||
nested: | ||||||
path: "first one" | ||||||
nested.path: "uh oh" | ||||||
value: "ref(nested.path) | ||||||
``` | ||||||
|
||||||
will produce the following definition: | ||||||
|
||||||
``` | ||||||
nested: | ||||||
path: "first one" | ||||||
nested.path: "uh oh" | ||||||
value: "uh oh" | ||||||
``` | ||||||
|
||||||
to resolve the ambiguity, we try looking for the reference key at the top level, and then traverse the structs downward | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
until we find a key with the given path, or until there is nothing to traverse. | ||||||
|
||||||
More details on referencing values can be found [here](https://airbyte-cdk.readthedocs.io/en/latest/api/airbyte_cdk.sources.declarative.parsers.html?highlight=yamlparser#airbyte_cdk.sources.declarative.parsers.yaml_parser.YamlParser). |
Uh oh!
There was an error while loading. Please reload this page.