Skip to content

Commit 27cd8c2

Browse files
committed
fix: Disallow request body for GET requests to comply with standard HTTP usage
1 parent 8bdc8be commit 27cd8c2

File tree

2 files changed

+50
-12
lines changed

2 files changed

+50
-12
lines changed

README.md

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ SwiftApiAdapter is a Swift package designed to streamline the process of retriev
1414
- **Extra Data Management**: Store additional necessary information about the API using the `extraData` field.
1515
- **Web Page Content Loading**: Load and process web page content using the same interface as for API content.
1616

17+
### Important Note About `GET` Requests
18+
19+
In compliance with standard HTTP usage, **SwiftApiAdapter does not attach any request body if the HTTP method is `GET`**. If your configuration specifies `GET` along with a non-empty body, the body will be ignored. If you need to send a payload, please switch to a method like `POST` or `PUT`.
20+
1721
## Installation
1822

1923
### Swift Package Manager
@@ -22,7 +26,7 @@ Add SwiftApiAdapter to your project via Swift Package Manager by including it in
2226

2327
```swift
2428
dependencies: [
25-
.package(url: "https://github.com/yourusername/SwiftApiAdapter.git", from: "1.0.0")
29+
.package(url: "https://github.com/RayKitajima/SwiftApiAdapter.git", from: "1.0.0")
2630
]
2731
```
2832

@@ -60,7 +64,7 @@ let response = await apiConnector.requester.processJsonApi(
6064
endpoint: endpoint,
6165
method: "GET",
6266
headers: headers,
63-
body: "" // Empty body for GET request
67+
body: "" // Empty body for GET request; otherwise body is ignored
6468
)
6569
```
6670

@@ -266,12 +270,24 @@ class ApiController: ObservableObject {
266270
@Published var imageData: Data?
267271

268272
func loadImageContent() async {
273+
let apiContentImage = ApiContent(
274+
id: UUID(),
275+
name: "Image API Content",
276+
endpoint: "https://exampleapi.com/image",
277+
method: .get,
278+
headers: ["Authorization": "Bearer your_access_token"],
279+
body: "",
280+
arguments: ["image": "[\"data\"][0][\"message\"][\"content\"]"],
281+
contentType: .base64image
282+
)
283+
269284
do {
270285
let apiContentRack = try await ApiContentLoader.load(
271286
contextId: UUID(),
272287
apiContent: apiContentImage
273288
)
274-
if let apiContentRack = apiContentRack, let base64String = apiContentRack.arguments["image"],
289+
if let apiContentRack = apiContentRack,
290+
let base64String = apiContentRack.arguments["image"],
275291
let imageData = Data(base64Encoded: base64String) {
276292
DispatchQueue.main.async {
277293
self.imageData = imageData
@@ -330,12 +346,24 @@ class ApiController: ObservableObject {
330346
@Published var textData: String?
331347

332348
func loadTextContent() async {
349+
let apiContentText = ApiContent(
350+
id: UUID(),
351+
name: "Text API Content",
352+
endpoint: "https://exampleapi.com/text",
353+
method: .get,
354+
headers: ["Authorization": "Bearer your_access_token"],
355+
body: "",
356+
arguments: ["text": "[\"choices\"][0][\"message\"][\"content\"]"],
357+
contentType: .text
358+
)
359+
333360
do {
334361
let apiContentRack = try await ApiContentLoader.load(
335362
contextId: UUID(),
336363
apiContent: apiContentText
337364
)
338-
if let apiContentRack = apiContentRack, let text = apiContentRack.arguments["text"] {
365+
if let apiContentRack = apiContentRack,
366+
let text = apiContentRack.arguments["text"] {
339367
DispatchQueue.main.async {
340368
self.textData = text
341369
}
@@ -371,7 +399,7 @@ ApiConnectorManager.shared.clearAllConnectors()
371399

372400
## Configuration
373401

374-
You can customize headers for each API request, allowing the setting of `User-Agent` and other necessary headers depending on the endpoint requirements.
402+
You can customize headers for each API request, allowing the setting of `User-Agent` and other necessary headers depending on the endpoint requirements. However, remember that **for GET requests, any provided body data will be ignored**.
375403

376404
## Contributing
377405

Sources/SwiftApiAdapter/Connector.swift

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,20 +238,30 @@ public class ApiSerialExecutor: @unchecked Sendable {
238238
goNextRequest: (() -> Void)? = nil
239239
) {
240240
var request = URLRequest(url: endpoint)
241-
request.httpMethod = method
241+
242+
// If method is GET and there's a body, do not attach httpBody
243+
if method.uppercased() == "GET" && !executionRequest.requestData.isEmpty {
244+
#if DEBUG
245+
print("[ApiSerialExecutor] GET request with body is not allowed; ignoring body.")
246+
#endif
247+
request.httpMethod = method
248+
} else {
249+
request.httpMethod = method
250+
// normal body-attachment steps
251+
if let requestJson = try? JSONSerialization.jsonObject(with: executionRequest.requestData, options: []) as? [String: Any] {
252+
if let requestBody = try? JSONSerialization.data(withJSONObject: requestJson, options: []) {
253+
request.httpBody = requestBody
254+
}
255+
}
256+
}
257+
242258
request.addValue(DEFAULT_USER_AGENT, forHTTPHeaderField: "User-Agent")
243259
for (key, value) in headers {
244260
if !key.isEmpty && !value.isEmpty {
245261
request.addValue(value, forHTTPHeaderField: key)
246262
}
247263
}
248264

249-
if let requestJson = try? JSONSerialization.jsonObject(with: executionRequest.requestData, options: []) as? [String: Any] {
250-
if let requestBody = try? JSONSerialization.data(withJSONObject: requestJson, options: []) {
251-
request.httpBody = requestBody
252-
}
253-
}
254-
255265
let defaultConfig = URLSessionConfiguration.default
256266
defaultConfig.timeoutIntervalForRequest = 180
257267

0 commit comments

Comments
 (0)