* default schema loader * Update generator * update example * remove more cruft * Update code sampels in section 3 (but not the text) * Update code sampels in 5 * Update instructions * Update code samples * Update samples * Use now_utc instead of local * isolate complexity to JsonSchema * Bump cdk version * Update changelog * fix unit test * slightly more helpful default * Don't freeze cdk version in template * remove newline * newline * bump * Update changelog * Bump
7.1 KiB
Step 3: Connecting to the API
We're now ready to start implementing the connector.
Over the course of this tutorial, we'll be editing a few files that were generated by the code generator:
source-exchange-rates-tutorial/source_exchange_rates_tutorial/spec.yaml: This is the spec file. It describes the inputs used to configure the connector.source-exchange-rates-tutorial/source_exchange_rates_tutorial/exchange_rates_tutorial.yaml: This is the connector definition. It describes how the data should be read from the API source.source-exchange_rates-tutorial/integration_tests/configured_catalog.json: This is the connector's catalog. It describes what data is available in a sourcesource-exchange-rates-tutorial/integration_tests/sample_state.json: This is a sample state object to be used to test incremental syncs.
We'll also be creating the following files:
source-exchange-rates-tutorial/secrets/config.json: This is the configuration file we'll be using to test the connector. Its schema should match the schema defined in the spec file.source-exchange-rates-tutorial/secrets/invalid_config.json: This is an invalid configuration file we'll be using to test the connector. Its schema should match the schema defined in the spec file.source_exchange_rates_tutorial/schemas/rates.json: This is the schema definition for the stream we'll implement.
Updating the connector spec and config
Let's populate the specification (spec.yaml) and the configuration (secrets/config.json) so the connector can access the access key and base currency.
- We'll add these properties to the connector spec in
source-exchange-rates-tutorial/source_exchange_rates_tutorial/spec.yaml
documentationUrl: https://docs.airbyte.io/integrations/sources/exchangeratesapi
connectionSpecification:
$schema: http://json-schema.org/draft-07/schema#
title: exchangeratesapi.io Source Spec
type: object
required:
- access_key
- base
additionalProperties: true
properties:
access_key:
type: string
description: >-
Your API Access Key. See <a
href="https://exchangeratesapi.io/documentation/">here</a>. The key is
case sensitive.
airbyte_secret: true
base:
type: string
description: >-
ISO reference currency. See <a
href="https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html">here</a>.
examples:
- EUR
- USD
- We also need to fill in the connection config in the
secrets/config.jsonBecause of the sensitive nature of the access key, we recommend storing this config in thesecretsdirectory because it is ignored by git.
echo '{"access_key": "<your_access_key>", "base": "USD"}' > secrets/config.json
Updating the connector definition
Next, we'll update the connector definition (source-exchange-rates-tutorial/source_exchange_rates_tutorial/exchange_rates_tutorial.yaml). It was generated by the code generation script.
More details on the connector definition file can be found in the overview and connection definition sections.
Let's fill this out these TODOs with the information found in the Exchange Rates API docs.
- We'll first set the API's base url. According to the API documentation, the base url is
"https://api.apilayer.com".
definitions:
<...>
requester:
url_base: "https://api.apilayer.com"
- Then, let's rename the stream from
customerstorates, update the primary key todate, and set the path to "/exchangerates_data/latest" as per the API's documentation. This path is specific to the stream, so we'll set it within therates_streamdefinition
rates_stream:
$ref: "*ref(definitions.base_stream)"
$options:
name: "rates"
primary_key: "date"
path: "/exchangerates_data/latest"
We'll also update the reference in the streams block
streams:
- "*ref(definitions.rates_stream)"
- Update the references in the
checkblock
check:
stream_names:
- "rates"
Adding the reference in the check tells the check operation to use that stream to test the connection.
- Next, we'll set up the authentication.
The Exchange Rates API requires an access key to be passed as header named "apikey".
This can be done using an
ApiKeyAuthenticator, which we'll configure to point to the config'saccess_keyfield.
definitions:
<...>
requester:
url_base: "https://api.apilayer.com"
http_method: "GET"
authenticator:
type: ApiKeyAuthenticator
header: "apikey"
api_token: "{{ config['access_key'] }}"
- According to the ExchangeRatesApi documentation, we can specify the base currency of interest in a request parameter. Let's assume the user will configure this via the connector configuration in parameter called
base; we'll pass the value input by the user as a request parameter:
definitions:
<...>
requester:
<...>
request_options_provider:
request_parameters:
base: "{{ config['base'] }}"
The full connector definition should now look like
version: "0.1.0"
definitions:
selector:
extractor:
field_pointer: [ ]
requester:
url_base: "https://api.apilayer.com"
http_method: "GET"
authenticator:
type: ApiKeyAuthenticator
header: "apikey"
api_token: "{{ config['access_key'] }}"
request_options_provider:
request_parameters:
base: "{{ config['base'] }}"
retriever:
record_selector:
$ref: "*ref(definitions.selector)"
paginator:
type: NoPagination
requester:
$ref: "*ref(definitions.requester)"
base_stream:
retriever:
$ref: "*ref(definitions.retriever)"
rates_stream:
$ref: "*ref(definitions.base_stream)"
$options:
name: "rates"
primary_key: "date"
path: "/exchangerates_data/latest"
streams:
- "*ref(definitions.rates_stream)"
check:
stream_names:
- "rates"
We can now run the check operation, which verifies the connector can connect to the API source.
python main.py check --config secrets/config.json
which should now succeed with logs similar to:
{"type": "LOG", "log": {"level": "INFO", "message": "Check succeeded"}}
{"type": "CONNECTION_STATUS", "connectionStatus": {"status": "SUCCEEDED"}}
Next steps
Next, we'll extract the records from the response