AI Development Guide - C# SDK Documentation

This guide provides a comprehensive, fast reference for AI systems to quickly develop applications using the BosBase C# SDK. All examples are production-ready and follow best practices.

Table of Contents

  1. Authentication
  2. Initialize Collections
  3. Define Collection Fields
  4. Add Data to Collections
  5. Modify Collection Data
  6. Delete Data from Collections
  7. Query Collection Contents
  8. Add and Delete Fields from Collections
  9. Query Collection Field Information
  10. Upload Files
  11. Query Logs
  12. Send Emails

Authentication

Initialize Client

using Bosbase;

var client = new BosbaseClient("http://localhost:8090");

Password Authentication

// Authenticate with email/username and password
var authData = await client.Collection("users").AuthWithPasswordAsync(
    "user@example.com",
    "password123"
);

// Auth data is automatically stored
Console.WriteLine(client.AuthStore.IsValid());  // true
Console.WriteLine(client.AuthStore.Token);      // JWT token
Console.WriteLine(client.AuthStore.Record);      // User record

OAuth2 Authentication

// Get OAuth2 providers
var methods = await client.Collection("users").ListAuthMethodsAsync();
// Access available providers from methods

// Authenticate with OAuth2
var authData = await client.Collection("users").AuthWithOAuth2Async(new Dictionary<string, object?>
{
    ["provider"] = "google"
});

OTP Authentication

// Request OTP
var otpResponse = await client.Collection("users").RequestVerificationAsync("user@example.com");

// Authenticate with OTP
var authData = await client.Collection("users").AuthWithOtpAsync(
    otpResponse["otpId"]?.ToString() ?? "",
    "123456" // OTP code
);

Check Authentication Status

if (client.AuthStore.IsValid())
{
    var record = client.AuthStore.Record;
    Console.WriteLine($"Authenticated as: {record["email"]}");
}
else
{
    Console.WriteLine("Not authenticated");
}

Logout

client.AuthStore.Clear();

Initialize Collections

Create Base Collection

var collection = await client.Collections.CreateBaseAsync("articles", new Dictionary<string, object?>
{
    ["fields"] = new[]
    {
        new Dictionary<string, object?>
        {
            ["name"] = "title",
            ["type"] = "text",
            ["required"] = true,
            ["min"] = 6,
            ["max"] = 100
        },
        new Dictionary<string, object?>
        {
            ["name"] = "description",
            ["type"] = "text"
        }
    },
    ["listRule"] = "@request.auth.id != \"\" || status = \"public\"",
    ["viewRule"] = "@request.auth.id != \"\" || status = \"public\""
});

Create Auth Collection

var authCollection = await client.Collections.CreateAuthAsync("users", new Dictionary<string, object?>
{
    ["fields"] = new[]
    {
        new Dictionary<string, object?>
        {
            ["name"] = "name",
            ["type"] = "text",
            ["required"] = false
        }
    }
});

Create View Collection

var viewCollection = await client.Collections.CreateViewAsync("published_posts", 
    "SELECT * FROM posts WHERE published = true"
);

Get Collection by ID or Name

var collection = await client.Collections.GetOneAsync("posts");
// or by ID
var collection = await client.Collections.GetOneAsync("_pbc_2287844090");

Define Collection Fields

Add Field to Collection

var updatedCollection = await client.Collections.UpdateAsync("posts", new Dictionary<string, object?>
{
    ["schema"] = new[]
    {
        // Existing fields...
        new Dictionary<string, object?>
        {
            ["name"] = "content",
            ["type"] = "editor",
            ["required"] = false
        }
    }
});

Common Field Types

// Text field
new Dictionary<string, object?>
{
    ["name"] = "title",
    ["type"] = "text",
    ["required"] = true,
    ["min"] = 10,
    ["max"] = 255
}

// Number field
new Dictionary<string, object?>
{
    ["name"] = "views",
    ["type"] = "number",
    ["required"] = false,
    ["min"] = 0
}

// Boolean field
new Dictionary<string, object?>
{
    ["name"] = "published",
    ["type"] = "bool",
    ["required"] = false
}

// Date field
new Dictionary<string, object?>
{
    ["name"] = "published_at",
    ["type"] = "date",
    ["required"] = false
}

// File field
new Dictionary<string, object?>
{
    ["name"] = "avatar",
    ["type"] = "file",
    ["required"] = false,
    ["maxSelect"] = 1,
    ["maxSize"] = 2097152, // 2MB
    ["mimeTypes"] = new[] { "image/jpeg", "image/png" }
}

// Relation field
new Dictionary<string, object?>
{
    ["name"] = "author",
    ["type"] = "relation",
    ["required"] = true,
    ["collectionId"] = "_pbc_users_auth_",
    ["maxSelect"] = 1
}

// Select field
new Dictionary<string, object?>
{
    ["name"] = "status",
    ["type"] = "select",
    ["required"] = true,
    ["options"] = new Dictionary<string, object?>
    {
        ["values"] = new[] { "draft", "published", "archived" }
    }
}

Add Data to Collections

Create Single Record

var record = await client.Collection("posts").CreateAsync(new Dictionary<string, object?>
{
    ["title"] = "My First Post",
    ["content"] = "This is the content",
    ["published"] = true
});

Console.WriteLine($"Created record ID: {record["id"]}");

Create Record with File Upload

using Bosbase.Models;

var fileAttachment = FileAttachment.FromPath("image", "/path/to/image.jpg", "image/jpeg");
var record = await client.Collection("posts").CreateAsync(
    new Dictionary<string, object?> { ["title"] = "Post with Image" },
    files: new[] { fileAttachment }
);

Create Record with Relations

var record = await client.Collection("posts").CreateAsync(new Dictionary<string, object?>
{
    ["title"] = "My Post",
    ["author"] = "user_record_id", // Related record ID
    ["categories"] = new[] { "cat1_id", "cat2_id" } // Multiple relations
});

Batch Create Records

var batch = client.CreateBatch();
batch.Collection("posts").Create(new Dictionary<string, object?> { ["title"] = "Post 1" });
batch.Collection("posts").Create(new Dictionary<string, object?> { ["title"] = "Post 2" });
var results = await batch.SendAsync();

Modify Collection Data

Update Single Record

var updated = await client.Collection("posts").UpdateAsync("record_id", new Dictionary<string, object?>
{
    ["title"] = "Updated Title",
    ["content"] = "Updated content"
});

Update Record with File

using Bosbase.Models;

var fileAttachment = FileAttachment.FromPath("image", "/path/to/new-image.jpg", "image/jpeg");
var updated = await client.Collection("posts").UpdateAsync(
    "record_id",
    new Dictionary<string, object?> { ["title"] = "Updated Title" },
    files: new[] { fileAttachment }
);

Partial Update

// Only update specific fields
var updated = await client.Collection("posts").UpdateAsync("record_id", new Dictionary<string, object?>
{
    ["views"] = 100 // Only update views
});

Delete Data from Collections

Delete Single Record

await client.Collection("posts").DeleteAsync("record_id");

Delete Multiple Records

// Using batch
var batch = client.CreateBatch();
batch.Collection("posts").Delete("record_id_1");
batch.Collection("posts").Delete("record_id_2");
await batch.SendAsync();

Delete All Records (Truncate)

await client.Collections.TruncateAsync("posts");

Query Collection Contents

List Records with Pagination

var result = await client.Collection("posts").GetListAsync(1, 50);

var page = result["page"];        // 1
var perPage = result["perPage"];     // 50
var totalItems = result["totalItems"];  // Total count
var items = result["items"] as List<object?>;       // Array of records

Filter Records

var result = await client.Collection("posts").GetListAsync(1, 50, 
    filter: "published = true && views > 100",
    sort: "-created"
);

Filter Operators

// Equality
filter: "status = \"published\""

// Comparison
filter: "views > 100"
filter: "created >= \"2023-01-01\""

// Text search
filter: "title ~ \"javascript\""

// Multiple conditions
filter: "status = \"published\" && views > 100"
filter: "status = \"draft\" || status = \"pending\""

// Relation filter
filter: "author.id = \"user_id\""

Sort Records

// Single field
sort: "-created"  // DESC
sort: "title"     // ASC

// Multiple fields
sort: "-created,title"  // DESC by created, then ASC by title

Expand Relations

var result = await client.Collection("posts").GetListAsync(1, 50, expand: "author,categories");

// Access expanded data
if (result["items"] is List<object?> items)
{
    foreach (var item in items)
    {
        if (item is Dictionary<string, object?> post)
        {
            var expand = post["expand"] as Dictionary<string, object?>;
            var author = expand?["author"] as Dictionary<string, object?>;
            Console.WriteLine(author?["name"]);
        }
    }
}

Get Single Record

var record = await client.Collection("posts").GetOneAsync("record_id", expand: "author");

Get First Matching Record

var record = await client.Collection("posts").GetFirstListItemAsync(
    "slug = \"my-post-slug\"",
    expand: "author"
);

Get All Records

var allRecords = await client.Collection("posts").GetFullListAsync(
    filter: "published = true",
    sort: "-created"
);

Add and Delete Fields from Collections

Add Field

var collection = await client.Collections.GetOneAsync("posts");
var schema = collection["schema"] as List<object?> ?? new List<object?>();
schema.Add(new Dictionary<string, object?>
{
    ["name"] = "tags",
    ["type"] = "select",
    ["options"] = new Dictionary<string, object?>
    {
        ["values"] = new[] { "tech", "science", "art" }
    }
});

await client.Collections.UpdateAsync("posts", new Dictionary<string, object?>
{
    ["schema"] = schema
});

Update Field

// Update field by modifying collection schema
var collection = await client.Collections.GetOneAsync("posts");
// Modify schema and update

Remove Field

// Remove field by modifying collection schema
var collection = await client.Collections.GetOneAsync("posts");
// Remove field from schema and update

Query Collection Field Information

Get All Fields for a Collection

var collection = await client.Collections.GetOneAsync("posts");
if (collection["schema"] is List<object?> fields)
{
    foreach (var field in fields)
    {
        if (field is Dictionary<string, object?> fieldDict)
        {
            Console.WriteLine($"{fieldDict["name"]} {fieldDict["type"]} {fieldDict["required"]}");
        }
    }
}

Get Collection Schema (Simplified)

var schema = await client.Collections.GetSchemaAsync("posts");
if (schema["fields"] is List<object?> fields)
{
    // Array of field info
    foreach (var field in fields)
    {
        Console.WriteLine(field);
    }
}

Get All Collection Schemas

var schemas = await client.Collections.GetAllSchemasAsync();
if (schemas["collections"] is List<object?> collections)
{
    foreach (var collection in collections)
    {
        if (collection is Dictionary<string, object?> collDict)
        {
            Console.WriteLine($"{collDict["name"]} {collDict["fields"]}");
        }
    }
}

Upload Files

Upload File with Record Creation

using Bosbase.Models;

var fileAttachment = FileAttachment.FromPath("image", "/path/to/image.jpg", "image/jpeg");
var record = await client.Collection("posts").CreateAsync(
    new Dictionary<string, object?> { ["title"] = "Post Title" },
    files: new[] { fileAttachment }
);

Upload File with Record Update

using Bosbase.Models;

var fileAttachment = FileAttachment.FromPath("image", "/path/to/new-image.jpg", "image/jpeg");
var updated = await client.Collection("posts").UpdateAsync(
    "record_id",
    files: new[] { fileAttachment }
);

Get File URL

var record = await client.Collection("posts").GetOneAsync("record_id");
var fileUrl = client.Files.GetUrl(record, record["image"]?.ToString() ?? "");

Get File URL with Options

var fileUrl = client.Files.GetUrl(record, record["image"]?.ToString() ?? "", 
    thumb: "100x100",  // Thumbnail
    download: true     // Force download
);

Get Private File Token

// For accessing private files
var token = await client.Files.GetTokenAsync();
// Use token in file URL query params

Query Logs

List Logs

var logs = await client.Logs.GetListAsync(1, 50);
if (logs["items"] is List<object?> items)
{
    // Array of log entries
    foreach (var log in items)
    {
        Console.WriteLine(log);
    }
}

Filter Logs

var errorLogs = await client.Logs.GetListAsync(1, 50, 
    filter: "level > 0 && created >= \"2024-01-01\""
);

Get Log Statistics

var stats = await client.Logs.GetStatsAsync(new Dictionary<string, object?>
{
    ["filter"] = "level >= 0"
});

Send Emails

Test Email

await client.Settings.TestEmailAsync(
    "test@example.com",
    "verification", // template: verification, password-reset, email-change, otp, login-alert
    "_superusers" // collection (optional)
);

Email Templates

  • verification - Email verification template
  • password-reset - Password reset template
  • email-change - Email change confirmation template
  • otp - One-time password template
  • login-alert - Login alert template

Complete Example

using Bosbase;
using Bosbase.Models;

var client = new BosbaseClient("http://localhost:8090");

// 1. Authenticate
await client.Collection("users").AuthWithPasswordAsync("user@example.com", "password");

// 2. Create collection
var collection = await client.Collections.CreateBaseAsync("posts", new Dictionary<string, object?>
{
    ["fields"] = new[]
    {
        new Dictionary<string, object?>
        {
            ["name"] = "title",
            ["type"] = "text",
            ["required"] = true
        },
        new Dictionary<string, object?>
        {
            ["name"] = "content",
            ["type"] = "editor"
        }
    }
});

// 3. Create record
var record = await client.Collection("posts").CreateAsync(new Dictionary<string, object?>
{
    ["title"] = "My Post",
    ["content"] = "Post content"
});

// 4. Query records
var posts = await client.Collection("posts").GetListAsync(1, 20, 
    filter: "title ~ \"Post\"",
    sort: "-created"
);

// 5. Update record
await client.Collection("posts").UpdateAsync(record["id"]?.ToString() ?? "", new Dictionary<string, object?>
{
    ["title"] = "Updated Title"
});

// 6. Delete record
await client.Collection("posts").DeleteAsync(record["id"]?.ToString() ?? "");