Developers

Slider

Our SDKs make it easy and secure to store records in their country of origin

1

Create an account and
get an API key

2

Use the SDK for your
language

3

You must use an InCountry SDK
to ensure that data is encrypted

Developer Tabs

Installation

The recommended way to install the SDK is to use pipenv (or pip):

$ pipenv install incountry

Usage

To access your data in InCountry using Python SDK, you need to create an instance of Storage class.

from incountry import Storage

storage = Storage(
    api_key="string",                 # Required to be passed in, or as environment variable INC_API_KEY
    environment_id="string",          # Required to be passed in, or as environment variable INC_ENVIRONMENT_ID
    endpoint="string",                # Optional. Defines API URL
    encrypt=bool,                     # Optional. If False, encryption is not used
    debug=bool,                       # Optional. If True enables some debug logging
    secret_key_accessor=accessor,     # Instance of SecretKeyAccessor class. Used to fetch encryption secret
)

api_key and environment_id can be fetched from your dashboard on Incountry site.

endpoint defines API URL and is used to override default one.

You can turn off encryption (not recommended). Set encrypt property to false if you want to do this.

Encryption key

secret_key_accessor is used to pass a secret used for encryption.

Note: even though PBKDF2 is used internally to generate a cryptographically strong encryption key, you must make sure that you use strong enough password.

Here are some examples how you can use SecretKeyAccessor.

# Get secret from variable
from incountry import SecretKeyAccessor

password = "password"
secret_key_accessor = SecretKeyAccessor(lambda: password)

# Get secret via http request
from incountry import SecretKeyAccessor
import requests as req

def get_secret():
    url = "<your_secret_url>"
    r = req.get(url)
    return r.json().get("secret") # assuming response is {"secret": "password"}

secret_key_accessor = SecretKeyAccessor(get_secret)

Writing data to Storage

Use write method in order to create a record.

record = storage.write(
    country="string",     # Required country code of where to store the data
    key="string",         # Required record key
    body="string",        # Optional payload
    profile_key="string"# Optional
    range_key=integer,    # Optional
    key2="string",        # Optional
    key3="string",        # Optional
)

# `write` returns created record on success

Encryption

InCountry uses client-side encryption for your data. Note that only body is encrypted. Some of other fields are hashed. Here is how data is transformed and stored in InCountry database:

{
    key,           # hashed
    body,          # encrypted
    profile_key,   # hashed
    range_key,     # plain
    key2,          # hashed
    key3,          # hashed
}

Reading stored data

Stored record can be read by key using readAsync method. It accepts an object with two fields: country and key

record = storage.read(
    country="string",      # Required country code
    key="string",          # Required record key
)

Find records

It is possible to search by random keys using find method.

records = storage.find(country, limit, offset, **filter_kwargs)

Parameters: country – country code, limit – maximum amount of records you’d like to retrieve. Defaults to 100, offset – specifies the number of records to skip, filter_kwargs – a filter parameters.

Here is the example of how find method can be used:

records = storage.find(country="us", limit=10, offset=10, key2="kitty", key3=["mew", "purr"])

This call returns all records with key2 equals kitty AND key3 equals mew OR purr. The options parameter defines the number of records to return and the starting index. It can be used for pagination. Note: SDK returns 100 records at most.

The return object looks like the following:

  {
    "data": [...],
    "meta": {
        "limit": 10,
        "offset": 10,
        "total": 124,    # total records matching filter, ignoring limit
        }
  }

You can use the following types for filter parameters. Single value:

key2="kitty"

One of the values:

key3=["mew", "purr"]

range_key is a numeric field so you can use range filter requests, for example:

range_key={"$lt": 1000} # search for records with range_key < 1000

Available request options for range_key$lt$lte$gt, $gte.

You can search by any keys: keykey2key3profile_keyrange_key.

Find one record matching filter

If you need to find the first record matching filter, you can use the find_one method.

record = storage.find_one(country, offset, **filter_kwargs)

If record is not found, it will return None.

Delete records

Use deleteAsync method in order to delete a record from InCountry storage. It is only possible using key field.

storage.delete(
    country="string",    # Required country code
    key="string",        # Required record key
)

# `delete` will raise an Exception if fails

Testing Locally

  1. In terminal run pipenv run tests for unit tests
  2. In terminal run pipenv run integrations to run integration tests

Installation

SDK is available via NPM:

npm install incountry --save

Usage

To access your data in InCountry using NodeJS SDK, you need to create an instance of Storage class.

const Storage= require('incountry/storage');
const storage = new Storage({
    apiKey="string",                 // Required to be passed in, or as environment variable INC_API_KEY
    environmentId="string",          // Required to be passed in, or as environment variable INC_ENVIRONMENT_ID
    endpoint="string",               // Optional. Defines API URL
    encrypt=string,                  // Optional. If false, encryption is not used
},
    secretKeyAccessor               // Instance of SecretKeyAccessor class. Used to fetch encryption secret
    logger                          // Allows for logging at different log levels in a consistent manner
);

apiKey and environmentId can be fetched from your dashboard on Incountry site.

endpoint defines API URL and is used to override default one.

You can turn off encryption (not recommended). Set encrypt property to false if you want to do this.

Encryption key

secretKeyAccessor is used to pass a secret used for encryption.

Note: even though PBKDF2 is used internally to generate a cryptographically strong encryption key, you must make sure that you use strong enough password.

Here are some examples how you can use SecretKeyAccessor.

const SecretKeyAccessor = require('incountry/secret-key-accessor');
const secretKeyAccessor = new SecretKeyAccessor(() => {
    return 'longAndStrongPassword'
});

// Asynchronous accessor
const secretKeyAccessor = new SecretKeyAccessor(async () => {
    const password = await getPasswordFromSomewhere();
    return password;
});

// Using promises
const secretKeyAccessor = new SecretKeyAccessor(() => new Promise((resolve) => {
    getPasswordFromSomewhere().then(resolve);
}));

Logging

By default SDK outputs logs into console in JSON format. You can override this behavior passing logger object. Logger object must look like the following:

const customLogger = {
	write: (logLevel, message) => {}
};

Writing data to Storage

Use writeAsync method in order to create/overwrite a record for a given key.

const writeResponse = await storage.writeAsync({
    country: 'string',       # Required country code of where to store the data
    key: 'string',           # Required record key
    body: 'string',          # Optional payload
    profile_key: 'string',   # Optional
    range_key: integer,      # Optional
    key2: 'string',          # Optional
    key3: 'string',          # Optional
}

Encryption

InCountry uses client-side encryption for your data. Note that only body is encrypted. Some of other fields are hashed. Here is how data is transformed and stored in InCountry database:

{
    key,           # hashed
    body,          # encrypted
    profile_key,   # hashed
    range_key,     # plain
    key2,          # hashed
    key3,          # hashed
}

Reading stored data

Stored record can be read by key using readAsync method. It accepts an object with two fields: country and key

const readResponse = await storage.readAsync({
    country:"string",      # Required country code
    key:"string",          # Required record key
)

// Use readResponse.status for status code, and readResponse.data for payload received.

Note that readAsync returns a Promise which is always fulfilled. Use status property in order check if operation was successful or not.

Find records

It is possible to search by random keys using find method.

const records = await storage.find(country, filter, options);

Parameters: country – country code, filter – a filter object (see below), options – an object containing search options.

Here is the example of how find method can be used:

const records = await storage.find('us', {
	key2: 'kitty',
	key3: ['mew', 'purr'],
}, {
	limit: 10,
	offset: 10
});

This call returns all records with key2 equals kitty AND key3 equals mew OR purr. The options parameter defines the number of records to return and the starting index. It can be used to implement pagination. Note: SDK returns 100 records at most.

The return object looks like the following:

{
	data: [/* kitties */],
	meta: {
		limit: 10,
		offset: 10,
		total: 124 // total records matching filter, ignoring limit
	}
}

You can use the following types for filter fields. Single value:

{
	key2: 'kitty'
}

One of the values:

{
	key3: ['mew', 'purr']
}

range_key is a numeric field so you can use range filter requests, for example:

{
	range_key: { $lt: 1000 } // search for records with range_key <1000
}

Available request options for range_key$lt$lte$gt, $gte. You can search by any keys: keykey2key3profile_keyrange_key.

Find one record matching filter

If you need to find the first record matching filter, you can use the findOne method.

const record = await storage.findOne(country, filter);

If record not found, it will return null.

Delete records

Use deleteAsync method in order to delete a record from InCountry storage. It is only possible using key field.

const deleteResponse = await storage.deleteAsync({
	country: 'string',      // Required country code
	key: 'string'           // Required record key
});

// Use deleteResponse.status for status code.

Logging

You can specify a custom logger at any time as following:

const logger = {
 write: (level, message) => { console.log(`[${level}] ${message}`) }
}

storage.setLogger(logger);

Logger must be an object implementing method write, which has following signature:

write(level, message)
  • level (string) – message level: DEBUG, INFO, etc.
  • message (string) – log message

Testing Locally

  1. In terminal run npm run test for unit tests
  2. In terminal run npm run integrations to run integration tests

Usage

To access your data in InCountry using Java SDK, you need to create an instance of Storage class.

 Storage(
    String environmentID,
    String apiKey,
    String endpoint,
    boolean encrypt,
    ISecretKeyAccessor secretKeyAccessor
)

# `write` returns created record on success

apiKey and environmentID can be fetched from your dashboard on Incountry site.

endpoint defines API URL and is used to override default one.

You can turn off encryption (not recommended). Set encrypt parameter to false if you want to do this.

Encryption key

secretKeyAccessor is used to pass a secret used for encryption.

Note: even though PBKDF2 is used internally to generate a cryptographically strong encryption key, you must make sure that you use strong enough password.

Here are some examples how you can use SecretKeyAccessor.

public class SimpleSecretKeyAccessor implements ISecretKeyAccessor {
    private String secret;
    public SecretKeyAccessor(String secret) {
        this.secret = secret;
}	
    @Override
    public String getKey() {
        return this.secret;
}
}
SimpleSecretKeyAccessor accessor = new SimpleSecretKeyAccessor("myStrongPassword");

Writing data to Storage

Use write method in order to create/overwrite a record for a given key.

public void write(Record record) throws StorageException, GeneralSecurityException, IOException

Here is how you initialize a record object:

public Record(
    String country,       # Required country code of where to store the data
    String key,           # Required record key
    String body,          # Optional payload
    String profileKey,    # Optional
    Integer rangeKey,     # Optional
    String key2,          # Optional
    String key3,          # Optional
)

Encryption

InCountry uses client-side encryption for your data. Note that only body is encrypted. Some of other fields are hashed.
Here is how data is transformed and stored in InCountry database:

{
    key,           # hashed
    body,          # encrypted
    profile_key,   # hashed
    range_key,     # plain
    key2,          # hashed
    key3,          # hashed
}

Reading stored data

Stored record can be read by key using read method.

public Record read(String country, String key) throws StorageException, IOException, GeneralSecurityException

country is a country code of the record
key is a record key

This method returns Record object. It contains the following properties: country, key, body, key2, key3, profileKey, rangeKey.

These properties can be accessed using getters, for example:

String key2 = record.getKey2();
String body = record.getBody();

Find records

It is possible to search by random keys using find method.

public BatchRecord find(String country, FindFilter filter, FindOptions options) throws StorageException, IOException, GeneralSecurityException

Parameters:
country – country code,
filter – a filter object (see below),
options – an object containing search options.

FindFilter has the following constructor:

public FindFilter(FilterStringParam key, FilterStringParam profileKey, FilterRangeParam rangeKey, FilterStringParam key2, FilterStringParam key3)

And for FindOptions:

public FindOptions(int limit, int offset) throws FindOptionsException

There are two different types of filter params: FilterStringParam and FilterRangeParam.
FilterStringParam is used for all the keys except rangeKey:

public FilterStringParam(String[] value);

or

public FilterStringParam(String value);

Here is the example of how find method can be used:

FindFilter filter = new FindFilter(
    null,
    null,
    null,
    new FilterStringParam("kitty"),
    new FilterStringParam(new String[]{"mew", "pur"})
);

FindOptions options = new FindOptions(10, 10);

BatchRecord records = storage.find("us", filter, options);

This call returns all records with key2 equals kitty AND key3 equals mew OR purr.
Note: SDK returns 100 records at most. Use pagination to iterate over all the records.

Find returns BatchRecord object which contains an array of Record and some metadata:

int count;
int limit;
int offset;
int total;
Record[] records;

These fields can be accessed using getters, for example:

int limit = records.getTotal();

FilterRangeParam works differently from FilterStringParam. rangeKey is an integer non-encrypted field so you can perform range operations on it.
For example you can request all the records with rangeKey less than 1000:

FilterRangeParam rangeParam = new FilterRangeParam("$lt", 1000);

or if you want just to check equality:

FilterRangeParam rangeParam = new FilterRangeParam(1000);

Available request options for FilterRangeParam: $lt, $lte, $gt, $gte.

Find one record matching filter

If you need to find the first record matching filter, you can use the findOne method.
It works the same way as find but returns the first record or null if no matching records.

Delete records

Use delete method in order to delete a record from InCountry storage. It is only possible using key field.

public void delete(String country, String key) throws StorageException, IOException

Here country – country code of the record, key – the record’s key



We have placed cookies on your device to help make this website better. By continuing to use this website you agree to our Cookie Policy. X