Skip to content

Commit 999ab08

Browse files
committed
Add more defined headers
1 parent 09ceaeb commit 999ab08

File tree

9 files changed

+442
-175
lines changed

9 files changed

+442
-175
lines changed

Sources/NetworkingCore/RequestModifiers/Headers/AcceptLanguage.swift

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
//
2+
// CommonHeaders.swift
3+
// Networking
4+
//
5+
// Created by Joe Maghzal on 2/11/25.
6+
//
7+
8+
import Foundation
9+
10+
/// An `Accept-Language` HTTP header.
11+
///
12+
/// Specifies the preferred languages for the response. Commonly used for localization.
13+
@frozen public struct AcceptLanguage: RequestHeader, Equatable, Hashable, Sendable {
14+
/// The language value.
15+
public var value: String
16+
17+
/// The headers dictionary representation.
18+
public var headers: [String: String] {
19+
return ["Accept-Language": value]
20+
}
21+
22+
//// Creates an `Accept-Language` header.
23+
///
24+
/// - Parameter value: The language tag to apply (e.g. `"en-US"`).
25+
@inlinable public init(_ value: String) {
26+
self.value = value
27+
}
28+
}
29+
30+
/// An `Accept-Encoding` HTTP header.
31+
///
32+
/// Specifies the content encoding types the client supports.
33+
@frozen public struct AcceptEncoding: RequestHeader, Equatable, Hashable, Sendable {
34+
/// The encoding type.
35+
public var type: String
36+
37+
/// The headers dictionary representation.
38+
public var headers: [String: String] {
39+
return ["Accept-Encoding": type]
40+
}
41+
42+
/// Creates an `Accept-Encoding` header from a raw string.
43+
///
44+
/// - Parameter type: The encoding value to apply.
45+
@inlinable public init(_ type: String) {
46+
self.type = type
47+
}
48+
49+
/// Creates an `Accept-Encoding` header from a predefined encoding type.
50+
///
51+
/// - Parameter type: A supported encoding type.
52+
@inlinable public init(_ type: EncodingType) {
53+
self.init(type.rawValue)
54+
}
55+
56+
/// Common content encoding types.
57+
public enum EncodingType: String, Equatable, Hashable, Sendable, CaseIterable {
58+
/// `gzip`.
59+
case gzip = "gzip"
60+
61+
/// `deflate`.
62+
case deflate = "deflate"
63+
64+
/// `br`.
65+
case br = "br"
66+
67+
/// `identity`.
68+
case identity = "identity"
69+
}
70+
}
71+
72+
/// An `Accept` HTTP header.
73+
///
74+
/// Declares the content types the client is willing to receive from the server.
75+
@frozen public struct Accept: RequestHeader, Equatable, Hashable, Sendable {
76+
/// The accepted content type
77+
public var type: String
78+
79+
/// The headers dictionary representation.
80+
public var headers: [String: String] {
81+
return ["Accept": type]
82+
}
83+
84+
/// Creates an `Accept` header from a raw value.
85+
///
86+
/// - Parameter type: The content type string.
87+
@inlinable public init(_ type: String) {
88+
self.type = type
89+
}
90+
91+
/// Creates an `Accept` header using a predefined content type.
92+
///
93+
/// - Parameter type: A supported body content type.
94+
@inlinable public init(_ type: BodyContentType) {
95+
self.init(type.value)
96+
}
97+
}
98+
99+
/// A `User-Agent` HTTP header.
100+
///
101+
/// Identifies the client software making the request, such as app name and version.
102+
@frozen public struct UserAgent: RequestHeader, Equatable, Hashable, Sendable {
103+
/// The user agent.
104+
public var agent: String
105+
106+
/// The headers dictionary representation.
107+
public var headers: [String: String] {
108+
return ["User-Agent": agent]
109+
}
110+
111+
/// Creates a `User-Agent` header.
112+
///
113+
/// - Parameter agent: The user agent string to apply.
114+
@inlinable public init(_ agent: String) {
115+
self.agent = agent
116+
}
117+
}
118+
119+
/// A `Content-Disposition` HTTP header.
120+
///
121+
/// Used to control content delivery, often for file uploads or downloads.
122+
@frozen public struct ContentDisposition: RequestHeader, Equatable, Hashable, Sendable {
123+
/// The header value.
124+
public let value: String
125+
126+
/// The headers dictionary representation.
127+
public var headers: [String: String] {
128+
return ["Content-Disposition": value]
129+
}
130+
131+
/// Creates a `Content-Disposition` header with a custom value.
132+
///
133+
/// - Parameter value: The header value to apply.
134+
@inlinable public init(_ value: String) {
135+
self.value = value
136+
}
137+
138+
/// Creates a `Content-Disposition` header for form data.
139+
///
140+
/// - Parameters:
141+
/// - name: The name of the form field.
142+
/// - fileName: The optional file name to associate with the field.
143+
public init(name: String, fileName: String? = nil) {
144+
var disposition = """
145+
form-data; name="\(name)"
146+
"""
147+
if let fileName {
148+
disposition += """
149+
; filename="\(fileName)"
150+
"""
151+
}
152+
self.init(disposition)
153+
}
154+
}
155+
156+
/// An `Authorization` HTTP header.
157+
///
158+
/// Use this header to apply authentication credentials to requests, such as bearer tokens or
159+
/// basic authentication.
160+
@frozen public struct Authorization: RequestHeader, Equatable, Hashable, Sendable {
161+
/// The raw value to use for the `Authorization` header.
162+
public var value: String
163+
164+
/// The headers dictionary representation.
165+
public var headers: [String: String] {
166+
return ["Authorization": value]
167+
}
168+
169+
/// Creates an `Authorization` header from a raw value.
170+
///
171+
/// Use this when you already have a formatted string such as `"Bearer abc123"` or
172+
/// a custom scheme.
173+
///
174+
/// - Parameter value: The full authorization header value.
175+
@inlinable public init(_ value: String) {
176+
self.value = value
177+
}
178+
179+
/// Creates an `Authorization` header using a bearer token.
180+
///
181+
/// The value will be formatted as `"Bearer <token>"`.
182+
///
183+
/// - Parameter token: The bearer token to apply.
184+
@inlinable public init(bearer token: String) {
185+
self.init("Bearer \(token)")
186+
}
187+
188+
/// Creates an `Authorization` header using HTTP Basic authentication.
189+
///
190+
/// Combines the username and password into a base64-encoded string and formats
191+
/// the value as `"Basic <base64(username:password)>"`.
192+
///
193+
/// - Parameters:
194+
/// - username: The username to include.
195+
/// - password: The password to include.
196+
public init(username: String, password: String) {
197+
let base64 = "\(username):\(password)"
198+
.data(using: .utf8)!
199+
.base64EncodedString()
200+
self.init("Basic \(base64)")
201+
}
202+
}

Sources/NetworkingCore/RequestModifiers/Headers/ContentDisposition.swift

Lines changed: 0 additions & 43 deletions
This file was deleted.

Sources/NetworkingCore/RequestModifiers/Headers/ContentType.swift

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,26 @@ import UniformTypeIdentifiers
1313
/// A `Content-Type` header modifier.
1414
@frozen public struct ContentType: RequestHeader, Equatable, Hashable, Sendable {
1515
/// The content type.
16-
public var type: BodyContentType
16+
public var type: String
1717

1818
/// The headers dictionary representation.
1919
public var headers: [String: String] {
20-
return ["Content-Type": type.value]
20+
return ["Content-Type": type]
2121
}
2222

2323
/// Creates a new ``ContentType`` modifier.
2424
///
2525
/// - Parameter type: The content type to apply.
26-
@inlinable public init(_ type: BodyContentType) {
26+
@inlinable public init(_ type: String) {
2727
self.type = type
2828
}
29+
30+
/// Creates a new ``ContentType`` modifier.
31+
///
32+
/// - Parameter type: The content type to apply.
33+
@inlinable public init(_ type: BodyContentType) {
34+
self.init(type.value)
35+
}
2936
}
3037

3138
/// The standard HTTP content types.
@@ -41,8 +48,17 @@ import UniformTypeIdentifiers
4148
/// - Parameter boundary: The boundary string used for separating parts.
4249
case multipartFormData(boundary: String)
4350

44-
/// Custom content type.
45-
case custom(String)
51+
/// `text/plain`.
52+
case text
53+
54+
/// `text/html`.
55+
case html
56+
57+
/// `application/xml`.
58+
case applicationXML
59+
60+
/// `*/*`.
61+
case any
4662

4763
#if canImport(UniformTypeIdentifiers)
4864
/// Mime Type
@@ -58,8 +74,14 @@ import UniformTypeIdentifiers
5874
return "application/json"
5975
case .multipartFormData(let boundary):
6076
return "multipart/form-data; boundary=\(boundary)"
61-
case .custom(let type):
62-
return type
77+
case .text:
78+
return "text/plain"
79+
case .html:
80+
return "text/html"
81+
case .applicationXML:
82+
return "application/xml"
83+
case .any:
84+
return "*/*"
6385
#if canImport(UniformTypeIdentifiers)
6486
case .mime(let type):
6587
return type.preferredMIMEType ?? "Unsupported"

Tests/NetworkingCoreTests/Request Modifiers/Body Tests/FormDataBodyTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ struct FormDataBodyTests {
113113
#expect(result.contains("key = \(key)"))
114114
#expect(result.contains("fileName = \(fileName)"))
115115
#expect(result.contains("mimeType = \(mimeType.description)"))
116-
#expect(result.contains(contentType.type.value))
116+
#expect(result.contains(contentType.type))
117117
}
118118

119119
@Test func descriptionIncludesAllFieldsWithoutFileNameAndMimeType() {

Tests/NetworkingCoreTests/Request Modifiers/Body Tests/FormDataFileTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ final class FormDataFileTests {
184184
#expect(result.contains("fileName = \(fileName)"))
185185
#expect(result.contains("fileURL = \(tempFileURL!)"))
186186
#expect(result.contains("mimeType = \(mimeType.description)"))
187-
#expect(result.contains(contentType.type.value))
187+
#expect(result.contains(contentType.type))
188188
}
189189

190190
@Test func descriptionIncludesAllFieldsWithoutFileNameAndMimeType() {

Tests/NetworkingCoreTests/Request Modifiers/Body Tests/RequestBodyTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct RequestBodyTests {
1717
@Test(arguments: [
1818
ContentType(.applicationFormURLEncoded),
1919
ContentType(.applicationJson),
20-
ContentType(.custom("Custom"))
20+
ContentType("Custom")
2121
])
2222
func requestBodySetsContentType(expectedContentType: ContentType) throws {
2323
let body = "Test Body".data(using: .utf8)

0 commit comments

Comments
 (0)