Skip to content

Commit 50111d3

Browse files
brianjlairodireich
authored andcommitted
[low code connectors] perform schema validation of the input config against the declarative language schema (#15543)
* draft: first pass at complete schema language generation and factory validator * actually a working validator and fixes to the schema that went uncaught * remove extra spike file * fix formatting file * pr feedback and a little bit of refactoring * fix some types that were erroneously marked as invalid schema * some comments * add jsonschemamixin to interfaces * update changelog * bump version
1 parent 4d58132 commit 50111d3

31 files changed

+670
-93
lines changed

airbyte-cdk/python/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## 0.1.77
4+
- Add schema validation for declarative YAML connector configs
5+
36
## 0.1.76
47
- Bugfix: Correctly set parent slice stream for sub-resource streams
58

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#
2+
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
3+
#
4+
5+
from dataclasses import dataclass
6+
7+
from airbyte_cdk.sources.streams.http.requests_native_auth.abstract_token import AbstractHeaderAuthenticator
8+
from dataclasses_jsonschema import JsonSchemaMixin
9+
10+
11+
@dataclass
12+
class DeclarativeAuthenticator(JsonSchemaMixin):
13+
"""
14+
Interface used to associate which authenticators can be used as part of the declarative framework
15+
"""
16+
17+
18+
@dataclass
19+
class NoAuth(AbstractHeaderAuthenticator, DeclarativeAuthenticator, JsonSchemaMixin):
20+
@property
21+
def auth_header(self) -> str:
22+
return ""
23+
24+
@property
25+
def token(self) -> str:
26+
return ""

airbyte-cdk/python/airbyte_cdk/sources/declarative/auth/oauth.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
from typing import Any, List, Mapping, Optional, Union
77

88
import pendulum
9+
from airbyte_cdk.sources.declarative.auth.declarative_authenticator import DeclarativeAuthenticator
910
from airbyte_cdk.sources.declarative.interpolation.interpolated_mapping import InterpolatedMapping
1011
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
1112
from airbyte_cdk.sources.streams.http.requests_native_auth.abstract_oauth import AbstractOauth2Authenticator
1213
from dataclasses_jsonschema import JsonSchemaMixin
1314

1415

1516
@dataclass
16-
class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, JsonSchemaMixin):
17+
class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAuthenticator, JsonSchemaMixin):
1718
"""
1819
Generates OAuth2.0 access tokens from an OAuth2.0 refresh token and client credentials based on
1920
a declarative connector configuration file. Credentials can be defined explicitly or via interpolation
@@ -40,7 +41,7 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, JsonSchemaMixi
4041
options: InitVar[Mapping[str, Any]]
4142
scopes: Optional[List[str]] = None
4243
token_expiry_date: Optional[Union[InterpolatedString, str]] = None
43-
_token_expiry_date: pendulum.DateTime = field(init=False, repr=False)
44+
_token_expiry_date: pendulum.DateTime = field(init=False, repr=False, default=None)
4445
access_token_name: Union[InterpolatedString, str] = "access_token"
4546
expires_in_name: Union[InterpolatedString, str] = "expires_in"
4647
refresh_request_body: Optional[Mapping[str, Any]] = None

airbyte-cdk/python/airbyte_cdk/sources/declarative/auth/token.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
from dataclasses import InitVar, dataclass
77
from typing import Any, Mapping, Union
88

9+
from airbyte_cdk.sources.declarative.auth.declarative_authenticator import DeclarativeAuthenticator
910
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
1011
from airbyte_cdk.sources.declarative.types import Config
1112
from airbyte_cdk.sources.streams.http.requests_native_auth.abstract_token import AbstractHeaderAuthenticator
1213
from dataclasses_jsonschema import JsonSchemaMixin
1314

1415

1516
@dataclass
16-
class ApiKeyAuthenticator(AbstractHeaderAuthenticator, JsonSchemaMixin):
17+
class ApiKeyAuthenticator(AbstractHeaderAuthenticator, DeclarativeAuthenticator, JsonSchemaMixin):
1718
"""
1819
ApiKeyAuth sets a request header on the HTTP requests sent.
1920
@@ -51,7 +52,7 @@ def token(self) -> str:
5152

5253

5354
@dataclass
54-
class BearerAuthenticator(AbstractHeaderAuthenticator, JsonSchemaMixin):
55+
class BearerAuthenticator(AbstractHeaderAuthenticator, DeclarativeAuthenticator, JsonSchemaMixin):
5556
"""
5657
Authenticator that sets the Authorization header on the HTTP requests sent.
5758
@@ -81,7 +82,7 @@ def token(self) -> str:
8182

8283

8384
@dataclass
84-
class BasicHttpAuthenticator(AbstractHeaderAuthenticator):
85+
class BasicHttpAuthenticator(AbstractHeaderAuthenticator, DeclarativeAuthenticator, JsonSchemaMixin):
8586
"""
8687
Builds auth based off the basic authentication scheme as defined by RFC 7617, which transmits credentials as USER ID/password pairs, encoded using base64
8788
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme

airbyte-cdk/python/airbyte_cdk/sources/declarative/declarative_stream.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ class DeclarativeStream(Stream, JsonSchemaMixin):
3636
config: Config
3737
options: InitVar[Mapping[str, Any]]
3838
name: str
39-
_name: str = field(init=False, repr=False)
39+
_name: str = field(init=False, repr=False, default="")
4040
primary_key: Optional[Union[str, List[str], List[List[str]]]]
41-
_primary_key: str = field(init=False, repr=False)
42-
stream_cursor_field: Optional[List[str]] = None
41+
_primary_key: str = field(init=False, repr=False, default="")
42+
stream_cursor_field: Optional[Union[List[str], str]] = None
4343
transformations: List[RecordTransformation] = None
4444
checkpoint_interval: Optional[int] = None
4545

airbyte-cdk/python/airbyte_cdk/sources/declarative/decoders/decoder.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
33
#
44

5-
from abc import ABC, abstractmethod
5+
from abc import abstractmethod
66
from dataclasses import dataclass
77
from typing import Any, List, Mapping, Union
88

99
import requests
10+
from dataclasses_jsonschema import JsonSchemaMixin
1011

1112

1213
@dataclass
13-
class Decoder(ABC):
14+
class Decoder(JsonSchemaMixin):
1415
"""
1516
Decoder strategy to transform a requests.Response into a Mapping[str, Any]
1617
"""

airbyte-cdk/python/airbyte_cdk/sources/declarative/decoders/json_decoder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77

88
import requests
99
from airbyte_cdk.sources.declarative.decoders.decoder import Decoder
10+
from dataclasses_jsonschema import JsonSchemaMixin
1011

1112

1213
@dataclass
13-
class JsonDecoder(Decoder):
14+
class JsonDecoder(Decoder, JsonSchemaMixin):
1415
"""
1516
Decoder strategy that returns the json-encoded content of a response, if any.
1617
"""

airbyte-cdk/python/airbyte_cdk/sources/declarative/extractors/http_selector.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
33
#
44

5-
from abc import ABC, abstractmethod
5+
from abc import abstractmethod
66
from dataclasses import dataclass
77
from typing import Any, List, Mapping, Optional
88

99
import requests
1010
from airbyte_cdk.sources.declarative.types import Record, StreamSlice, StreamState
11+
from dataclasses_jsonschema import JsonSchemaMixin
1112

1213

1314
@dataclass
14-
class HttpSelector(ABC):
15+
class HttpSelector(JsonSchemaMixin):
1516
"""
1617
Responsible for translating an HTTP response into a list of records by extracting records from the response and optionally filtering
1718
records based on a heuristic.

airbyte-cdk/python/airbyte_cdk/sources/declarative/extractors/record_extractor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
33
#
44

5-
from abc import ABC, abstractmethod
5+
from abc import abstractmethod
66
from dataclasses import dataclass
77
from typing import List
88

99
import requests
1010
from airbyte_cdk.sources.declarative.types import Record
11+
from dataclasses_jsonschema import JsonSchemaMixin
1112

1213

1314
@dataclass
14-
class RecordExtractor(ABC):
15+
class RecordExtractor(JsonSchemaMixin):
1516
"""
1617
Responsible for translating an HTTP response into a list of records by extracting records from the response.
1718
"""

airbyte-cdk/python/airbyte_cdk/sources/declarative/extractors/record_filter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
33
#
44

5-
from dataclasses import InitVar, dataclass, field
5+
from dataclasses import InitVar, dataclass
66
from typing import Any, List, Mapping, Optional
77

88
from airbyte_cdk.sources.declarative.interpolation.interpolated_boolean import InterpolatedBoolean
@@ -20,7 +20,7 @@ class RecordFilter(JsonSchemaMixin):
2020
"""
2121

2222
options: InitVar[Mapping[str, Any]]
23-
config: Config = field(default=dict)
23+
config: Config
2424
condition: str = ""
2525

2626
def __post_init__(self, options: Mapping[str, Any]):

0 commit comments

Comments
 (0)