Skip to content

Commit 969e223

Browse files
authored
Fix security scheme duplication issue (#39)
- fix security scheme duplication issue - update readme, prep for release
1 parent b55312e commit 969e223

5 files changed

Lines changed: 111 additions & 6 deletions

File tree

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
The FeatherOpenAPI library makes it easy to define OpenAPI specifications using Swift in a type-safe way.
44

55
[
6-
![Release: 1.0.0-beta.4](https://img.shields.io/badge/Release-1%2E0%2E0--beta%2E4-F05138)
6+
![Release: 1.0.0-beta.5](https://img.shields.io/badge/Release-1%2E0%2E0--beta%2E5-F05138)
77
](
8-
https://github.com/feather-framework/feather-openapi/releases/tag/1.0.0-beta.4
8+
https://github.com/feather-framework/feather-openapi/releases/tag/1.0.0-beta.5
99
)
1010

1111
## Features
@@ -34,7 +34,7 @@ The FeatherOpenAPI library makes it easy to define OpenAPI specifications using
3434
Use Swift Package Manager; add the dependency to your `Package.swift` file:
3535

3636
```swift
37-
.package(url: "https://github.com/feather-framework/feather-openapi", exact: "1.0.0-beta.4"),
37+
.package(url: "https://github.com/feather-framework/feather-openapi", exact: "1.0.0-beta.5"),
3838
```
3939

4040
Then add `FeatherOpenAPI` to your target dependencies:

Sources/FeatherOpenAPI/Document/DocumentRepresentable.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,20 @@ extension DocumentRepresentable {
5656
public var referencedSecurityRequirements:
5757
[SecurityRequirementRepresentable]
5858
{
59-
paths.values.map { $0.referencedSecurityRequirements }.flatMap { $0 }
59+
var seen = Set<String>()
60+
return paths.values
61+
.map { $0.referencedSecurityRequirements }
62+
.flatMap { $0 }
63+
.filter { requirement in
64+
let requirementID =
65+
requirement.security.openAPIIdentifier + "::"
66+
+ requirement.requirements.sorted().joined(separator: ",")
67+
if seen.contains(requirementID) {
68+
return false
69+
}
70+
seen.insert(requirementID)
71+
return true
72+
}
6073
}
6174

6275
/// Builds an OpenAPI document from the representable values.

Tests/FeatherOpenAPITests/FeatherOpenAPITestSuite.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ struct FeatherOpenAPITestSuite {
3030
#expect(tags.map(\.name) == ["Dogs"])
3131
}
3232

33+
@Test
34+
func documentDeduplicatesSecurityRequirementsBySchemeAndRequirements() {
35+
let document = SecurityRequirementDedupDocument(
36+
info: SecurityRequirementDedupInfo(),
37+
paths: SecurityRequirementDedupPaths().pathMap,
38+
components: Components()
39+
)
40+
41+
let openAPIDoc = document.openAPIDocument()
42+
let security = openAPIDoc.security
43+
44+
#expect(security.count == 1)
45+
}
46+
3347
@Test
3448
func multipleVersions() throws {
3549

Tests/FeatherOpenAPITests/TestObjects.swift

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,81 @@ struct TagDedupCreateDogOperation: OperationRepresentable {
247247
]
248248
}
249249
}
250+
251+
// MARK: -
252+
253+
struct SecurityRequirementDedupInfo: InfoRepresentable {
254+
var title: String { "Security Requirement Dedup Test" }
255+
var version: String { "1.0.0" }
256+
}
257+
258+
struct SecurityRequirementDedupDocument: DocumentRepresentable {
259+
var info: OpenAPIInfoRepresentable
260+
var paths: PathMap
261+
var components: OpenAPIComponentsRepresentable
262+
}
263+
264+
struct SecurityRequirementDedupPaths: PathCollectionRepresentable {
265+
var pathMap: PathMap {
266+
[
267+
"cats": SecurityRequirementDedupCatPathItem()
268+
]
269+
}
270+
}
271+
272+
struct SecurityRequirementDedupCatPathItem: PathItemRepresentable {
273+
var get: OperationRepresentable? {
274+
SecurityRequirementDedupListCatsOperation()
275+
}
276+
var post: OperationRepresentable? {
277+
SecurityRequirementDedupCreateCatOperation()
278+
}
279+
}
280+
281+
struct SecurityRequirementDedupBearerTokenScheme: SecuritySchemeRepresentable {
282+
var type: OpenAPI.SecurityScheme.SecurityType {
283+
.http(
284+
scheme: "bearer",
285+
bearerFormat: "token"
286+
)
287+
}
288+
}
289+
290+
struct SecurityRequirementDedupBearerTokenRequirement:
291+
SecurityRequirementRepresentable
292+
{
293+
var security: any SecuritySchemeRepresentable {
294+
SecurityRequirementDedupBearerTokenScheme()
295+
}
296+
}
297+
298+
struct SecurityRequirementDedupCatSchema: StringSchemaRepresentable {
299+
var example: String? = "Milo"
300+
}
301+
302+
struct SecurityRequirementDedupCatResponse: JSONResponseRepresentable {
303+
var description: String = "Cat response"
304+
var schema: SecurityRequirementDedupCatSchema = .init()
305+
}
306+
307+
struct SecurityRequirementDedupListCatsOperation: OperationRepresentable {
308+
var security: [SecurityRequirementRepresentable]? {
309+
[SecurityRequirementDedupBearerTokenRequirement()]
310+
}
311+
var responseMap: ResponseMap {
312+
[
313+
200: SecurityRequirementDedupCatResponse().reference()
314+
]
315+
}
316+
}
317+
318+
struct SecurityRequirementDedupCreateCatOperation: OperationRepresentable {
319+
var security: [SecurityRequirementRepresentable]? {
320+
[SecurityRequirementDedupBearerTokenRequirement()]
321+
}
322+
var responseMap: ResponseMap {
323+
[
324+
200: SecurityRequirementDedupCatResponse().reference()
325+
]
326+
}
327+
}

0 commit comments

Comments
 (0)