diff --git a/.github/workflows/abstractions.yml b/.github/workflows/abstractions.yml
new file mode 100644
index 0000000..d848eec
--- /dev/null
+++ b/.github/workflows/abstractions.yml
@@ -0,0 +1,26 @@
+name: Swift abstractions
+
+on:
+ workflow_dispatch:
+ push:
+ branches: [ main ]
+ paths: ['abstractions/**', '.github/workflows/**']
+ pull_request:
+ paths: ['abstractions/**', '.github/workflows/**']
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ env:
+ relativePath: ./abstractions
+ steps:
+ - uses: actions/checkout@v4
+ - uses: swift-actions/setup-swift@v2
+ with:
+ swift-version: '5.7'
+ - name: Build SDK project
+ run: swift build
+ working-directory: ${{ env.relativePath }}
+ - name: Run unit tests
+ run: swift test
+ working-directory: ${{ env.relativePath }}
diff --git a/abstractions/.gitignore b/abstractions/.gitignore
new file mode 100644
index 0000000..3b29812
--- /dev/null
+++ b/abstractions/.gitignore
@@ -0,0 +1,9 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/
+DerivedData/
+.swiftpm/config/registries.json
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+.netrc
diff --git a/abstractions/MicrosoftKiotaAbstractions.podspec b/abstractions/MicrosoftKiotaAbstractions.podspec
new file mode 100644
index 0000000..ade5b27
--- /dev/null
+++ b/abstractions/MicrosoftKiotaAbstractions.podspec
@@ -0,0 +1,20 @@
+Pod::Spec.new do |s|
+ s.name = "MicrosoftKiotaAbstractions"
+ s.version = "1.0.0"
+ s.summary = "MicrosoftKiotaAbstractions provides the base infrastructure for the Kiota-generated SDKs to function.
+ It defines multiple concepts related to abstract HTTP requests, serialization, and authentication.
+ These concepts can then be implemented independently without tying the SDKs to any specific implementation.
+ Kiota also provides default implementations for these concepts."
+ s.homepage = "https://github.com/microsoft/kiota"
+ s.license = { :type => "MIT" }
+ s.authors = { "Microsoft" => "graphtooling+kiota@service.microsoft.com" }
+
+ s.requires_arc = true
+ s.swift_version = "5.0"
+ s.osx.deployment_target = "10.9"
+ s.ios.deployment_target = "9.0"
+ s.watchos.deployment_target = "3.0"
+ s.tvos.deployment_target = "9.0"
+ s.source = { :git => "https://github.com/microsoft/kiota.git", :tag => s.version }
+ s.source_files = "Source/*.swift"
+end
\ No newline at end of file
diff --git a/abstractions/MicrosoftKiotaAbstractions.xcworkspace/contents.xcworkspacedata b/abstractions/MicrosoftKiotaAbstractions.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..e95b612
--- /dev/null
+++ b/abstractions/MicrosoftKiotaAbstractions.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/abstractions/Package.resolved b/abstractions/Package.resolved
new file mode 100644
index 0000000..ad51a95
--- /dev/null
+++ b/abstractions/Package.resolved
@@ -0,0 +1,34 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "PathKit",
+ "repositoryURL": "https://github.com/kylef/PathKit.git",
+ "state": {
+ "branch": null,
+ "revision": "3bfd2737b700b9a36565a8c94f4ad2b050a5e574",
+ "version": "1.0.1"
+ }
+ },
+ {
+ "package": "Spectre",
+ "repositoryURL": "https://github.com/kylef/Spectre.git",
+ "state": {
+ "branch": null,
+ "revision": "26cc5e9ae0947092c7139ef7ba612e34646086c7",
+ "version": "0.10.1"
+ }
+ },
+ {
+ "package": "URITemplate",
+ "repositoryURL": "https://github.com/kylef/URITemplate.swift.git",
+ "state": {
+ "branch": null,
+ "revision": "a309673fdf86e4919a0250730e461ac533a03b3a",
+ "version": "3.0.1"
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/abstractions/Package.swift b/abstractions/Package.swift
new file mode 100644
index 0000000..f3fb819
--- /dev/null
+++ b/abstractions/Package.swift
@@ -0,0 +1,17 @@
+// swift-tools-version:5.0
+import PackageDescription
+
+let package = Package(
+ name: "MicrosoftKiotaAbstractions",
+ products: [
+ .library(name: "MicrosoftKiotaAbstractions", targets: ["MicrosoftKiotaAbstractions"])
+ ],
+ dependencies: [
+ .package(url: "https://github.com/kylef/URITemplate.swift.git", from: "3.0.0")
+ ],
+ targets: [
+ .target(name: "MicrosoftKiotaAbstractions", dependencies: ["URITemplate"]),
+ .testTarget(name: "MicrosoftKiotaAbstractionsTests", dependencies: ["MicrosoftKiotaAbstractions"])
+ ],
+ swiftLanguageVersions: [.v5]
+)
\ No newline at end of file
diff --git a/abstractions/Podfile b/abstractions/Podfile
new file mode 100644
index 0000000..7df3631
--- /dev/null
+++ b/abstractions/Podfile
@@ -0,0 +1,23 @@
+# Uncomment the next line to define a global platform for your project
+platform :ios, '9.0'
+
+target 'MicrosoftKiotaAbstractions' do
+ # Comment the next line if you don't want to use dynamic frameworks
+ use_frameworks!
+
+ # Pods for MicrosoftKiotaAbstractions
+ pod 'URITemplate'
+
+ target 'MicrosoftKiotaAbstractionsTests' do
+ # Pods for testing
+ end
+
+end
+
+target 'MicrosoftKiotaAbstractionsPackageDescription' do
+ # Comment the next line if you don't want to use dynamic frameworks
+ use_frameworks!
+
+ # Pods for MicrosoftKiotaAbstractionsPackageDescription
+
+end
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/ApiClientBuilder.swift b/abstractions/Source/MicrosoftKiotaAbstractions/ApiClientBuilder.swift
new file mode 100644
index 0000000..cb94228
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/ApiClientBuilder.swift
@@ -0,0 +1,33 @@
+public class ApiClientBuilder {
+ private init() {
+
+ }
+ private static let defaultSerializationWriterFactoryInstanceIntl = SerializationWriterFactoryRegistry()
+ public static var defaultSerializationWriterFactoryInstance: SerializationWriterFactory {
+ get {
+ return defaultSerializationWriterFactoryInstanceIntl
+ }
+ }
+ public static func registerDefaultSerializer(metaFactory: () -> SerializationWriterFactory) {
+ let factory = metaFactory()
+ if let contentType = try? factory.getValidContentType() {
+ if contentType != "" {
+ defaultSerializationWriterFactoryInstanceIntl.contentTypeAssociatedFactories[contentType] = factory
+ }
+ }
+ }
+ private static let defaultParseNodeFactoryInstanceIntl = ParseNodeFactoryRegistry()
+ public static var defaultParseNodeFactoryInstance: ParseNodeFactory {
+ get {
+ return defaultParseNodeFactoryInstanceIntl
+ }
+ }
+ public static func registerDefaultParser(metaFactory: () -> ParseNodeFactory) {
+ let factory = metaFactory()
+ if let contentType = try? factory.getValidContentType() {
+ if contentType != "" {
+ defaultParseNodeFactoryInstanceIntl.contentTypeAssociatedFactories[contentType] = factory
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/ApiError.swift b/abstractions/Source/MicrosoftKiotaAbstractions/ApiError.swift
new file mode 100644
index 0000000..1007772
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/ApiError.swift
@@ -0,0 +1,3 @@
+public enum ApiError: Error {
+ case unknownError(String, Any? = nil)
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AccessTokenProvider.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AccessTokenProvider.swift
new file mode 100644
index 0000000..8154b59
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AccessTokenProvider.swift
@@ -0,0 +1,6 @@
+import Foundation
+
+public protocol AccessTokenProvider {
+ func getAuthenticationToken(url: URL) async throws -> String?
+ var allowedHostsValidator: AllowedHostsValidator { get }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AllowedHostsValidator.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AllowedHostsValidator.swift
new file mode 100644
index 0000000..4312a05
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AllowedHostsValidator.swift
@@ -0,0 +1,25 @@
+import Foundation
+public class AllowedHostsValidator {
+ private var validHostsIntl = Set()
+ public init(validHosts: [String]) {
+ self.validHosts = validHosts;
+ }
+ public var validHosts: [String] { get {
+ return Array(validHostsIntl)
+
+ } set (validHosts) {
+ self.validHostsIntl = Set(validHosts.map { $0.lowercased() })
+ }}
+ public func isUrlHostValid(url: URL) -> Bool {
+ if let host = url.host {
+ return validHostsIntl.contains(host.lowercased())
+ }
+ return false
+ }
+}
+public let isSchemeHttps = { (url: URL) -> Bool in
+ if let scheme = url.scheme {
+ return scheme.lowercased() == "https"
+ }
+ return false
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AnonymousAuthenticationProvider.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AnonymousAuthenticationProvider.swift
new file mode 100644
index 0000000..b45580e
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AnonymousAuthenticationProvider.swift
@@ -0,0 +1,5 @@
+public class AnonymousAuthenticationProvider : AuthenticationProvider {
+ public func authenticateRequest(request: RequestInformation) async throws {
+ // Do nothing
+ }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AuthenticationProvider.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AuthenticationProvider.swift
new file mode 100644
index 0000000..7e67fbc
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/AuthenticationProvider.swift
@@ -0,0 +1,3 @@
+public protocol AuthenticationProvider {
+ func authenticateRequest(request: RequestInformation) async throws
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/BaseBearerAuthenticationProvider.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/BaseBearerAuthenticationProvider.swift
new file mode 100644
index 0000000..c111e7c
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Authentication/BaseBearerAuthenticationProvider.swift
@@ -0,0 +1,22 @@
+public class BaseBearerAuthenticationProvider : AuthenticationProvider {
+ public init (accessTokenProvider: AccessTokenProvider) {
+ accessTokenProviderIntl = accessTokenProvider
+ }
+ private var accessTokenProviderIntl: AccessTokenProvider
+ public var accessTokenProvider: AccessTokenProvider {
+ get {
+ return accessTokenProviderIntl
+ }
+ }
+ public let authorizationHeaderKey = "Authorization"
+ public let authorizationHeaderValuePrefix = "Bearer "
+ public func authenticateRequest(request: RequestInformation) async throws {
+ if request.headers[authorizationHeaderKey] == nil {
+ let url = try request.getUri()
+ let tokenResult = try? await accessTokenProvider.getAuthenticationToken(url: url)
+ if let token = tokenResult {
+ request.headers[authorizationHeaderKey] = authorizationHeaderValuePrefix + token
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/HttpMethod.swift b/abstractions/Source/MicrosoftKiotaAbstractions/HttpMethod.swift
new file mode 100644
index 0000000..70348a9
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/HttpMethod.swift
@@ -0,0 +1,11 @@
+public enum HttpMethod {
+ case get
+ case post
+ case patch
+ case delete
+ case options
+ case connect
+ case put
+ case trace
+ case head
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/RequestAdapter.swift b/abstractions/Source/MicrosoftKiotaAbstractions/RequestAdapter.swift
new file mode 100644
index 0000000..fd9fefd
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/RequestAdapter.swift
@@ -0,0 +1,11 @@
+public typealias ErrorMappings = [String:ParsableFactory]
+public typealias ResponseHandler = (Any, ErrorMappings) async throws -> DeserializationType
+public protocol RequestAdapter {
+ func send(request: RequestInformation, ctor: ParsableFactory, responseHandler: ResponseHandler?, errorMappings: ErrorMappings?) async throws -> T?
+ func sendCollection(request: RequestInformation, ctor: ParsableFactory, responseHandler: ResponseHandler?, errorMappings: ErrorMappings?) async throws -> [T]?
+ func sendPrimitive(request: RequestInformation, responseHandler: ResponseHandler?, errorMappings: ErrorMappings?) async throws -> T?
+ func sendNoContent(request: RequestInformation, responseHandler: ResponseHandler?, errorMappings: ErrorMappings?) async throws -> Void
+ func enableBackingStore() throws
+ var baseUrl: String { get set }
+ var serializationWriterFactory: SerializationWriterFactory { get }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/RequestInformation.swift b/abstractions/Source/MicrosoftKiotaAbstractions/RequestInformation.swift
new file mode 100644
index 0000000..0b59d47
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/RequestInformation.swift
@@ -0,0 +1,96 @@
+import Foundation
+import URITemplate
+
+public enum RequestInformationErrors : Error {
+ case emptyUrlTemplate
+ case emptyContentType
+ case unableToExpandUriTemplate
+ case invalidRawUrl
+}
+
+public class RequestInformation {
+ public var method: HttpMethod = HttpMethod.get
+ public var urlTemplate = ""
+ public var queryParameters = [String:String]()
+ public var pathParameters = [String:String]()
+ public var headers = [String:String]()
+ var contentInternal: Data?
+ public var content: Data? {
+ get {
+ return contentInternal
+ }
+ set(newContent) {
+ contentInternal = newContent
+ if newContent != nil {
+ headers[contentTypeHeaderKey] = binaryContentType
+ }
+ }
+ }
+ var uriInternal: URL?
+ public func getUri() throws -> URL {
+ if let uriInternalValue = uriInternal {
+ return uriInternalValue
+ }
+ guard !urlTemplate.isEmpty else {
+ throw RequestInformationErrors.emptyUrlTemplate
+ }
+ if let rawUrl = pathParameters[rawUrlKey] {
+ if rawUrl != "" {
+ let newValue = URL(string: rawUrl)
+ if let url = newValue {
+ setUri(newUri: url)
+ return url
+ }
+ }
+ throw RequestInformationErrors.invalidRawUrl
+ } else {
+ let urlTemplate = URITemplate(template: self.urlTemplate)
+ let merged = pathParameters.merging(queryParameters)
+ { (first, _) in first }
+ let url = urlTemplate.expand(merged)
+ if let newValue = URL(string: url) {
+ return newValue
+ } else {
+ throw RequestInformationErrors.unableToExpandUriTemplate
+ }
+ }
+ }
+ public func setUri(newUri: URL) {
+ uriInternal = newUri
+ pathParameters.removeAll()
+ queryParameters.removeAll()
+ }
+ var options = [String:RequestOption]()
+ let rawUrlKey = "request-raw-url"
+ let contentTypeHeaderKey = "Content-Type"
+ let binaryContentType = "application/octet-stream"
+ public func addRequestOption(options:RequestOption...) {
+ for option in options {
+ self.options[option.key] = option
+ }
+ }
+ public func getRequestOptions() -> [RequestOption] {
+ return [RequestOption](options.values)
+ }
+ public func setContentFromParsable(requestAdapter: RequestAdapter, contentType: String, item: T) throws {
+ guard contentType != "" else {
+ throw RequestInformationErrors.emptyContentType
+ }
+ if let writer = try? requestAdapter.serializationWriterFactory.getSerializationWriter(contentType: contentType) {
+ try writer.writeObjectValue(key: "", value: item)
+ self.content = try? writer.getSerializedContent()
+ self.headers[contentTypeHeaderKey] = contentType
+ }
+ }
+ public func setContentFromParsableCollection(requestAdapter: RequestAdapter, contentType: String, items: [T]) throws {
+ guard contentType != "" else {
+ throw RequestInformationErrors.emptyContentType
+ }
+ if let writer = try? requestAdapter.serializationWriterFactory.getSerializationWriter(contentType: contentType) {
+ try writer.writeCollectionOfObjectValues(key: "", value: items)
+ self.content = try? writer.getSerializedContent()
+ self.headers[contentTypeHeaderKey] = contentType
+ }
+ }
+ //TODO add query parameters from object by reflection
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/RequestOption.swift b/abstractions/Source/MicrosoftKiotaAbstractions/RequestOption.swift
new file mode 100644
index 0000000..4ae1eb2
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/RequestOption.swift
@@ -0,0 +1,3 @@
+public protocol RequestOption {
+ var key: String { get }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/AdditionalDataHolder.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/AdditionalDataHolder.swift
new file mode 100644
index 0000000..756421c
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/AdditionalDataHolder.swift
@@ -0,0 +1,3 @@
+public protocol AdditionalDataHolder {
+ var additionalData : [String:Any] { get set }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/Parsable.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/Parsable.swift
new file mode 100644
index 0000000..1adcdeb
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/Parsable.swift
@@ -0,0 +1,6 @@
+public typealias FieldDeserializer = (T, ParseNode) throws -> Void
+public typealias ParsableFactory = (ParseNode) throws -> Parsable
+public protocol Parsable {
+ func serialize(writer: SerializationWriter) throws
+ func getFieldDeserializers() -> [String:FieldDeserializer]
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNode.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNode.swift
new file mode 100644
index 0000000..9fdb88a
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNode.swift
@@ -0,0 +1,23 @@
+import Foundation
+public protocol ParseNode {
+ func getChileNode(key: String) throws -> ParseNode?
+ func getObjectValue(ctor: ParsableFactory) throws -> T?
+ func getCollectionOfObjectValues(ctor: ParsableFactory) throws -> [T]?
+ func getCollectionOfPrimitiveValues() throws -> [T]?
+ func getStringValue() throws -> String?
+ func getBoolValue() throws -> Bool?
+ func getUint8Value() throws -> UInt8?
+ func getInt8Value() throws -> Int8?
+ func getInt32Value() throws -> Int32?
+ func getInt64Value() throws -> Int64?
+ func getFloat32Value() throws -> Float32?
+ func getFloat64Value() throws -> Float64?
+ func getByteArrayValue() throws -> [UInt8]?
+ func getDateValue() throws -> Date? //TODO
+ func getTimeOnlyValue() throws -> Date? //TODO
+ func getDateOnlyValue() throws -> Date?
+ func getDurationValue() throws -> Date? //TODO
+ func getUUIDValue() throws -> UUID?
+ func getAdditionalData() throws -> [String:Any]?
+ //TODO get enum value & get collection of enum values
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNodeFactory.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNodeFactory.swift
new file mode 100644
index 0000000..f41dd5b
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNodeFactory.swift
@@ -0,0 +1,5 @@
+import Foundation
+public protocol ParseNodeFactory {
+ func getValidContentType() throws -> String
+ func getRootParseNode(contentType: String, content: Data?) throws -> ParseNode
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNodeFactoryRegistry.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNodeFactoryRegistry.swift
new file mode 100644
index 0000000..1c42032
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/ParseNodeFactoryRegistry.swift
@@ -0,0 +1,21 @@
+import Foundation
+public enum ParseNodeFactoryRegistryErrors : Error {
+ case registrySupportsMultipleTypesGetOneFactory
+ case factoryNotFoundForContentType
+ case contentCannotBeNil
+}
+public class ParseNodeFactoryRegistry : ParseNodeFactory {
+ public var contentTypeAssociatedFactories = [String:ParseNodeFactory]()
+ public func getValidContentType() throws -> String {
+ throw ParseNodeFactoryRegistryErrors.registrySupportsMultipleTypesGetOneFactory
+ }
+ public func getRootParseNode(contentType: String, content: Data?) throws -> ParseNode {
+ guard let factory = contentTypeAssociatedFactories[contentType] else {
+ throw ParseNodeFactoryRegistryErrors.factoryNotFoundForContentType
+ }
+ guard content != nil else {
+ throw ParseNodeFactoryRegistryErrors.contentCannotBeNil
+ }
+ return try factory.getRootParseNode(contentType: contentType, content: content)
+ }
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriter.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriter.swift
new file mode 100644
index 0000000..64d4f6a
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriter.swift
@@ -0,0 +1,24 @@
+import Foundation
+
+public protocol SerializationWriter {
+ func writeStringValue(key : String, value : String?) throws
+ func writeBoolValue(key : String, value : Bool?) throws
+ func writeUint8Value(key : String, value : UInt8?) throws
+ func writeInt8Value(key : String, value : Int8?) throws
+ func writeInt32Value(key : String, value : Int32?) throws
+ func writeInt64Value(key : String, value : Int64?) throws
+ func writeFloat32Value(key : String, value : Float32?) throws
+ func writeFloat64Value(key : String, value : Float64?) throws
+ func writeByteArrayValue(key : String, value : [UInt8]) throws
+ func writeDateValue(key : String, value : Date?) throws //TODO
+ func writeTimeOnlyValue(key : String, value : Date?) throws //TODO
+ func writeDateOnlyValue(key : String, value : Date?) throws
+ func writeDurationValue(key : String, value : Date?) throws //TODO
+ func writeUUIDValue(key : String, value : UUID?) throws
+ func writeObjectValue(key: String, value: T) throws
+ func writeCollectionOfObjectValues(key: String, value: [T]) throws
+ func writeCollectionOfPrimitiveValues(key: String, value: [T]) throws
+ func getSerializedContent() throws -> Data?
+ func writeAdditionalData(value: [String:Any]?) throws
+ //TODO write enum value & write collection of enum values
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriterFactory.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriterFactory.swift
new file mode 100644
index 0000000..c4f4e77
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriterFactory.swift
@@ -0,0 +1,4 @@
+public protocol SerializationWriterFactory {
+ func getValidContentType() throws -> String
+ func getSerializationWriter(contentType: String) throws -> SerializationWriter
+}
\ No newline at end of file
diff --git a/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriterFactoryRegistry.swift b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriterFactoryRegistry.swift
new file mode 100644
index 0000000..c7f2031
--- /dev/null
+++ b/abstractions/Source/MicrosoftKiotaAbstractions/Serialization/SerializationWriterFactoryRegistry.swift
@@ -0,0 +1,16 @@
+public enum SerializationWriterFactoryRegistryErrors : Error {
+ case registrySupportsMultipleTypesGetOneFactory
+ case factoryNotFoundForContentType
+}
+public class SerializationWriterFactoryRegistry : SerializationWriterFactory {
+ public var contentTypeAssociatedFactories = [String:SerializationWriterFactory]()
+ public func getValidContentType() throws -> String {
+ throw SerializationWriterFactoryRegistryErrors.registrySupportsMultipleTypesGetOneFactory
+ }
+ public func getSerializationWriter(contentType: String) throws -> SerializationWriter {
+ guard let factory = contentTypeAssociatedFactories[contentType] else {
+ throw SerializationWriterFactoryRegistryErrors.factoryNotFoundForContentType
+ }
+ return try factory.getSerializationWriter(contentType: contentType)
+ }
+}
\ No newline at end of file
diff --git a/abstractions/Tests/MicrosoftKiotaAbstractionsTests/RequestInformationTests.swift b/abstractions/Tests/MicrosoftKiotaAbstractionsTests/RequestInformationTests.swift
new file mode 100644
index 0000000..e69de29