diff --git a/README.md b/README.md index b64a0bc..bfdab7a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # Skyflow-python --- -## Description -This Python SDK is designed to help developers easily implement Skyflow into their python backend. +## Description +This Python SDK is designed to help developers easily implement Skyflow into their python backend. ## Table of Contents + - [Skyflow-python](#skyflow-python) - [Description](#description) - [Table of Contents](#table-of-contents) @@ -18,6 +19,7 @@ This Python SDK is designed to help developers easily implement Skyflow into the - [Vault APIs](#vault-apis) - [Insert data into the vault](#insert-data-into-the-vault) - [Detokenize](#detokenize) + - [Tokenize](#tokenize) - [Get](#get) - [Get By Id](#get-by-id) - [Redaction Types](#redaction-types) @@ -28,7 +30,6 @@ This Python SDK is designed to help developers easily implement Skyflow into the - [Logging](#logging) - [Reporting a Vulnerability](#reporting-a-vulnerability) - ## Features Authentication with a Skyflow Service Account and generation of a bearer token @@ -41,7 +42,7 @@ Invoking connections to call downstream third party APIs without directly handli ### Requirements -- Python 3.7.0 and above +- Python 3.8.0 and above ### Configuration @@ -57,545 +58,734 @@ The [Service Account](https://github.com/skyflowapi/skyflow-python/tree/main/sky The `generate_bearer_token(filepath)` function takes the credentials file path for token generation, alternatively, you can also send the entire credentials as string, by using `generate_bearer_token_from_creds(credentials)` -[Example using filepath](https://github.com/skyflowapi/skyflow-python/blob/main/samples/sa_token_sample.py): +[Example using filepath](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/token_generation_example.py): ```python -from skyflow.errors import SkyflowError +from skyflow.error import SkyflowError from skyflow.service_account import generate_bearer_token, is_expired # cache token for reuse -bearerToken = '' -tokenType = '' +bearer_token = '' +token_type = '' +def token_provider(): + global bearer_token + global token_type + + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_toke('') + return bearer_token, token_type + +try: + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) +except SkyflowError as e: + print(e) + +``` + +[Example using credentials string](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/token_generation_example.py): + +```python +from skyflow.error import SkyflowError +from skyflow.service_account import generate_bearer_token, generate_bearer_token_from_creds, is_expired + +# cache token for reuse +bearer_token = '' +token_type = '' def token_provider(): - global bearerToken - global tokenType - - if is_expired(bearerToken): - bearerToken, tokenType = generate_bearer_token('') - return bearerToken, tokenType + global bearer_token + global token_type + # As an example + skyflow_credentials = { + 'clientID': '', + 'clientName': '', + 'tokenURI': '', + 'keyID': '', + 'privateKey': '', + } + credentials_string = json.dumps(skyflow_credentials) + + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token_from_creds(skyflow_credentials_string) + return bearer_token, token_type try: - accessToken, tokenType = token_provider() - print("Access Token:", accessToken) - print("Type of token:", tokenType) + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) except SkyflowError as e: print(e) ``` +## Service Account Scoped Token Generation + +[Example using filepath](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/scoped_token_generation_example.py): + +```python +from skyflow.error import SkyflowError +from skyflow.service_account import generate_bearer_token, is_expired + +# cache token for reuse +bearer_token = '' +token_type = '' +options = { + 'role_ids': ['ROLE_ID1', 'ROLE_ID2'] +} +def token_provider(): + global bearer_token + global token_type -[Example using credentials string](https://github.com/skyflowapi/skyflow-python/blob/main/samples/generate_bearer_token_from_creds_sample.py): + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token('', options) + return bearer_token, token_type + +try: + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) +except SkyflowError as e: + print(e) + +``` + +[Example using credentials string](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/scoped_token_generation_example.py): ```python -from skyflow.errors import SkyflowError -from skyflow.service_account import generate_bearer_token_from_creds, is_expired +from skyflow.error import SkyflowError +from skyflow.service_account import generate_bearer_token, generate_bearer_token_from_creds, is_expired # cache token for reuse -bearerToken = '' -tokenType = '' +bearer_token = '' +token_type = '' +options = { + 'role_ids': ['ROLE_ID1', 'ROLE_ID2'] +} def token_provider(): - global bearerToken - global tokenType + global bearer_token + global token_type # As an example - credentials = { - "clientID": "", - "clientName": "", - "keyID": "", - "tokenURI": '', - "privateKey": "" + skyflow_credentials = { + 'clientID': '', + 'clientName': '', + 'tokenURI': '', + 'keyID': '', + 'privateKey': '', } - jsonString = json.dumps(credentials) - if is_expired(bearerToken): - bearerToken, tokenType = generate_bearer_token_from_creds( - credentials=jsonString) - return bearerToken, tokenType + credentials_string = json.dumps(skyflow_credentials) + + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token_from_creds(skyflow_credentials_string, options) + return bearer_token, token_type try: - accessToken, tokenType = token_provider() - print("Access Token:", accessToken) - print("Type of token:", tokenType) + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) except SkyflowError as e: print(e) ``` -## Vault APIs +## Service Account Token Generation With Context -The [Vault](https://github.com/skyflowapi/skyflow-python/tree/main/skyflow/vault) python module is used to perform operations on the vault such as inserting records, detokenizing tokens, retrieving tokens for a skyflow_id and to invoke a connection. +[Example using filepath](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/token_generation_with_context_example.py): -To use this module, the skyflow client must first be initialized as follows. +```python +from skyflow.error import SkyflowError +from skyflow.service_account import generate_bearer_token, is_expired + +# cache token for reuse +bearer_token = '' +token_type = '' +options = { + 'ctx': "" +} +def token_provider(): + global bearer_token + global token_type + + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token('', options) + return bearer_token, token_type + +try: + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) +except SkyflowError as e: + print(e) + +``` + +[Example using credentials string](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/token_generation_with_context_example.py): + +```python +from skyflow.error import SkyflowError +from skyflow.service_account import generate_bearer_token, generate_bearer_token_from_creds, is_expired + +# cache token for reuse +bearer_token = '' +token_type = '' +options = { + 'ctx': '' +} +def token_provider(): + global bearer_token + global token_type + # As an example + skyflow_credentials = { + 'clientID': '', + 'clientName': '', + 'tokenURI': '', + 'keyID': '', + 'privateKey': '', + } + credentials_string = json.dumps(skyflow_credentials) + + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token_from_creds(skyflow_credentials_string, options) + return bearer_token, token_type + +try: + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) +except SkyflowError as e: + print(e) + +``` + +## Service Account Signed Token Generation + +[Example using filepath](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/signed_token_generation_example.py): ```python -from skyflow.vault import Client, Configuration +from skyflow.error import SkyflowError from skyflow.service_account import generate_bearer_token, is_expired -# cache for reuse -bearerToken = '' +# cache token for reuse +bearer_token = '' +token_type = '' +options = { + 'ctx': 'CONTEX_ID', + 'data_tokens': ['DATA_TOKEN1', 'DATA_TOKEN2'], + 'time_to_live': 90 # in seconds +} +def token_provider(): + global bearer_token + global token_type -# User defined function to provide access token to the vault apis + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token('', options) + return bearer_token, token_type + +try: + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) +except SkyflowError as e: + print(e) + +``` + +[Example using credentials string](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/service_account/signed_token_generation_example.py): + +```python +from skyflow.error import SkyflowError +from skyflow.service_account import generate_bearer_token, generate_bearer_token_from_creds, is_expired + +# cache token for reuse +bearer_token = '' +token_type = '' +options = { + 'ctx': 'CONTEX_ID', + 'data_tokens': ['DATA_TOKEN1', 'DATA_TOKEN2'], + 'time_to_live': 90 # in seconds +} def token_provider(): - global bearerToken - if !(is_expired(bearerToken)): - return bearerToken - bearerToken, _ = generate_bearer_token('') - return bearerToken + global bearer_token + global token_type + # As an example + skyflow_credentials = { + 'clientID': '', + 'clientName': '', + 'tokenURI': '', + 'keyID': '', + 'privateKey': '', + } + credentials_string = json.dumps(skyflow_credentials) + + if is_expired(bearer_token): + bearer_token, token_type = generate_bearer_token_from_creds(skyflow_credentials_string, options) + return bearer_token, token_type + +try: + bearer_token, token_type = token_provider() + print('Access Token:', bearer_token) + print('Type of token:', token_type) +except SkyflowError as e: + print(e) +``` + +## Vault APIs + +The vault python module is used to perform operations on the vault such as inserting records, detokenizing tokens, retrieving tokens for a skyflow_id and to invoke a connection. + +To use this module, the skyflow client must first be initialized as follows. + +```python +from skyflow import Env +from skyflow import Skyflow, LogLevel + +# To generate Bearer Token from credentials string. +skyflow_credentials = { + 'clientID': '', + 'clientName': '', + 'tokenURI': '', + 'keyID': '', + 'privateKey': '', + } +credentials_string = json.dumps(skyflow_credentials) + +# Pass one of api_key, token, credentials_string & path as credentials +credentials = { + 'token': 'BEARER_TOKEN', # bearer token + # api_key: "API_KEY", # API_KEY + # path: "PATH", # path to credentials file + # credentials_string: credentials_string, # credentials as string +} -#Initializing a Skyflow Client instance with a SkyflowConfiguration object -config = Configuration('', '', token_provider) -client = Client(config) +client = ( + Skyflow.builder() + .add_vault_config({ + 'vault_id': 'VAULT_ID', # primary vault + 'cluster_id': 'CLUSTER_ID', # ID from your vault URL Eg https://{clusterId}.vault.skyflowapis.com + 'env': Env.PROD, # Env by default it is set to PROD + 'credentials': credentials # individual credentials + }) + .add_skyflow_credentials(credentials) # skyflow credentials will be used if no individual credentials are passed + .set_log_level(LogLevel.INFO) # set log level by default it is set to ERROR + .build() +) ``` +Notes: + +- If both Skyflow common credentials and individual credentials at the configuration level are provided, the individual credentials at the configuration level will take priority. + All Vault APIs must be invoked using a client instance. ### Insert data into the vault -To insert data into your vault use the `insert(records: dict, options: InsertOptions)` method. The `records` parameter is a dictionary that requires a `records` key and takes an array of records to insert into the vault. The `options` parameter takes a dictionary of optional parameters for the insertion. This includes an option to return tokenized data, upsert records and continue on error. +To insert data into your vault, use the `insert` method. The `InsertRequest` class is used to create an insert request, which contains the values to be inserted in the form of a dictionary of records. Additionally, you can provide options in the insert request, such as returning tokenized data, upserting records, and continuing on error. + +Insert call schema ```python -# Optional, indicates whether you return tokens for inserted data. Defaults to 'true'. -tokens: bool -# Optional, indicates Upsert support in the vault. -upsert: [UpsertOption] -# Optional, decides whether to continue if error encountered or not -continueOnError: bool +#Initialize Client +from skyflow.error import SkyflowError +from skyflow.vault.data import InsertRequest + +try: + insert_data = [ + {'': ''}, + {'': ''} + ] + + + insert_request = InsertRequest( + table_name = '', + values = insert_data, + ) + + response = skyflow_client.vault('VAULT_ID').insert(insert_request) + print('Response:', response) +except SkyflowError as e: + print('Error Occurred:', e) ``` -Insert call schema +**Insert call [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/insert_records.py)** + ```python -from skyflow.vault import InsertOptions, UpsertOption -from skyflow.errors import SkyflowError +from skyflow.error import SkyflowError +from skyflow.vault.data import InsertRequest -#Initialize Client try: - # Create an Upsert option. - upsertOption = UpsertOption(table="",column="") - options = InsertOptions(tokens=True, upsert=[upsertOption], continueOnError=False) + insert_data = [ + {'card_number': '4111111111111111'}, + ] - data = { - "records": [ - { - "table": "", - "fields": { - "": "" - } - } - ] - } - response = client.insert(data, options=options) + insert_request = InsertRequest( + table_name = 'table1', + values = insert_data, + return_tokens = True # returns tokens + ) + + response = client.vault('').insert(insert_request) print("Response:", response) except SkyflowError as e: print("Error Occurred:", e) + ``` -**Insert call [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/insert_sample.py)** +Skyflow returns tokens for the record you just inserted. ```python -client.insert( - { - "records": [ +InsertResponse( + inserted_fields= + [ { - "table": "cards", - "fields": { - "cardNumber": "41111111111", - "cvv": "123", - }, + 'skyflow_id': 'a8f3ed5d-55eb-4f32-bf7e-2dbf4b9d9097', + 'card_number': '5479-4229-4622-1393' } - ] - }, - InsertOptions(True), + ], + errors=[] ) ``` -Skyflow returns tokens for the record you just inserted. +**Insert call example with `continue_on_error` option** -```json -{ - "records": [ - { - "table": "cards", - "fields": { - "cardNumber": "f3907186-e7e2-466f-91e5-48e12c2bcbc1", - "cvv": "1989cb56-63da-4482-a2df-1f74cd0dd1a5", - "skyflow_id": "d863633c-8c75-44fc-b2ed-2b58162d1117" - }, - "request_index": 0 - } +```python +from skyflow.error import SkyflowError +from skyflow.vault.data import InsertRequest + +try: + insert_data = [ + {'card_number': '4111111111111111'}, + {'card_numbe': '4111111111111111'}, # Intentional typo card_numbe ] -} + + insert_request = InsertRequest( + table_name = 'table1', + values = insert_data, + return_tokens = True, # returns tokens + continue_on_error = True + ) + + response = client.vault('').insert(insert_request) + print('Response:', response) +except SkyflowError as e: + print('Error Occurred:', e) + ``` -**Insert call [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/insert_with_continue_on_error_sample.py) with `continueOnError` option** +Sample Response ```python -client.insert( - { - "records": [ +InsertResponse( + inserted_fields= + [ { - "table": "cards", - "fields": { - "card_number": "4111111111111111", - "full_name": "john doe" - } - }, - { - "table": "pii_field", - "fields": { - "card_number": "4242424242424200" - "full_name": "jane doe" - } + 'skyflow_id': '89c125d1-3bec-4360-b701-a032dda16500', + 'request_index': 0, + 'card_number': '5479-4229-4622-1393' } + ], + errors= + [ + { + 'request_index': 1, + 'error': 'Insert failed. Column card_numbe is invalid. Specify a valid column.' + } ] - }, InsertOptions(tokens=True, continueOnError=True) ) + ``` -Sample Response +**Insert call example with `upsert` options** -```json -{ - "records": [ - { - "table": "cards", - "fields": { - "card_number": "f37186-e7e2-466f-91e5-48e2bcbc1", - "full_name": "1989cb56-63a-4482-adf-1f74cd1a5", - "skyflow_id": "3daf1a7f-bc7f-4fc9-8c56-a6e4e93231e6" - }, - "request_index": 0 - } - ], - "errors": [ - { - "error": { - "code": 404, - "description": "Object Name pii_field was not found for Vault - requestId : af4aad11-f276-474d-b626-c75c8b35d49e", - "request_index": 1 - } - } - ] -} +```python +from skyflow.error import SkyflowError +from skyflow.vault.data import InsertRequest +try: + insert_data = [ + {"name": 'sample name'}, + ] + + insert_request = InsertRequest( + table_name = 'table1', + values = insert_data, + return_tokens = True, # returns tokens + upsert = "name" # unique column name + ) + + response = client.vault('').insert(insert_request) + print('Response:', response) +except SkyflowError as e: + print('Error Occurred:', e) ``` -**Insert call [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/insert_upsert_sample.py) with `upsert` options** +Skyflow returns tokens, with `upsert` support, for the record you just inserted. ```python -upsertOption = UpsertOption(table="cards",column="cardNumber") -client.insert( - { - "records": [ +InsertResponse( + inserted_fields= + [ { - "table": "cards", - "fields": { - "cardNumber": "41111111111", - "cvv": "123", - }, + 'skyflow_id': 'a8f3ed5d-55eb-4f32-bf7e-2dbf4b9d9097', + 'name': '3f27b3d7-6bf0-432a-acf9-789c0470e2da' } - ] - }, - InsertOptions(tokens=True,upsert=[upsertOption]), + ], + errors=[] ) ``` -Skyflow returns tokens, with `upsert` support, for the record you just inserted. - -```json -{ - "records": [ - { - "table": "cards", - "fields": { - "cardNumber": "f3907186-e7e2-466f-91e5-48e12c2bcbc1", - "cvv": "1989cb56-63da-4482-a2df-1f74cd0dd1a5", - "skyflow_id": "60b32788-12ec-4dd7-9da5-0146c3afbe11" - }, - "request_index": 0 - } - ] -} -``` - ### Detokenize -To retrieve tokens from your vault, you can use the `Detokenize(records: dict, options: DetokenizeOptions)` method.The records parameter takes a dictionary that contains the `records` key that takes an array of records to return. The options parameter is a `DetokenizeOptions` object that provides further options, including `continueOnError` operation, for your detokenize call, as shown below: +To retrieve tokens from your vault, you can use the `detokenize` method. The `DetokenizeRequest` class requires a list of detokenization data to be provided as input. Additionally, the redaction type and continue on error are optional parameters. ```python -{ - "records":[ - { - "token": str , # Token for the record to fetch - "redaction": Skyflow.RedactionType # Optional. Redaction to apply for retrieved data. E.g. RedactionType.MASKED - } - ] -} +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.tokens import DetokenizeRequest + +try: + detokenize_data = ['', '', ''] + + detokenize_request = DetokenizeRequest( + tokens =d etokenize_data, + continue_on_error = False, # optional + redaction_type = RedactionType.PLAIN_TEXT # optional + ) + + response = skyflow_client.vault('').detokenize(detokenize_request) + print('Response:', response) +except SkyflowError as e: + print('Error Occurred:', e) + ``` + Notes: -- `redaction` defaults to [RedactionType.PLAIN_TEXT](#redaction-types). -- `continueOnError` in DetokenizeOptions will default to `True`. -An [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/detokenize_sample.py) of a detokenize call: +- `redaction_type` defaults to `RedactionType.PLAIN_TEXT`. +- `continue_on_error` default valus is `False`. + +An [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/detokenize_records.py) of a detokenize call: ```python +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.tokens import DetokenizeRequest + try: - client.detokenize( - { - "records": [ - { - "token": "45012507-f72b-4f5c-9bf9-86b133bae719" - }, - { - "token": '1r434532-6f76-4319-bdd3-96281e051051', - "redaction": Skyflow.RedactionType.MASKED - }, - { - "token": "invalid-token" - } - ] - } + detokenize_data = ['9738-1683-0486-1480', '6184-6357-8409-6668', '4914-9088-2814-3840'] + + detokenize_request = DetokenizeRequest( + tokens = detokenize_data, + continue_on_error = False, # optional + redaction_type = RedactionType.PLAIN_TEXT # optional ) + + response = skyflow_client.vault('').detokenize(detokenize_request) + print('Response:', response) except SkyflowError as e: - if e.data: - print(e.data) # see note below - else: - print(e) + print('Error Occurred:', e) + ``` Sample response: ```python -{ - "records": [ - { - "token": "131e70dc-6f76-4319-bdd3-96281e051051", - "value": "1990-01-01" - }, - { - "token": "1r434532-6f76-4319-bdd3-96281e051051", - "value": "xxxxxxer", - } - ], - "errors": [ - { - "token": "invalid-token", - "error": { - "code": 404, - "description": "Tokens not found for invalid-token" - } - } - ] -} +DetokenizeResponse( + detokenized_fields=[ + {'token': '9738-1683-0486-1480', 'value': '4111111111111115', 'type': 'STRING'}, + {'token': '6184-6357-8409-6668', 'value': '4111111111111119', 'type': 'STRING'}, + {'token': '4914-9088-2814-3840', 'value': '4111111111111118', 'type': 'STRING'} + ], + errors=[] +) ``` -An [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/detokenize_with_continue_on_error_sample.py) of a detokenize call with continueOnError: +An example of a detokenize call with continue_on_error: ```python +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.tokens import DetokenizeRequest + try: - client.detokenize( - { - "records": [ - { - "token": "45012507-f72b-4f5c-9bf9-86b133bae719" - }, - { - "token": '1r434532-6f76-4319-bdd3-96281e051051', - "redaction": Skyflow.RedactionType.MASKED - } - ] - }, DetokenizeOptions(continueOnError=False) + detokenize_data = ['9738-1683-0486-1480', '6184-6357-8409-6668', '4914-9088-2814-384'] + + detokenize_request = DetokenizeRequest( + tokens = detokenize_data, + continue_on_error = True, # optional + redaction_type = RedactionType.PLAIN_TEXT # optional ) + + response = skyflow_client.vault('').detokenize(detokenize_request) + print('Response:', response) except SkyflowError as e: - if e.data: - print(e.data) # see note below - else: - print(e) + print('Error Occurred:', e) + ``` Sample response: ```python -{ - "records": [ - { - "token": "131e70dc-6f76-4319-bdd3-96281e051051", - "value": "1990-01-01" - }, - { - "token": "1r434532-6f76-4319-bdd3-96281e051051", - "value": "xxxxxxer", - } - ] -} -``` - -### Get +DetokenizeResponse( + detokenized_fields=[ + { + 'token': '9738-1683-0486-1480', + 'value': '4111111111111115', + 'type': 'STRING' + }, + { + 'token': '6184-6357-8409-6668', + 'value': '4111111111111119', + 'type': 'STRING' + } + ], + errors=[ + { + 'token': '4914-9088-2814-384', + 'error': 'Token Not Found' + } + ] +) -To retrieve data using Skyflow IDs or unique column values, use the `get(records: dict,options: GetOptions)` method. The `records` parameter takes a Dictionary that contains either an array of Skyflow IDs or a unique column name and values.The second parameter options is a GetOptions object that retrieves tokens of Skyflow IDs. +``` -Note: +### Tokenize - - You can use either Skyflow IDs or `unique` values to retrieve records. You can't use both at the same time. - - GetOptions parameter applicable only for retrieving tokens using Skyflow ID. - - You can't pass GetOptions along with the redaction type. - - `tokens` defaults to false. +To tokenize data, use the `tokenize` method. The `TokenizeRequest` class is utilized to create a tokenize request. In this request, you specify the `values` parameter, which is a list of dictionaries. Each dictionary contains two keys: `value` and `column_group`. ```python -{ - 'records': [ - { - 'columnName': str, # Name of the unique column. - 'columnValues': [str], # List of unique column values. - 'table': str, # Name of table holding the data. - 'redaction': Skyflow.RedactionType, # Redaction applied to retrieved data. - } - ] -} - or -{ - 'records': [ - { - 'ids': [str], # List of Skyflow IDs. - 'table': str, # Name of table holding the data. - 'redaction': Skyflow.RedactionType, # Redaction applied to retrieved data. - } - ] -} +from skyflow.vault.tokens import TokenizeRequest +tokenize_request = TokenizeRequest( + values = [{ + 'value': '', + 'column_group': '' + }] +) ``` + Sample usage -The following snippet shows how to use the `get()` method. For details, see [get_sample.py](https://github.com/skyflowapi/skyflow-python/blob/main/samples/get_sample.py), - -```python -from skyflow.vault import RedactionType - -skyflowIDs = ['f8d8a622-b557-4c6b-a12c-c5ebe0b0bfd9'] -record = {'ids': skyflowIDs, 'table': 'cards', 'redaction':RedactionType.PLAIN_TEXT} -recordsWithUniqueColumn = - { - 'table': 'test_table', - 'columnName': 'card_number', - 'columnValues': ['123456'], - 'redaction': RedactionType.PLAIN_TEXT - } - -invalidID = ['invalid skyflow ID'] -badRecord = {'ids': invalidID, 'table': 'cards', 'redaction': RedactionType.PLAIN_TEXT} - -records = {'records': [record, badRecord]} - +An [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/tokenize_records.py) of a tokenize call: + +```python +from skyflow.error import SkyflowError +from skyflow.vault.tokens import TokenizeRequest + try: - client.get(records) -except SkyflowError as e: - if e.data: - print(e.data) - else: - print(e) + tokenize_request = TokenizeRequest( + values = [{ + "value": '4111111111111111', + "column_group": "card_number_cg" + }] + ) + + response = client.vault('').tokenize(tokenize_request) + print(response) +except SyntaxError as e: + print('Error Occurred: ', e) ``` Sample response: ```python -{ - 'records': [ - { - 'fields': { - 'card_number': '4111111111111111', - 'cvv': '127', - 'expiry_date': '11/35', - 'fullname': 'monica', - 'skyflow_id': 'f8d8a622-b557-4c6b-a12c-c5ebe0b0bfd9' - }, - 'table': 'cards' - }, - { - 'fields': { - 'card_number': '123456', - 'cvv': '317', - 'expiry_date': '10/23', - 'fullname': 'sam', - 'skyflow_id': 'da26de53-95d5-4bdb-99db-8d8c66a35ff9' - }, - 'table': 'cards' - } - ], - 'errors': [ - { - 'error': { - 'code': '404', - 'description': 'No Records Found' - }, - 'skyflow_ids': ['invalid skyflow id'] - } - ] -} +TokenizeResponse( + tokenized_fields=[ + { + 'token': '5479-4229-4622-1393' + } + ] +) + ``` -The following snippet shows how to use the `get()` method with GetOptions. +### Get + +To retrieve data using Skyflow IDs or unique column values, use the `get` method. The `GetRequest` class is used to create a get request, where you specify parameters such as the table name, redaction type, Skyflow IDs, column names, column values, and return tokens. If Skyflow IDs are provided, column names and column values cannot be used. Similarly, if column names or column values are provided, Skyflow IDs cannot be used. ```python -from skyflow.vault import GetOptions +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.data import GetRequest + +GetRequest( + table = '', + ids = ['SKYFLOW_ID1>', 'SKYFLOW_ID2>'], + return_tokens = True, + redaction_type = RedactionType.PLAIN_TEXT +) + +# or + +GetRequest( + table = '', + column_name ='', + column_values = ['COLUMN_VALUE1>', 'COLUMN_VALUE2>'], + redaction_type = RedactionType.PLAIN_TEXT +) +``` + +Sample usage + +### Get By Column Name and Column Values + +The following snippet shows how to use the `get` method using column names and column values. For details, see [get_column_values.py](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/get_column_values.py), + +```python +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.data import GetRequest -{ - 'records': [ - { - 'ids': ['56513264-fc45-41fa-9cb0-d1ad3602bc49','da26de53-95d5-4bdb-99db-8d8c66a35ff9'], - 'table': 'cards', - } - ] -} - try: - client.get(records, GetOptions(True)) + column_values = [ + '123456' + ] + + get_request = GetRequest( + table = 'table1', + column_name = 'card_number', # It must be configured as unique in the schema. + column_values = column_values, + redaction_type = RedactionType.PLAIN_TEXT + ) + + response = skyflow_client.vault('').get(get_request) + print('Response:', response) except SkyflowError as e: - if e.data: - print(e.data) - else: - print(e) + print('Error Occurred:', e) + ``` Sample response: ```python -{ - 'records': [ - { - 'fields': { - 'card_number': '4555-5176-5936-1930', - 'cvv': '6ad5f708-2061-453e-9491-618a1f29a688', - 'skyflow_id': '56513264-fc45-41fa-9cb0-d1ad3602bc49' - }, - 'table': 'cards' - }, - { - 'fields': { - 'card_number': '8882-7418-2776-6660', - 'cvv': '25260679-e339-4b33-a5b0-c8b08df77af7', - 'skyflow_id': 'da26de53-95d5-4bdb-99db-8d8c66a35ff9' - }, - 'table': 'cards' - } - ], - 'errors': [] -} -``` +GetResponse( + data=[ + { + 'card_number': '123456', + 'skyflow_id': '4f7af9f9-09e0-4f47-af8e-04c9b1ee1968' + } + ], + errors=[] +) -### Get By Id +``` -For retrieving using SkyflowID's, use the get_by_id(records: dict) method. The records parameter takes a Dictionary that contains records to be fetched as shown below: +### Get By Skyflow Ids ```python -{ - "records": [ - { - "ids": [str], # List of SkyflowID's of the records to be fetched - "table": str, # name of table holding the above skyflow_id's - "redaction": Skyflow.RedactionType, # redaction to be applied to retrieved data - } - ] -} +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.data import GetRequest + +GetRequest( + table = '', + ids = ['SKYFLOW_ID1>', 'SKYFLOW_ID2>'], + return_tokens = True, + redaction_type = RedactionType.PLAIN_TEXT +) ``` #### Redaction Types + There are 4 accepted values in Skyflow.RedactionTypes: - `PLAIN_TEXT` @@ -603,245 +793,244 @@ There are 4 accepted values in Skyflow.RedactionTypes: - `REDACTED` - `DEFAULT` -An [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/get_by_ids_sample.py) of get_by_id call: +An [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/get_records.py) of get by skyflow ids call: ```python -from skyflow.vault import RedactionType +from skyflow.error import SkyflowError +from skyflow.utils.enums import RedactionType +from skyflow.vault.data import GetRequest -skyflowIDs = [ - "f8d8a622-b557-4c6b-a12c-c5ebe0b0bfd9", - "da26de53-95d5-4bdb-99db-8d8c66a35ff9" -] -record = {"ids": skyflowIDs, "table": "cards", "redaction": RedactionType.PLAIN_TEXT} +try: + get_request = GetRequest( + table = 'table1', + ids = ['aea64577-12b1-4682-aad5-a183194c3f3d', 'b385c565-86eb-4af2-b959-8376f9b0754b'], + redaction_type = RedactionType.PLAIN_TEXT + ) -invalidID = ["invalid skyflow ID"] -badRecord = {"ids": invalidID, "table": "cards", "redaction": RedactionType.PLAIN_TEXT} + response = client.vault('').get(get_request) + print('Response:', response) +except SkyflowError as e: + print('Error Occurred:', e) +``` -records = {"records": [record, badRecord]} +Sample response: + +```python +GetResponse( + data=[ + { + 'card_number': '4555555555555553', + 'skyflow_id': 'aea64577-12b1-4682-aad5-a183194c3f3d' + }, + { + 'card_number': '4555555555555559', + 'skyflow_id': 'b385c565-86eb-4af2-b959-8376f9b0754b' + } + ], + errors=[] +) + +``` + +The following snippet shows how to use the `get()` method with return_tokens true. + +```python +from skyflow.error import SkyflowError +from skyflow.vault.data import GetRequest try: - client.get_by_id(records) + get_request = GetRequest( + table = 'table1', + ids = ['aea64577-12b1-4682-aad5-a183194c3f3d', 'b385c565-86eb-4af2-b959-8376f9b0754b'], + return_tokens = True + ) + + response = client.vault('').get(get_request) + print('Response:', response) except SkyflowError as e: - if e.data: - print(e.data) # see note below - else: - print(e) + print('Error Occurred:', e) + ``` Sample response: ```python -{ - "records": [ - { - "fields": { - "card_number": "4111111111111111", - "cvv": "127", - "expiry_date": "11/35", - "fullname": "myname", - "skyflow_id": "f8d8a622-b557-4c6b-a12c-c5ebe0b0bfd9" - }, - "table": "cards" - }, - { - "fields": { - "card_number": "4111111111111111", - "cvv": "317", - "expiry_date": "10/23", - "fullname": "sam", - "skyflow_id": "da26de53-95d5-4bdb-99db-8d8c66a35ff9" - }, - "table": "cards" - } - ], - "errors": [ - { - "error": { - "code": "404", - "description": "No Records Found" - }, - "skyflow_ids": ["invalid skyflow id"] - } - ] -} +GetResponse( + data=[ + { + 'card_number': '3562-0140-8820-7499', + 'skyflow_id': 'aea64577-12b1-4682-aad5-a183194c3f3d' + }, + { + 'card_number': '3998-2139-0328-0697', + 'skyflow_id': 'b385c565-86eb-4af2-b959-8376f9b0754b' + } + ], + errors=[] +) ``` -`Note:` While using detokenize and get_by_id methods, there is a possibility that some or all of the tokens might be invalid. In such cases, the data from response consists of both errors and detokenized records. In the SDK, this will raise a SkyflowError Exception and you can retrieve the data from this Exception object as shown above. - ### Update -To update data in your vault, use the `update(records: dict, options: UpdateOptions)` method. The `records` parameter takes a Dictionary that contains records to fetch. If `UpdateTokens` is `True`, Skyflow returns tokens for the record you just updated. If `UpdateOptions` is `False`, Skyflow returns IDs for the record you updated. +To update data in your vault, use the `update` method. The `UpdateRequest` class is used to create an update request, where you specify parameters such as the table name, data (as a dictionary), tokens, return_tokens, and token_strict. If `return_tokens` is set to True, Skyflow returns tokens for the updated records. If `return_tokens` is set to False, Skyflow returns IDs for the updated records. ```python -# Optional, indicates whether to return all fields for updated data. Defaults to 'true'. -options: UpdateOptions -``` +from skyflow.error import SkyflowError +from skyflow.vault.data import UpdateRequest -```python -{ - 'records': [ - { - 'id': str, # Skyflow ID of the record to be updated. - 'table': str, # Name of table holding the skyflowID. - 'fields': { - str: str # Name of the column and value to update. - } - } - ] -} +try: + update_data = { + 'skyflow_id': '', + '': '' + } + + update_request = UpdateRequest( + table='TABLE_NAME', + data=update_data + ) + + response = skyflow_client.vault('VAULT_ID').update(update_request) + print('Response:', response) +except SkyflowError as e: + print('Error Occurred:', e) ``` + Sample usage -The following snippet shows how to use the `update()` method. For details, see [update_sample.py](https://github.com/skyflowapi/skyflow-python/blob/main/samples/update_sample.py), +The following snippet shows how to use the `update()` method. For details, see [update_record.py](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/update_record.py), ```python -records = { - 'records': [ - { - 'id': '56513264-fc45-41fa-9cb0-d1ad3602bc49', - 'table': 'cards', - 'fields': { - 'card_number': '45678910234' - } - } - ] - } +from skyflow.error import SkyflowError +from skyflow.vault.data import UpdateRequest + try: - client.update(records, UpdateOptions(True)) + update_data = { + 'skyflow_id': '3b80c76a-c0d7-4c02-be00-b4128cb0f315', + 'card_number': '4111111111117777' + } + + update_request = UpdateRequest( + table = 'table1', + data = update_data + ) + + response = skyflow_client.vault('').update(update_request) + print('Response:', response) except SkyflowError as e: - if e.data: - print(e.data) - else: - print(e) + print('Error Occurred:', e) ``` Sample response -`UpdateOptions` set to `True` +`return_tokens` set to `True` ```python -{ - 'records':[ - { - 'id':'56513264-fc45-41fa-9cb0-d1ad3602bc49', - 'fields':{ - 'card_number':'0051-6502-5704-9879' - } - } - ], - 'errors':[] -} -``` - -`UpdateOptions` set to `False` +UpdateResponse( + updated_field={ + 'skyflow_id': '3b80c76a-c0d7-4c02-be00-b4128cb0f315', + 'card_number': '4131-1751-0217-8491' + }, + errors=[] +) -```python -{ - 'records':[ - { - 'id':'56513264-fc45-41fa-9cb0-d1ad3602bc49' - } - ], - 'errors':[] -} ``` -Sample Error +`return_tokens` set to `False` ```python -{ - 'records':[ - { - 'id':'56513264-fc45-41fa-9cb0-d1ad3602bc49' - } - ], - 'errors':[ - { - 'error':{ - 'code':404, - 'description':'Token for skyflowID doesn"t exist in vault - Request ID: a8def196-9569-9cb7-9974-f899f9e4bd0a' - } - } - ] -} +UpdateResponse( + updated_field={'skyflow_id': '3b80c76a-c0d7-4c02-be00-b4128cb0f315'}, + errors=[] +) + ``` ### Delete -For deleting using SkyflowID's, use the delete(records: dict) method. The records parameter takes a Dictionary that contains records to be deleted as shown below: +To delete records using Skyflow IDs, use the `delete` method. The `DeleteRequest` class accepts a list of Skyflow IDs that you want to delete, as shown below: ```python -{ - "records": [ - { - "id": str, # SkyflowID of the records to be deleted - "table": str, # name of table holding the above skyflow_id - }, - { - "id": str, # SkyflowID of the records to be deleted - "table": str, # name of table holding the above skyflow_id - } - ] -} +from skyflow.error import SkyflowError +from skyflow.vault.data import DeleteRequest + +primary_delete_ids = [ + 'SKYFLOW_ID1', + 'SKYFLOW_ID2', + 'SKYFLOW_ID3', +] + +delete_request = DeleteRequest( + table = '', + ids = primary_delete_ids +) ``` -An [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/delete_sample.py) of delete call: +An [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/delete_records.py) of delete call: ```python +from skyflow.error import SkyflowError +from skyflow.vault.data import DeleteRequest -skyflowID = "b3d52e6d-1d6c-4750-ba28-aa30d04dbf01" -record = {"id": skyflowID, "table": "cards"} - -invalidID = "invalid skyflow ID" -badRecord = {"id": invalidID, "table": "cards"} +try: + delete_ids = [ + '77e093f8-3ace-4295-8683-bb6745d6178e', + 'bf5989cc-79e8-4b2f-ad71-cb20b0a76091' + ] -records = {"records": [record, badRecord]} + delete_request = DeleteRequest( + table='table1', + ids=delete_ids + ) -try: - client.delete(records) + response = client.vault('').delete(delete_request) + print('Response:', response) except SkyflowError as e: - if e.data: - print(e.data) # see note below - else: - print(e) + print('Error Occurred:', e) + ``` Sample response: ```python -{ - "records":[ - { - "skyflow_id":"b3d52e6d-1d6c-4750-ba28-aa30d04dbf01", - "deleted":true - } - ], - "errors":[ - { - "id":"invalid skyflow ID", - "error":{ - "code":404, - "description":"No Records Found - request id: 239d462c-aa13-9f9d-a349-165b3dd11217" - } - } - ] -} +DeleteResponse( + deleted_ids=[ + '77e093f8-3ace-4295-8683-bb6745d6178e', + 'bf5989cc-79e8-4b2f-ad71-cb20b0a76091' + ], + errors=[] +) + ``` ### Invoke Connection -Using Skyflow Connection, end-user applications can integrate checkout/card issuance flow with their apps/systems. To invoke connection, use the invoke_connection(config: Skyflow.ConnectionConfig) method of the Skyflow client. +Using Skyflow Connection, end-user applications can integrate checkout/card issuance flow with their apps/systems. To invoke connection, use the `invoke` method of the Skyflow client. ```python -config = ConnectionConfig( - connectionURL: str, # connection url received when creating a skyflow connection integration - methodName: Skyflow.RequestMethod, - pathParams: dict, # optional - queryParams: dict, # optional - requestHeader: dict, # optional - requestBody: dict, # optional +from skyflow.error import SkyflowError +from skyflow.vault.connection import InvokeConnectionRequest + +body = { + 'KEY1': 'VALUE1', + 'KEY2': 'VALUE2' +} +headers = { + 'KEY1': 'VALUE1' +} +path_params = { + 'KEY1': 'VALUE1' +} +query_params = { + 'KEY1': 'VALUE1' +} + +invoke_connection_request = InvokeConnectionRequest( + method = Method.POST, + body = body, + headers = headers, # optional + path_params = path_params, # optional + query_params = query_params # optional ) -client.invokeConnection(config) ``` `methodName` supports the following methods: @@ -852,77 +1041,88 @@ client.invokeConnection(config) - PATCH - DELETE -**pathParams, queryParams, requestHeader, requestBody** are the JSON objects represented as dictionaries that will be sent through the connection integration url. +**path_params, query_params, request_header, request_body** are the JSON objects represented as dictionaries that will be sent through the connection integration url. -An [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/invoke_connection_sample.py) of invoke_connection: +An [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/invoke_connection.py) of invoke_connection: ```python -from skyflow.vault import ConnectionConfig, Configuration, RequestMethod +from skyflow import Skyflow +from skyflow import LogLevel +from skyflow.utils.enums import Method +from skyflow.error import SkyflowError +from skyflow.vault.connection import InvokeConnectionRequest + +credentials = { + 'path': '/path/to/credentials.json', +} -bearerToken = '' -def token_provider(): - global bearerToken - if !(is_expired(bearerToken)): - return bearerToken - bearerToken, _ = generate_bearer_token('') - return bearerToken +client = ( + Skyflow.builder() + .add_connection_config({ + 'connection_id': '', + 'connection_url': '', + 'credentials': credentials + }) + .set_log_level(LogLevel.OFF) + .build() +) -try: - config = Configuration('', '', token_provider) - connectionConfig = ConnectionConfig('', RequestMethod.POST, - requestHeader={ - 'Content-Type': 'application/json', - 'Authorization': '' - }, - requestBody= # For third party integration - { - "expirationDate": { - "mm": "12", - "yy": "22" - } +invoke_connection_request = InvokeConnectionRequest( + method=Method.POST, + body={ + 'card_number': '4337-1696-5866-0865', + 'ssn': '524-41-4248' }, - pathParams={'cardID': ''}) # param as in the example - client = Client(config) + headers = { + 'Content-Type': 'application/json' + } +) + +response = client.connection('').invoke(invoke_connection_request) + +print(response) - response = client.invoke_connection(connectionConfig) - print('Response:', response) -except SkyflowError as e: - print('Error Occurred:', e) ``` Sample response: ```python -{ - "receivedTimestamp": "2021-11-05 13:43:12.534", - "processingTimeinMs": 12, - "resource": { - "cvv2": "558" +ConnectionResponse( + { + 'card_number': '4337-1696-5866-0865', + 'ssn': '524-41-4248', + 'request_id': '84796a11-0b7d-4cb0-a348-cf9fefb5886f,84796a11-0b7d-4cb0-a348-cf9fefb5886f' } -} +) + ``` ### Query -To retrieve data with SQL queries, use the `query(queryInput, options)` method. `queryInput` is an object that takes the `query` parameter as follows: +To retrieve data with SQL queries, use the `query` method. `QueryRequest` is class that takes the `query` parameter as follows: ```python -{ - query: str # SQL query statement -} +from skyflow.vault.data import QueryRequest + +query_request = QueryRequest( + query= '' +) ``` See [Query your data](https://docs.skyflow.com/query-data/) and [Execute Query](https://docs.skyflow.com/record/#QueryService_ExecuteQuery) for guidelines and restrictions on supported SQL statements, operators, and keywords. -An [example](https://github.com/skyflowapi/skyflow-python/blob/main/samples/query_sample.py) of Query call: +An [example](https://github.com/skyflowapi/skyflow-python/blob/SK-1749-readme/samples/vault_api/query_records.py) of Query call: ```python -queryInput = { - query: "SELECT * FROM cards WHERE skyflow_id='3ea3861-x107-40w8-la98-106sp08ea83f'" -} +from skyflow.error import SkyflowError +from skyflow.vault.data import QueryRequest + +query_request = QueryRequest( + query = "SELECT * FROM cards WHERE skyflow_id='3ea3861-x107-40w8-la98-106sp08ea83f'" +) try: - client.query(queryInput) + skyflow_client.vault('').query(query_request) except SkyflowError as e: if e.data: print(e.data) @@ -933,37 +1133,58 @@ except SkyflowError as e: Sample Response ```python -{ - "records": [ - { - "fields": { - "card_number": "XXXXXXXXXXXX1111", - "card_pin": "*REDACTED*", - "cvv": "", - "expiration_date": "*REDACTED*", - "expiration_month": "*REDACTED*", - "expiration_year": "*REDACTED*", - "name": "a***te", - "skyflow_id": "3ea3861-x107-40w8-la98-106sp08ea83f", - "ssn": "XXX-XX-6789", - "zip_code": None - }, - "tokens": None - } - ] -} +QueryResponse( + fields=[ + { + 'card_number': 'XXXXXXXXXXXX1112', + 'name': 'S***ar', + 'skyflow_id': '4f7af9f9-09e0-4f47-af8e-04c9b1ee1968', + 'tokenized_data': {} + } + ], + errors=[] +) ``` ## Logging -The skyflow python SDK provides useful logging using python's inbuilt `logging` library. By default the logging level of the SDK is set to `LogLevel.ERROR`. This can be changed by using `set_log_level(logLevel)` as shown below: +The skyflow python SDK provides useful logging using python's inbuilt `logging` library. By default the logging level of the SDK is set to `LogLevel.ERROR`. This can be changed by using `set_log_level(log_level)` as shown below: ```python -import logging -from skyflow import set_log_level, LogLevel +from skyflow import Skyflow +from skyflow import LogLevel +from skyflow import Env + +# To generate Bearer Token from credentials string. +skyflow_credentials = { + 'clientID': '', + 'clientName': '', + 'tokenURI': '', + 'keyID': '', + 'privateKey': '', + } +credentials_string = json.dumps(skyflow_credentials) + +# Pass one of api_key, token, credentials_string & path as credentials +credentials = { + 'token': 'BEARER_TOKEN', # bearer token + # api_key: "API_KEY", # API_KEY + # path: "PATH", # path to credentials file + # credentials_string: credentials_string, # credentials as string +} -logging.basicConfig() # You can set the basic config here -set_log_level(LogLevel.INFO) # sets the skyflow SDK log level to INFO +client = ( + Skyflow.builder() + .add_vault_config({ + 'vault_id': 'VAULT_ID', # primary vault + 'cluster_id': 'CLUSTER_ID', # ID from your vault URL Eg https://{clusterId}.vault.skyflowapis.com + 'env': Env.PROD, # Env by default it is set to PROD + 'credentials': credentials # individual credentials + }) + .add_skyflow_credentials(credentials) # skyflow credentials will be used if no individual credentials are passed + .set_log_level(LogLevel.INFO) # set log level by default it is set to ERROR + .build() +) ``` Current the following 5 log levels are supported: