Cubby is a Swift wrapper around the JSONBin API that provides a simple interface for storing, categorizing, and fetching Swift structs in the cloud.
API Support
Cubby provides full support for both v2 and v3 of the JSONBin API.
Version 2.0
- Bin
- Create
- Read
- Update
- Delete
- Collection
- Create
- Read
- Schema Doc
- Create
- Read
- Update
- Geolocation
- Lookup
- Experimental
- Request Count
Version 3.0
- Bin
- Create
- Read
- Version Count
- Update
- Update Name
- Update Privacy
- Delete
- Delete Versions
- Collection
- Create
- Fetch in Collection
- Fetch Uncategorized
- Update Name
- Add Schema Doc
- Remove Schema Doc
- Schema Doc
- Create
- Read
- Update
- Update Name
- Other
- List Usage Logs
- Download Usage Log
Usage
Cubby uses specification protocols to indicate which endpoints each API version supports. Use an appropriate instantiation of JSONBin.V2.API
or JSONBin.V3.API
depending on the endpoint you want to call. (Note that version 2 of the JSONBin API is planned for deprecation on January 1, 2022.)
Bin
Create, read, update, or delete bins that represent Swift structs. Each bin represents a single Swift struct and has a privacy setting, an optional name, and an optional collection it belongs to.
public protocol JSONBinV2APIBinSpec: JSONBinV2APISpec {
func createBin<Resource: Encodable>(named name: String?, with resource: Resource, inCollectionWith id: Collection.ID?, private: Bool?) -> Request
>
func
readBin<
Resource:
Decodable>(
with
id: ID,
of
type: Resource.
Type,
at
version: Version
?)
-> Request
func
updateBin<
Resource:
Encodable>(
with
id: ID,
using
resource: Resource,
versioning:
Bool
?)
-> Request
>
func
deleteBin(
with
id: ID)
-> Request
}
public
protocol
JSONBinV3APIBinSpec:
JSONBinV3APISpec {
func
createBin<
Resource:
Encodable>(
named
name:
String
?,
with
resource: Resource,
inCollectionWith
id:
Collection.ID
?,
private:
Bool
?)
-> Request
>
func
readBin<
Resource:
Decodable>(
with
id: ID,
of
type: Resource.
Type,
at
version: Version
?,
includingMetadata:
Bool
?,
usingDotPath
dotPath:
String
?)
-> Request
>
func
versionCount(
ofBinWith
id: ID)
-> Request
func
updateBin<
Resource:
Encodable>(
with
id: ID,
using
resource: Resource,
versioning:
Bool
?)
-> Request
>
func
updateName(
ofBinWith
id: ID,
toName
name:
String)
-> Request
func
updatePrivacy(
ofBinWith
id: ID,
toPrivate
private:
Bool)
-> Request
func
deleteBin(
with
id: ID)
-> Request
func
deleteVersions(
ofBinWith
id: ID,
preservingLatest:
Bool
?)
-> Request
}
Creation Example
var apple = Company(name: "Apple", remoteWorkPolicy: .hybrid)
let request = api.createBin(named: "Apple Computer", with: company)
let creation = try await request.returnedResource
let id = creation.metadata.id
print(creation.resource) // Company(name: "Apple", remoteWorkPolicy: .hybrid)
Read Example
let request = api.readBin(with: id, of type: Company.self, at: .number(1), includingMetadata: false)
let company = try await request.returnedResource
print(company) // Company(name: "Apple Computer", remoteWorkPolicy: .hybrid)
Update Example
apple.remoteWorkPolicy = .disallowed
let request = api.updateBin(with: id, using: apple)
let update = try await request.returnedResource
print(update.resource) // Company(name: "Apple", remoteWorkPolicy: .disallowed)
Update Name Example
let request = api.updateName(ofBinWith: id, toName: "Apple Inc.")
let update = try await request.returnedResource
print(update.resource) // Company(name: "Apple", remoteWorkPolicy: .disallowed)
Version Count Example
let request = api.versionCount(ofBinWith: id)
let versionCount = try await request.returnedResource.metadata.versionCount
print(versionCount) // 1
Deletion Versions Example
let request = api.deleteVersions(ofBinWithID: id, preservingLatest: true)
let deletion = try await request.returnedResource
print(deletion.message) // "Versions for the Bin are deleted successfully and latest version preserved on the base record."
Deletion Example
let request = api.deleteBin(with: id)
let deletion = try await request.returnedResource
print(deletion.message) // "Bin deleted successfully"
Collection
Create, fetch from, or update collections that contain your Swift structs. To ensure a collection only contains structs of the same type, attach a schema document (see below) representing that type to the collection. Once attached, attempting to create a bin in a collection of a different type (i.e., one that cannot be validated by the schema) will fail.
public protocol JSONBinV2APICollectionSpec: JSONBinV2APISpec {
func createCollection(named name: String) -> Request
func
updateCollection(
with
id: ID,
using
action: Action)
-> Request
}
public
protocol
JSONBinV3APICollectionSpec:
JSONBinV3APISpec {
func
createCollection(
named
name:
String)
-> Request
func
fetchBins(
inCollectionWith
id: ID,
sortedBy
sortOrder: Fetch.SortOrder
?)
-> Request<[Fetch.Result]>
func
fetchUncategorizedBins(
sortedBy
sortOrder: Fetch.SortOrder
?)
-> Request<[Fetch.Result]>
func
updateName(
ofCollectionWith
id: ID,
toName
name:
String)
-> Request
func
addSchemaDoc(
with
id: SchemaDoc.ID,
toCollectionWith
collectionID: ID)
-> Request
func
removeSchemaDoc(
fromCollectionWith
id: ID)
-> Request
}
Creation Example
let request = api.createCollection(named: "WFH Companies")
let creation = try await request.returnedResource
let id = creation.metadata.id
print(creation.metadata.name) // "WFH Companies"
Fetch Example
let request = api.fetchBins(inCollectionWith: id)
let companies = try await request.returnedResource
print(companies) // [Company(name: "Twitter", remoteWorkPolicy: .allowed), Company(name: "GitHub", remoteWorkPolicy: .distributed)]
Update Name Example
let request = api.updateName(ofCollectionWith: id, toName: "Remote Companies")
let update = try await request.returnedResource
print(update.metadata.name) // "Remote Companies"
Add Schema Doc Example
let request = api.addSchemaDoc(with: schemaDocID, toCollectionWith: id)
request() // Adds a schema doc to the collection
Remove Schema Doc Example
let request = api.removeSchemaDoc(fromCollectionWith: id)
request() // Removes the schema doc from the collection
Schema Doc
Create, read, or update schema documents that can be attached to collections.
public protocol JSONBinV2APISchemaDocSpec: JSONBinV2APISpec {
func createSchemaDoc<Resource>(for type: Resource.Type, named name: String) -> Request
>
func
readSchemaDoc<
Resource>(
with
id: ID,
for
type: Resource.
Type)
-> Request
>
func
updateSchemaDoc<
Resource>(
with
id: ID,
toSchemaFor
type: Resource.
Type)
-> Request
> }
public
protocol
JSONBinV3APISchemaDocSpec:
JSONBinV3APISpec {
func
createSchemaDoc<
Resource>(
for
type: Resource.
Type,
named
name:
String)
-> Request
>
func
readSchemaDoc<
Resource>(
with
id: ID,
for
type: Resource.
Type)
-> Request
>
func
updateSchemaDoc<
Resource>(
with
id: ID,
toSchemaFor
type: Resource.
Type)
-> Request
>
func
updateName(
ofSchemaDocWith
id: ID,
toName
name:
String)
-> Request
}
Creation Example
extension Company: SchemaAdhering {
static var description: String? {
"A company has both a name and a remote work policy."
}
static var properties: [CodingKeys: SchemaType] {
[
.name: .string,
.remoteWorkPolicy: .string
]
}
}
let request = api.createSchemaDoc(for: Company.self, named: "Company Schema Doc")
let creation = try await request.returnedResource
let id = creation.metadata.id
print(creation.metadata.name) // "Company Schema Doc"
print(creation.schema.title) // "Company"
print(creation.schema.description) // "A company has both a name and a remote work policy."
print(creation.schema.properties) // [.name: .string, .remoteWorkPolicy: .string]
Read Example
let request = api.readSchemaDoc(with: id)
let read = try await request.returnedResource
print(read.metadata.name) // "Company Schema Doc"
print(read.schema.title) // "Company"
print(read.schema.description) // "A company has both a name and a remote work policy."
print(read.schema.properties) // [.name: .string, .remoteWorkPolicy: .string]
Update Example
extension Company: SchemaAdhering {
static var description: String? {
"A company has both a name, a remote work policy, and a number of employees."
}
static var properties: [CodingKeys: SchemaType] {
[
.name: .string,
.remoteWorkPolicy: .string,
.employeeCount: .integer
]
}
}
let request = api.updateSchemaDoc(with: id, toSchemaFor: Company.self)
let update = request.returnedResource
print(update.metadata.name) // "Company Schema Doc"
print(update.schema.title) // "Company"
print(update.schema.description) // "A company has, a name, a remote work policy, and a number of employees."
print(update.schema.properties) // [.name: .string, .remoteWorkPolicy: .string, .employeeCount: .integer]
Update Name Example
let request = api.updateName(ofSchemaDocWith: id, toName: "Company Schema Document")
let update = try await request.returnedResource
print(update.metadata.name) // "Company Schema Document"
Geolocation
Look up geolocation data for an IP address.
public protocol JSONBinV2APIGeoIPSpec: JSONBinV2APISpec {
func lookUpGeolocation(for ipAddress: IPAddress) -> Request
}
Look Up Geolocation Example
let ipAddress = IPAddress("141.158.45.225")
let request = api.lookUpGeolocation(for: ipAddress)
let lookupData = await request.returnedResource.data
print(lookupData.range) // 2375953408..<2375953919
print(lookupData.countryCode) // "US"
print(lookupData.regiounCode) // "PA"
print(lookupData.timeZone) // "America/New_York"
print(lookupData.city) // "Philadelphia"
print(lookupData.coordinates.latitude) // 39.934
print(lookupData.coordinates.longitude) // -75.16
print(lookupData.metroCode) // 504
print(lookupData.accuracyRadius) // 1
Experimental
Get the number of requests remaining for this account.
public protocol JSONBinV2APIExperimentalSpec: JSONBinV2APISpec {
func requestCount() -> Request
}
Request Count Example
let request = api.requestCount()
let count = try await request.returnedResource
print(count.value) // 1000000
Other
List the usage logs for this account, or download a specific usage log.
public protocol JSONBinV3APIOtherSpec: JSONBinV3APISpec {
func listUsageLogs() -> Request
func
downloadUsageLog(
named
name:
String)
-> Request
}
List Usage Logs Example
let ipAddress = IPAddress("141.158.45.225")
let request = api.listUsageLogs
let list = await request.returnedResource
print(list.logNames) // ["12-31-2022", "01-01-2022", "01-02-2022"]
Download Usage Log Example
let ipAddress = IPAddress("141.158.45.225")
let request = api.downloadUsageLog(named: "01-01-2022")
let usageLog = await request.returnedResource
print(usageLog.compressed) // ZIP data of log contents
Installation
Cubby is distributed using the Swift Package Manager. To install it into a project, simply add it as a dependency within your Package.swift
manifest:
let package = Package(
...
dependencies: [
.package(url: "https://github.com/Fleuronic/Cubby", from: "1.0.0")
],
...
)
Then import Cubby wherever you’d like to use it:
import Cubby
For more information on how to use the Swift Package Manager, check out this article, or its official documentation.