1- // The Swift Programming Language
2- // https://docs.swift.org/swift-book
31// MarkbookAPIClient.swift
42// Markbook Online REST API v1.5
53// https://smpcsonline.com.au/markbook/api/v1.5
@@ -8,7 +6,7 @@ import Foundation
86
97// MARK: - Errors
108
11- enum MarkbookAPIError : Error , LocalizedError {
9+ public enum MarkbookAPIError : Error , LocalizedError {
1210 /// The server returned a non-2xx HTTP status code.
1311 case httpError( statusCode: Int )
1412 /// The API returned a non-OKAY status in the response body.
@@ -20,7 +18,7 @@ enum MarkbookAPIError: Error, LocalizedError {
2018 /// The session could not be established or refreshed.
2119 case authenticationFailed( underlying: Error )
2220
23- var errorDescription : String ? {
21+ public var errorDescription : String ? {
2422 switch self {
2523 case . httpError( let code) :
2624 return " HTTP error: \( code) "
@@ -40,7 +38,7 @@ enum MarkbookAPIError: Error, LocalizedError {
4038
4139/// Defines the full surface area of the Markbook Online API client.
4240/// Conform a mock to this protocol to enable unit testing without network calls.
43- protocol MarkbookAPIClientProtocol {
41+ public protocol MarkbookAPIClientProtocol {
4442 func markbookList( ) async throws -> MarkbookListResponse
4543 func userList( ) async throws -> UserListResponse
4644 func getMarkbook( key: Int ) async throws -> GetMarkbookResponse
@@ -104,14 +102,16 @@ protocol MarkbookAPIClientProtocol {
104102/// re-authenticates before any call that would use an expired session.
105103///
106104/// ```swift
105+ /// import MarkbookAPI
106+ ///
107107/// let client = MarkbookAPIClient(
108108/// apiKey: "YOUR_32_CHAR_API_KEY",
109109/// username: "adminuser",
110110/// password: "secret"
111111/// )
112112/// let markbooks = try await client.markbookList()
113113/// ```
114- actor MarkbookAPIClient : MarkbookAPIClientProtocol {
114+ public actor MarkbookAPIClient : MarkbookAPIClientProtocol {
115115
116116 // MARK: - Private State
117117
@@ -140,7 +140,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
140140 /// - password: Password for the above user.
141141 /// - baseURL: Override only for testing. Defaults to the production endpoint.
142142 /// - urlSession: Override to inject a mock session for testing.
143- init (
143+ public init (
144144 apiKey: String ,
145145 username: String ,
146146 password: String ,
@@ -158,22 +158,22 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
158158 // MARK: - Public API Methods
159159
160160 /// Returns the list of all markbooks in the school database.
161- func markbookList( ) async throws -> MarkbookListResponse {
161+ public func markbookList( ) async throws -> MarkbookListResponse {
162162 try await get ( queryItems: [
163163 . init( name: " action " , value: APIAction . markbookList. rawValue)
164164 ] )
165165 }
166166
167167 /// Returns the list of all users in the school database.
168- func userList( ) async throws -> UserListResponse {
168+ public func userList( ) async throws -> UserListResponse {
169169 try await get ( queryItems: [
170170 . init( name: " action " , value: APIAction . userList. rawValue)
171171 ] )
172172 }
173173
174174 /// Returns the full contents of a markbook, with per-student result arrays.
175175 /// - Parameter key: The markbook key from ``markbookList()``.
176- func getMarkbook( key: Int ) async throws -> GetMarkbookResponse {
176+ public func getMarkbook( key: Int ) async throws -> GetMarkbookResponse {
177177 try await get ( queryItems: [
178178 . init( name: " action " , value: APIAction . getMarkbook. rawValue) ,
179179 . init( name: " key " , value: String ( key) )
@@ -182,7 +182,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
182182
183183 /// Returns the full contents of a markbook in the flat alternate format.
184184 /// - Parameter key: The markbook key from ``markbookList()``.
185- func getMarkbookAlt( key: Int ) async throws -> GetMarkbookAltResponse {
185+ public func getMarkbookAlt( key: Int ) async throws -> GetMarkbookAltResponse {
186186 try await get ( queryItems: [
187187 . init( name: " action " , value: APIAction . getMarkbookAlt. rawValue) ,
188188 . init( name: " key " , value: String ( key) )
@@ -191,7 +191,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
191191
192192 /// Returns outcome levels for all students in a markbook.
193193 /// - Parameter key: The markbook key from ``markbookList()``.
194- func getOutcomes( key: Int ) async throws -> GetOutcomesResponse {
194+ public func getOutcomes( key: Int ) async throws -> GetOutcomesResponse {
195195 try await get ( queryItems: [
196196 . init( name: " action " , value: APIAction . getOutcomes. rawValue) ,
197197 . init( name: " key " , value: String ( key) )
@@ -200,7 +200,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
200200
201201 /// Returns outcome levels in the flat alternate format.
202202 /// - Parameter key: The markbook key from ``markbookList()``.
203- func getOutcomesAlt( key: Int ) async throws -> GetOutcomesAltResponse {
203+ public func getOutcomesAlt( key: Int ) async throws -> GetOutcomesAltResponse {
204204 try await get ( queryItems: [
205205 . init( name: " action " , value: APIAction . getOutcomesAlt. rawValue) ,
206206 . init( name: " key " , value: String ( key) )
@@ -216,7 +216,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
216216 /// - taskKey: The task key from the markbook's `tasklist`.
217217 /// - taskName: The task name from the markbook's `tasklist`.
218218 /// - result: The result value to record.
219- func putStudentResult(
219+ public func putStudentResult(
220220 markbookKey: Int ,
221221 studentKey: Int ,
222222 sid: String ,
@@ -249,7 +249,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
249249 /// - gender: Student gender.
250250 /// - classKey: The class key from ``getMarkbook(key:)`` or ``getMarkbookAlt(key:)``.
251251 /// - Returns: The response containing the new student's key.
252- func createStudent(
252+ public func createStudent(
253253 markbookKey: Int ,
254254 sid: String ,
255255 familyName: String ,
@@ -281,7 +281,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
281281 /// - givenName: Student given name.
282282 /// - preferredName: Student preferred name (may be empty).
283283 /// - gender: Student gender.
284- func updateStudent(
284+ public func updateStudent(
285285 markbookKey: Int ,
286286 studentKey: Int ,
287287 sid: String ,
@@ -313,7 +313,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
313313 /// - studentKey: The student key from ``getMarkbook(key:)`` or ``getMarkbookAlt(key:)``.
314314 /// - sid: The student ID from the same source as `studentKey`.
315315 /// - classKey: The destination class key.
316- func updateStudentClass(
316+ public func updateStudentClass(
317317 markbookKey: Int ,
318318 studentKey: Int ,
319319 sid: String ,
@@ -332,13 +332,14 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
332332 }
333333
334334 /// Soft-deletes a student from a markbook.
335- /// The student remains in the database and can be restored via ``updateStudentClass(markbookKey:studentKey:sid:classKey:)``.
335+ /// The student remains in the database and can be restored via
336+ /// ``updateStudentClass(markbookKey:studentKey:sid:classKey:)``.
336337 ///
337338 /// - Parameters:
338339 /// - markbookKey: The markbook key from ``markbookList()``.
339340 /// - studentKey: The student key from ``getMarkbook(key:)`` or ``getMarkbookAlt(key:)``.
340341 /// - sid: The student ID from the same source as `studentKey`.
341- func deleteStudent(
342+ public func deleteStudent(
342343 markbookKey: Int ,
343344 studentKey: Int ,
344345 sid: String
@@ -362,7 +363,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
362363 /// - teacherFamilyName: The class teacher's family name.
363364 /// - teacherGivenName: The class teacher's given name.
364365 /// - Returns: The response containing the new class key.
365- func createClass(
366+ public func createClass(
366367 markbookKey: Int ,
367368 name: String ,
368369 teacherFamilyName: String ,
@@ -382,7 +383,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
382383 /// Only one backup can be scheduled per day; a second call replaces the first.
383384 ///
384385 /// - Parameter matching: A substring filter (minimum 2 characters) applied to markbook names.
385- func scheduleBackup( matching: String ) async throws {
386+ public func scheduleBackup( matching: String ) async throws {
386387 guard matching. count >= 2 else {
387388 throw MarkbookAPIError . invalidBackupMatchingParameter
388389 }
@@ -403,7 +404,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
403404 /// - Returns: The full response, including the `url` and `status`.
404405 /// Check `status` for `.errorPending` (backup not yet ready) or `.errorNoBackup`
405406 /// (no backup has been scheduled).
406- func getBackupURL( ) async throws -> GetBackupURLResponse {
407+ public func getBackupURL( ) async throws -> GetBackupURLResponse {
407408 try await get ( queryItems: [
408409 . init( name: " action " , value: APIAction . getBackupURL. rawValue)
409410 ] )
@@ -414,7 +415,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
414415 /// - Parameter request: The fully populated ``CreateMarkbookRequest``.
415416 /// Build it with the local class/student keys starting from 1.
416417 /// - Returns: The response containing the new markbook key and actual name used.
417- func createMarkbook( _ request: CreateMarkbookRequest ) async throws -> CreateMarkbookResponse {
418+ public func createMarkbook( _ request: CreateMarkbookRequest ) async throws -> CreateMarkbookResponse {
418419 try await post ( action: APIAction . createMarkbook. rawValue, body: request)
419420 }
420421
@@ -444,7 +445,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
444445 }
445446
446447 private func performAuthentication( ) async throws -> AuthenticationResponse {
447- let authURL = baseURL. appendingPathComponent ( " authenticate.lc " , isDirectory: false )
448+ let authURL = baseURL. appendingPathComponent ( " authenticate.lc " , isDirectory: false )
448449
449450 var components = URLComponents ( )
450451 components. queryItems = [
@@ -534,7 +535,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
534535
535536 let decoded = try decoder. decode ( T . self, from: data)
536537
537- // For any response type that carries a status field, surface API-level errors .
538+ // Surface API-level errors uniformly for any response type that carries a status.
538539 if let statusCarrier = decoded as? any StatusCarrying , !statusCarrier. status. isOkay {
539540 throw MarkbookAPIError . apiError ( statusCarrier. status)
540541 }
@@ -545,7 +546,7 @@ actor MarkbookAPIClient: MarkbookAPIClientProtocol {
545546
546547// MARK: - StatusCarrying
547548
548- /// Internal protocol used to extract `status` from any response type for uniform error checking .
549+ /// Internal protocol used to extract `status` from any response type for uniform error surfacing .
549550private protocol StatusCarrying {
550551 var status : APIStatus { get }
551552}
0 commit comments