///|
/// `Client` represents an authorized b2 client.
struct Client {
/// The identifier for the account.
account_id : String // `json:"accountId"`
/// A data structure that groups the information you need by API suite.
api_info : APIInfo // `json:"apiInfo"`
/// An authorization token to use with all calls, other than b2_authorize_account, that need an Authorization header. This authorization token is valid for at most 24 hours.
authorization_token : String // `json:"authorizationToken"`
/// Expiration timestamp for the application key.
application_key_expiration_timestamp : Int? // `json:"applicationKeyExpirationTimestamp,omitempty"`
/// This client is used to interact with this bucket.
bucket_id : String
bucket_name : String
} derive(Show)
///|
fn Client::from_json(
body : String,
bucket_id : String,
bucket_name : String,
) -> Client raise ClientError {
let json = @json.parse(body) catch { e => raise ClientError(e.to_string()) }
//
match json {
{
"accountId": String(account_id),
"apiInfo": Object(api_info),
"authorizationToken": String(authorization_token),
"applicationKeyExpirationTimestamp": application_key_expiration_timestamp,
..
} => {
let application_key_expiration_timestamp = match
application_key_expiration_timestamp {
Number(v, ..) => Some(v.to_int())
_ => None
}
let api_info = APIInfo::from_json(api_info)
{
account_id,
api_info,
authorization_token,
application_key_expiration_timestamp,
bucket_id,
bucket_name,
}
}
_ => raise ClientError("unable to parse Client: \{json}")
}
}
///|
test "Client::from_json - invalid apiInfo structure" {
let invalid_apiInfo_json =
#|{
#| "accountId": "12345",
#| "apiInfo": "invalidApiInfo",
#| "authorizationToken": "auth_token",
#| "applicationKeyExpirationTimestamp": 1672531200
#|}
try {
let client = Client::from_json(
invalid_apiInfo_json, "some-bucket-id", "some-bucket-name",
)
raise ClientError("expected failure, but got: \{client}")
} catch {
ClientError(e) =>
assert_eq(
e,
(
#|unable to parse Client: Object({"accountId": String("12345"), "apiInfo": String("invalidApiInfo"), "authorizationToken": String("auth_token"), "applicationKeyExpirationTimestamp": Number(1672531200)})
),
)
}
}
///|
test "Client::from_json - partial valid JSON input" {
let partial_valid_json =
#|{
#| "accountId": "12345",
#| "apiInfo": {
#| "storageApi": {
#| "absoluteMinimumPartSize": 5000000,
#| "apiUrl": "https://apiNNN.backblazeb2.com"
#| }
#| },
#| "authorizationToken": "auth_token"
#|}
try {
let client = Client::from_json(
partial_valid_json, "some-bucket-id", "some-bucket-name",
)
raise ClientError("expected failure, but got: \{client}")
} catch {
ClientError(e) =>
assert_eq(
e,
(
#|unable to parse Client: Object({"accountId": String("12345"), "apiInfo": Object({"storageApi": Object({"absoluteMinimumPartSize": Number(5000000), "apiUrl": String("https://apiNNN.backblazeb2.com")})}), "authorizationToken": String("auth_token")})
),
)
}
}
///|
test "Client::from_json - random JSON input" {
let random_json =
#|{
#| "randomField": "randomValue",
#| "anotherRandomField": 12345
#|}
try {
let client = Client::from_json(
random_json, "some-bucket-id", "some-bucket-name",
)
raise ClientError("expected failure, but got: \{client}")
} catch {
ClientError(e) =>
assert_eq(
e,
(
#|unable to parse Client: Object({"randomField": String("randomValue"), "anotherRandomField": Number(12345)})
),
)
}
}
///|
test "Client::from_json - empty JSON input" {
let empty_json = "{}"
try {
let client = Client::from_json(
empty_json, "some-bucket-id", "some-bucket-name",
)
raise ClientError("expected failure, but got: \{client}")
} catch {
ClientError(e) =>
assert_eq(
e,
(
#|unable to parse Client: Object({})
),
)
}
}
///|
test "Client::from_json - missing required fields" {
let missing_fields_json =
#|{
#| "accountId": "12345",
#| "apiInfo": {},
#| "authorizationToken": "auth_token"
#|}
try {
let client = Client::from_json(
missing_fields_json, "some-bucket-id", "some-bucket-name",
)
raise ClientError("expected failure, but got: \{client}")
} catch {
ClientError(e) =>
assert_eq(
e,
(
#|unable to parse Client: Object({"accountId": String("12345"), "apiInfo": Object({}), "authorizationToken": String("auth_token")})
),
)
}
}
///|
test "Client::from_json - invalid JSON input" {
let invalid_json = "invalid JSON string"
try {
let client = Client::from_json(
invalid_json, "some-bucket-id", "some-bucket-name",
)
raise ClientError("expected failure, but got: \{client}")
} catch {
ClientError(e) => assert_eq(e, "Invalid character 'i' at line 1, column 0")
}
}
///|
test "Client::from_json - valid JSON input with nulls" {
let valid_json =
#|{
#| "accountId": "12345",
#| "apiInfo": {
#| "storageApi": {
#| "absoluteMinimumPartSize": 5000000,
#| "apiUrl": "https://apiNNN.backblazeb2.com",
#| "bucketId": null,
#| "bucketName": null,
#| "capabilities": ["deleteFiles", "readFiles"],
#| "downloadUrl": "https://f001.backblazeb2.com",
#| "infoType": "storageApi",
#| "namePrefix": null,
#| "recommendedPartSize": 100000000,
#| "s3ApiUrl": "https://s3.us-west-NNN.backblazeb2.com"
#| }
#| },
#| "authorizationToken": "auth_token",
#| "applicationKeyExpirationTimestamp": null
#|}
inspect(
Client::from_json(valid_json, "some-bucket-id", "some-bucket-name"),
content=(
#|{account_id: "12345", api_info: {storage_api: {absolute_minimum_part_size: 5000000, api_url: "https://apiNNN.backblazeb2.com", bucket_id: None, bucket_name: None, capabilities: ["deleteFiles", "readFiles"], download_url: "https://f001.backblazeb2.com", info_type: "storageApi", name_prefix: None, recommended_part_size: 100000000, s3apiurl: "https://s3.us-west-NNN.backblazeb2.com"}}, authorization_token: "auth_token", application_key_expiration_timestamp: None, bucket_id: "some-bucket-id", bucket_name: "some-bucket-name"}
),
)
}