diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..be5f298 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,266 @@ +{ + "pins" : [ + { + "identity" : "async-http-client", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/async-http-client.git", + "state" : { + "revision" : "fb308ee72f3d4c082a507033f94afa7395963ef3", + "version" : "1.21.0" + } + }, + { + "identity" : "async-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/async-kit.git", + "state" : { + "revision" : "7ece208cd401687641c88367a00e3ea2b04311f1", + "version" : "1.19.0" + } + }, + { + "identity" : "console-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/console-kit.git", + "state" : { + "revision" : "a31f44ebfbd15a2cc0fda705279676773ac16355", + "version" : "4.14.1" + } + }, + { + "identity" : "fluent", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/fluent.git", + "state" : { + "revision" : "a586a5d4164f23a0ee4e02e1f467b9bbef0c9f1c", + "version" : "4.9.0" + } + }, + { + "identity" : "fluent-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/fluent-kit.git", + "state" : { + "revision" : "5f0938a3f5f1a751ff7a411117bfce4efe713526", + "version" : "1.47.2" + } + }, + { + "identity" : "fluent-postgres-driver", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/fluent-postgres-driver.git", + "state" : { + "revision" : "a538fc647f82d915eb84e0a12ca9b08c513e57c4", + "version" : "2.8.0" + } + }, + { + "identity" : "multipart-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/multipart-kit.git", + "state" : { + "revision" : "12ee56f25bd3fc4c2d09c2aa16e69de61dc786e8", + "version" : "4.6.0" + } + }, + { + "identity" : "postgres-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/postgres-kit.git", + "state" : { + "revision" : "e26763a6cb8d852f7ce01b1cd5925b3d8d084801", + "version" : "2.13.1" + } + }, + { + "identity" : "postgres-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/postgres-nio.git", + "state" : { + "revision" : "e345cbb9cf6052b37b27c0c4f976134fc01dbe15", + "version" : "1.21.1" + } + }, + { + "identity" : "routing-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/routing-kit.git", + "state" : { + "revision" : "2a92a7eac411a82fb3a03731be5e76773ebe1b3e", + "version" : "4.9.0" + } + }, + { + "identity" : "sql-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/sql-kit.git", + "state" : { + "revision" : "b2f128cb62a3abfbb1e3b2893ff3ee69e70f4f0f", + "version" : "3.28.0" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms.git", + "state" : { + "revision" : "da4e36f86544cdf733a40d59b3a2267e3a7bbf36", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "cd142fd2f64be2100422d658e7411e39489da985", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "f0525da24dc3c6cbb2b6b338b65042bc91cbc4bb", + "version" : "3.3.0" + } + }, + { + "identity" : "swift-http-types", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-types", + "state" : { + "revision" : "12358d55a3824bd5fed310b999ea8cf83a9a1a65", + "version" : "1.0.3" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5", + "version" : "1.5.4" + } + }, + { + "identity" : "swift-metrics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-metrics.git", + "state" : { + "revision" : "971ba26378ab69c43737ee7ba967a896cb74c0d1", + "version" : "2.4.1" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "fc63f0cf4e55a4597407a9fc95b16a2bc44b4982", + "version" : "2.64.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "a3b640d7dc567225db7c94386a6e71aded1bfa63", + "version" : "1.22.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "0904bf0feb5122b7e5c3f15db7df0eabe623dd87", + "version" : "1.30.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "7c381eb6083542b124a6c18fae742f55001dc2b5", + "version" : "2.26.0" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "6cbe0ed2b394f21ab0d46b9f0c50c6be964968ce", + "version" : "1.20.1" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics.git", + "state" : { + "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", + "version" : "1.0.2" + } + }, + { + "identity" : "swift-service-lifecycle", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/swift-service-lifecycle.git", + "state" : { + "revision" : "d7fe0e731499a8dcce53bf4cbbc812c8e565d3a7", + "version" : "2.4.1" + } + }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", + "version" : "1.2.1" + } + }, + { + "identity" : "vapor", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/vapor.git", + "state" : { + "revision" : "8409c3c296e7f8965df14e906dbcd44eb68f54a9", + "version" : "4.92.6" + } + }, + { + "identity" : "websocket-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/websocket-kit.git", + "state" : { + "revision" : "4232d34efa49f633ba61afde365d3896fc7f8740", + "version" : "2.15.0" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift index c0ae1d3..fd79d3d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.10 +// swift-tools-version:5.9 import PackageDescription let package = Package( diff --git a/Sources/App/Controllers/TodoController.swift b/Sources/App/Controllers/TodoController.swift deleted file mode 100644 index 30b7726..0000000 --- a/Sources/App/Controllers/TodoController.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Fluent -import Vapor - -struct TodoController: RouteCollection { - func boot(routes: RoutesBuilder) throws { - let todos = routes.grouped("todos") - - todos.get(use: { try await self.index(req: $0) }) - todos.post(use: { try await self.create(req: $0) }) - todos.group(":todoID") { todo in - todo.delete(use: { try await self.delete(req: $0) }) - } - } - - func index(req: Request) async throws -> [Todo] { - try await Todo.query(on: req.db).all() - } - - func create(req: Request) async throws -> Todo { - let todo = try req.content.decode(Todo.self) - - try await todo.save(on: req.db) - return todo - } - - func delete(req: Request) async throws -> HTTPStatus { - guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else { - throw Abort(.notFound) - } - - try await todo.delete(on: req.db) - return .noContent - } -} diff --git a/Sources/App/Controllers/cntrlAssociate.swift b/Sources/App/Controllers/cntrlAssociate.swift new file mode 100644 index 0000000..f157b82 --- /dev/null +++ b/Sources/App/Controllers/cntrlAssociate.swift @@ -0,0 +1,82 @@ +// +// cntrlAddociate.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + +import Fluent +import Vapor +import Crypto + + + +struct cntrlAssociate: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let rts = routes.grouped("associates") + rts.get(use: index) + rts.get(":x", use: read) + rts.post(use: create) + rts.delete(":x", use: delete) + //Additional routs added here + } + + @Sendable + func index(req: Request) async throws -> Response { + guard let obj = try? await mdlAssociate.ObjQuery(req: req).all() else { + throw Abort(.badGateway, reason: "Something went wrong with this api.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Array could not be shown.") + } + return response + } + + @Sendable + func read(req:Request) async throws -> Response{ + guard let obj = try? await mdlAssociate.ObjQuery(req: req).first() else{ + throw Abort(.notFound, reason: "Associate was not found.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else { + throw Abort(.noContent, reason: "Something went wrong decoding object.") + } + return response + } + + @Sendable + func create(req: Request) async throws -> Response { + + guard let obj = try? req.content.decode(mdlAssociate.self) else { + throw Abort(.notAcceptable, reason: "Associate json not formatted correctly or is missing parents.") + } + var exists = false + if(obj.id != nil){ + obj._$idExists = true + exists = true + } + guard let _ = try? await obj.save(on: req.db) else{ + throw Abort(.conflict, reason: "Something conflicts in the database. Associate cannot be saved.") + } + + guard let response = try? await obj.encodeResponse(status: exists ? .accepted : .created, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Associate has been saved.") + } + return response + } + + + @Sendable + func delete(req: Request) async throws -> Response { + guard let obj = try? await mdlAssociate.ObjQuery(req: req).first() else { + throw Abort(.notFound, reason: "Associate's ID was not supplied. Associate will not be deleted") + } + guard let _ = try? await obj.delete(on: req.db) else{ + throw Abort(.conflict, reason: "There was a conflict deleting Associate. Make sure it has not children.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Associate has been deleted.") + } + return response + } +} + diff --git a/Sources/App/Controllers/cntrlDepartment.swift b/Sources/App/Controllers/cntrlDepartment.swift new file mode 100644 index 0000000..183e5f3 --- /dev/null +++ b/Sources/App/Controllers/cntrlDepartment.swift @@ -0,0 +1,81 @@ +// +// cntrlDepartment.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + +import Fluent +import Vapor +import Crypto + + + +struct cntrlDepartment: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let rts = routes.grouped("departments") + rts.get(use: index) + rts.get(":x", use: read) + rts.post(use: create) + rts.delete(":x", use: delete) + //Additional routs added here + } + + @Sendable + func index(req: Request) async throws -> Response { + guard let obj = try? await mdlDepartment.ObjQuery(req: req).all() else { + throw Abort(.badGateway, reason: "Something went wrong with this api.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Array could not be shown.") + } + return response + } + + @Sendable + func read(req:Request) async throws -> Response{ + guard let obj = try? await mdlDepartment.ObjQuery(req: req).first() else{ + throw Abort(.notFound, reason: "Department was not found.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else { + throw Abort(.noContent, reason: "Something went wrong decoding object.") + } + return response + } + + @Sendable + func create(req: Request) async throws -> Response { + + guard let obj = try? req.content.decode(mdlDepartment.self) else { + throw Abort(.notAcceptable, reason: "Department json not formatted correctly or is missing parents.") + } + var exists = false + if(obj.id != nil){ + obj._$idExists = true + exists = true + } + guard let _ = try? await obj.save(on: req.db) else{ + throw Abort(.conflict, reason: "Something conflicts in the database. Department cannot be saved.") + } + + guard let response = try? await obj.encodeResponse(status: exists ? .accepted : .created, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Department has been saved.") + } + return response + } + + @Sendable + func delete(req: Request) async throws -> Response { + guard let obj = try? await mdlDepartment.ObjQuery(req: req).first() else { + throw Abort(.notFound, reason: "Department's ID was not supplied. Department will not be deleted") + } + guard let _ = try? await obj.delete(on: req.db) else{ + throw Abort(.conflict, reason: "There was a conflict deleting Department. Make sure it has not children.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Department has been deleted.") + } + return response + } +} + diff --git a/Sources/App/Controllers/cntrlDocType.swift b/Sources/App/Controllers/cntrlDocType.swift new file mode 100644 index 0000000..2908ab2 --- /dev/null +++ b/Sources/App/Controllers/cntrlDocType.swift @@ -0,0 +1,81 @@ +// +// cntrlDocType.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + +import Fluent +import Vapor +import Crypto + + + +struct cntrlDocType: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let rts = routes.grouped("doctypes") + rts.get(use: index) + rts.get(":x", use: read) + rts.post(use: create) + rts.delete(":x", use: delete) + //Additional routs added here + } + + @Sendable + func index(req: Request) async throws -> Response { + guard let obj = try? await mdlDocType.ObjQuery(req: req).all() else { + throw Abort(.badGateway, reason: "Something went wrong with this api.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Array could not be shown.") + } + return response + } + + @Sendable + func read(req:Request) async throws -> Response{ + guard let obj = try? await mdlDocType.ObjQuery(req: req).first() else{ + throw Abort(.notFound, reason: "DocType was not found.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else { + throw Abort(.noContent, reason: "Something went wrong decoding object.") + } + return response + } + + @Sendable + func create(req: Request) async throws -> Response { + + guard let obj = try? req.content.decode(mdlDocType.self) else { + throw Abort(.notAcceptable, reason: "DocType json not formatted correctly or is missing parents.") + } + var exists = false + if(obj.id != nil){ + obj._$idExists = true + exists = true + } + guard let _ = try? await obj.save(on: req.db) else{ + throw Abort(.conflict, reason: "Something conflicts in the database. DocType cannot be saved.") + } + + guard let response = try? await obj.encodeResponse(status: exists ? .accepted : .created, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. DocType has been saved.") + } + return response + } + + @Sendable + func delete(req: Request) async throws -> Response { + guard let obj = try? await mdlDocType.ObjQuery(req: req).first() else { + throw Abort(.notFound, reason: "DocType's ID was not supplied. DocType will not be deleted") + } + guard let _ = try? await obj.delete(on: req.db) else{ + throw Abort(.conflict, reason: "There was a conflict deleting DocType. Make sure it has not children.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. DocType has been deleted.") + } + return response + } +} + diff --git a/Sources/App/Controllers/cntrlDocument.swift b/Sources/App/Controllers/cntrlDocument.swift new file mode 100644 index 0000000..11833e8 --- /dev/null +++ b/Sources/App/Controllers/cntrlDocument.swift @@ -0,0 +1,81 @@ +// +// cntrlDocument.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + +import Fluent +import Vapor +import Crypto + + + +struct cntrlDocument: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let rts = routes.grouped("documents") + rts.get(use: index) + rts.get(":x", use: read) + rts.post(use: create) + rts.delete(":x", use: delete) + //Additional routs added here + } + + @Sendable + func index(req: Request) async throws -> Response { + guard let obj = try? await mdlDocument.ObjQuery(req: req).all() else { + throw Abort(.badGateway, reason: "Something went wrong with this api.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Array could not be shown.") + } + return response + } + + @Sendable + func read(req:Request) async throws -> Response{ + guard let obj = try? await mdlDocument.ObjQuery(req: req).first() else{ + throw Abort(.notFound, reason: "Document was not found.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else { + throw Abort(.noContent, reason: "Something went wrong decoding object.") + } + return response + } + + @Sendable + func create(req: Request) async throws -> Response { + + guard let obj = try? req.content.decode(mdlDocument.self) else { + throw Abort(.notAcceptable, reason: "Document json not formatted correctly or is missing parents.") + } + var exists = false + if(obj.id != nil){ + obj._$idExists = true + exists = true + } + guard let _ = try? await obj.save(on: req.db) else{ + throw Abort(.conflict, reason: "Something conflicts in the database. Document cannot be saved.") + } + + guard let response = try? await obj.encodeResponse(status: exists ? .accepted : .created, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Document has been saved.") + } + return response + } + + @Sendable + func delete(req: Request) async throws -> Response { + guard let obj = try? await mdlDocument.ObjQuery(req: req).first() else { + throw Abort(.notFound, reason: "Document's ID was not supplied. Document will not be deleted") + } + guard let _ = try? await obj.delete(on: req.db) else{ + throw Abort(.conflict, reason: "There was a conflict deleting Document. Make sure it has not children.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Document has been deleted.") + } + return response + } +} + diff --git a/Sources/App/Controllers/cntrlXAssociateDepartment.swift b/Sources/App/Controllers/cntrlXAssociateDepartment.swift new file mode 100644 index 0000000..05d7153 --- /dev/null +++ b/Sources/App/Controllers/cntrlXAssociateDepartment.swift @@ -0,0 +1,81 @@ +// +// cntrlXAssociateDepartment.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + +import Fluent +import Vapor +import Crypto + + + +struct cntrlXAssociateDepartment: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let rts = routes.grouped("xassociatedepartments") + rts.get(use: index) + rts.get(":x", use: read) + rts.post(use: create) + rts.delete(":x", use: delete) + //Additional routs added here + } + + @Sendable + func index(req: Request) async throws -> Response { + guard let obj = try? await mdlXAssocDept.ObjQuery(req: req).all() else { + throw Abort(.badGateway, reason: "Something went wrong with this api.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Array could not be shown.") + } + return response + } + + @Sendable + func read(req:Request) async throws -> Response{ + guard let obj = try? await mdlXAssocDept.ObjQuery(req: req).first() else{ + throw Abort(.notFound, reason: "XAssociateDepartment was not found.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else { + throw Abort(.noContent, reason: "Something went wrong decoding object.") + } + return response + } + + @Sendable + func create(req: Request) async throws -> Response { + + guard let obj = try? req.content.decode(mdlXAssocDept.self) else { + throw Abort(.notAcceptable, reason: "XAssociateDepartment json not formatted correctly or is missing parents.") + } + var exists = false + if(obj.id != nil){ + obj._$idExists = true + exists = true + } + guard let _ = try? await obj.save(on: req.db) else{ + throw Abort(.conflict, reason: "Something conflicts in the database. XAssociateDepartment cannot be saved.") + } + + guard let response = try? await obj.encodeResponse(status: exists ? .accepted : .created, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. XAssociateDepartment has been saved.") + } + return response + } + + @Sendable + func delete(req: Request) async throws -> Response { + guard let obj = try? await mdlXAssocDept.ObjQuery(req: req).first() else { + throw Abort(.notFound, reason: "XAssociateDepartment's ID was not supplied. XAssociateDepartment will not be deleted") + } + guard let _ = try? await obj.delete(on: req.db) else{ + throw Abort(.conflict, reason: "There was a conflict deleting XAssociateDepartment. Make sure it has not children.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. XAssociateDepartment has been deleted.") + } + return response + } +} + diff --git a/Sources/App/Controllers/cntrlXDocDept.swift b/Sources/App/Controllers/cntrlXDocDept.swift new file mode 100644 index 0000000..7ff4520 --- /dev/null +++ b/Sources/App/Controllers/cntrlXDocDept.swift @@ -0,0 +1,81 @@ +// +// cntrlXDocDept.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + +import Fluent +import Vapor +import Crypto + + + +struct cntrlXDocDept: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let rts = routes.grouped("xdocdepts") + rts.get(use: index) + rts.get(":x", use: read) + rts.post(use: create) + rts.delete(":x", use: delete) + //Additional routs added here + } + + @Sendable + func index(req: Request) async throws -> Response { + guard let obj = try? await mdlXDocDept.ObjQuery(req: req).all() else { + throw Abort(.badGateway, reason: "Something went wrong with this api.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. Array could not be shown.") + } + return response + } + + @Sendable + func read(req:Request) async throws -> Response{ + guard let obj = try? await mdlXDocDept.ObjQuery(req: req).first() else{ + throw Abort(.notFound, reason: "XDocDept was not found.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else { + throw Abort(.noContent, reason: "Something went wrong decoding object.") + } + return response + } + + @Sendable + func create(req: Request) async throws -> Response { + + guard let obj = try? req.content.decode(mdlXDocDept.self) else { + throw Abort(.notAcceptable, reason: "XDocDept json not formatted correctly or is missing parents.") + } + var exists = false + if(obj.id != nil){ + obj._$idExists = true + exists = true + } + guard let _ = try? await obj.save(on: req.db) else{ + throw Abort(.conflict, reason: "Something conflicts in the database. XDocDept cannot be saved.") + } + + guard let response = try? await obj.encodeResponse(status: exists ? .accepted : .created, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. XDocDept has been saved.") + } + return response + } + + @Sendable + func delete(req: Request) async throws -> Response { + guard let obj = try? await mdlXDocDept.ObjQuery(req: req).first() else { + throw Abort(.notFound, reason: "XDocDept's ID was not supplied. XDocDept will not be deleted") + } + guard let _ = try? await obj.delete(on: req.db) else{ + throw Abort(.conflict, reason: "There was a conflict deleting XDocDept. Make sure it has not children.") + } + guard let response = try? await obj.encodeResponse(status: .ok, for: req) else{ + throw Abort(.noContent, reason: "Something went wrong decoding data. XDocDept has been deleted.") + } + return response + } +} + diff --git a/Sources/App/CustomCrypto.swift b/Sources/App/CustomCrypto.swift new file mode 100644 index 0000000..bb5420d --- /dev/null +++ b/Sources/App/CustomCrypto.swift @@ -0,0 +1,52 @@ +// +// File.swift +// +// +// Created by Michiel Carman on 4/2/24. +// + +import Foundation +import Vapor +import Crypto + +enum CryptoError: Error{ + case badRequest +} + +struct CustomCrypto{ + public static func DecryptString(input: String) throws -> String{ + let apikey = Environment.get("API_KEY") ?? "rv0ywT7Ygwh01jP1dQWBP39ogjq5ladO+EoNUGcBVq0=" + print(apikey) + let base64Key = apikey // Replace with your actual key + guard let keyData = Data(base64Encoded: base64Key) else { + fatalError("Invalid Base64 key data") + } + let data = Data(base64Encoded: input) + let encryptionKey = SymmetricKey(data: keyData) + let sealedBox = try! AES.GCM.SealedBox(combined: data!) + let decryptedData = try! AES.GCM.open(sealedBox, using: encryptionKey) + guard let decryptedString = String(data: decryptedData, encoding: .utf8) else{ + throw CryptoError.badRequest + } + return decryptedString + } + + public static func EncryptString(input: String) throws -> String{ + let apikey = Environment.get("API_KEY") ?? "rv0ywT7Ygwh01jP1dQWBP39ogjq5ladO+EoNUGcBVq0=" + print(apikey) + guard let keyData = Data(base64Encoded: apikey) else{ + fatalError("Invalid Base64 key data") + } + let encryptionKey = SymmetricKey(data: keyData) + guard let datatoEncrypt = input.data(using: .utf8) else{ fatalError("Invalid Data")} + do{ + let sealedBox = try AES.GCM.seal(datatoEncrypt, using: encryptionKey) + guard let combined = sealedBox.combined else{ fatalError("Can't combine")} + let base64EncodedString = combined.base64EncodedString() + let urlEncodedString = base64EncodedString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) + return urlEncodedString! + } + } +} + + diff --git a/Sources/App/Migrations/AllMigrations.swift b/Sources/App/Migrations/AllMigrations.swift new file mode 100644 index 0000000..1d916e6 --- /dev/null +++ b/Sources/App/Migrations/AllMigrations.swift @@ -0,0 +1,24 @@ +// +// File.swift +// +// +// Created by Michiel Carman on 4/11/24. +// + +import NIOSSL +import Fluent +import FluentPostgresDriver +import Vapor + +public func doMigrations(_ app: Application) async throws{ + + app.migrations.add(mdlAssociate.Create()) + app.migrations.add(mdlDepartment.Create()) + app.migrations.add(mdlDepartment.AddParentReference()) + app.migrations.add(mdlDocType.Create()) + app.migrations.add(mdlDocument.Create()) + app.migrations.add(mdlXAssocDept.Create()) + app.migrations.add(mdlXDocDept.Create()) + + try await app.autoMigrate() +} diff --git a/Sources/App/Migrations/CreateTodo.swift b/Sources/App/Migrations/CreateTodo.swift deleted file mode 100644 index bf6d945..0000000 --- a/Sources/App/Migrations/CreateTodo.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Fluent - -struct CreateTodo: AsyncMigration { - func prepare(on database: Database) async throws { - try await database.schema("todos") - .id() - .field("title", .string, .required) - .create() - } - - func revert(on database: Database) async throws { - try await database.schema("todos").delete() - } -} diff --git a/Sources/App/Models/Todo.swift b/Sources/App/Models/Todo.swift deleted file mode 100644 index c3c9eac..0000000 --- a/Sources/App/Models/Todo.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Fluent -import Vapor - -final class Todo: Model, Content { - static let schema = "todos" - - @ID(key: .id) - var id: UUID? - - @Field(key: "title") - var title: String - - init() { } - - init(id: UUID? = nil, title: String) { - self.id = id - self.title = title - } -} diff --git a/Sources/App/Models/mdlAssociate.swift b/Sources/App/Models/mdlAssociate.swift new file mode 100644 index 0000000..fac4b32 --- /dev/null +++ b/Sources/App/Models/mdlAssociate.swift @@ -0,0 +1,100 @@ +// +// mdlUser.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + + +import Fluent +import Vapor +import Foundation +import FluentKit + +final class mdlAssociate: Model, Content { + static let schema = "associate" + + @ID(custom: "id", generatedBy: .database) var id: Int? + + @Field(key: "firstName") var firstname: String? + @Field(key: "lastName") var lastname: String? + + @Siblings(through: mdlXAssocDept.self, from: \.$associate, to: \.$department) var departments: [mdlDepartment] + + @Timestamp(key: "createDate", on: .create) var createdate: Date? + @Field(key: "createUserId") var createuserid: Int? + @Timestamp(key: "updateDate", on: .update) var updatedate: Date? + @Field(key: "updateUserId") var updateuserid: Int? + + init() { } + + init(id: Int? = nil, + firstname: String? = nil, + lastname: String? = nil, + createuserid: Int? = nil, + updateuserid: Int? = nil + ) { + self.id = id + self.firstname = firstname + self.lastname = lastname + self.createuserid = createuserid + self.updateuserid = updateuserid + } +} +extension mdlAssociate{ + struct Create: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("associate") + .field("id", .int, .identifier(auto: true)) + .field("firstName", .string) + .field("lastName", .string) + .field("createDate", .datetime) + .field("createUserId", .int) + .field("updateDate", .datetime) + .field("updateUserId", .int) + .create() + } + + func revert(on database: Database) async throws { + try await database.schema("associate").delete() + } + } + public static func ObjQuery(req: Request) async throws -> QueryBuilder{ + + let query = mdlAssociate.query(on: req.db) + .with(\.$departments){ + dept in dept.with(\.$documents){ + doc in doc + .with(\.$doctype) + .with(\.$parent) + .with(\.$subsequent) + } + } + + if let x = req.parameters.get("x"){ + let decryptedString = try CustomCrypto.DecryptString(input: x) + let array = decryptedString.components(separatedBy: ":") + ///This call is the standard get by id call + if (array.count == 1){ + let id = Int(array[0])! + return query.filter(\.$id == id) + } + ///Optional else if if there are multiple parameters in the call + ///You must include an else for each call that has parameters + ///Need to check the endpoint to get the right filter statements + ///else if(x.count == 2){ + /// let username = x[0] + /// let password = x[1] + /// return query.filter(\.$username == username).filter(\.$password == password) + ///} + else{ + throw Abort(.badRequest) + } + + } + else{ + return query + } + } +} + diff --git a/Sources/App/Models/mdlDepartment.swift b/Sources/App/Models/mdlDepartment.swift new file mode 100644 index 0000000..6eb52ba --- /dev/null +++ b/Sources/App/Models/mdlDepartment.swift @@ -0,0 +1,118 @@ +// +// mdlDepartment.swift +// +// +// Created by Michiel Carman on 4/11/2024. +// + + +import Fluent +import Vapor +import Foundation +import FluentKit + +final class mdlDepartment: Model, Content { + static let schema = "department" + + @ID(custom: "id", generatedBy: .database) var id: Int? + + @Field(key: "name") var name: String? + @OptionalParent(key: "parentId") var parent: mdlDepartment? + @Children(for: \.$parent) var subdepartments: [mdlDepartment] + + @Siblings(through: mdlXAssocDept.self, from: \.$department, to: \.$associate) var associates: [mdlAssociate] + @Siblings(through: mdlXDocDept.self, from: \.$department, to: \.$document) var documents: [mdlDocument] + + @Timestamp(key: "createDate", on: .create) var createdate: Date? + @Field(key: "createUserId") var createuserid: Int? + @Timestamp(key: "updateDate", on: .update) var updatedate: Date? + @Field(key: "updateUserId") var updateuserid: Int? + + init() { } + + init(id: Int? = nil, + name: String? = nil, + parentid: Int? = nil, + createuserid: Int? = nil, + updateuserid: Int? = nil + ) { + self.id = id + self.name = name + if(parentid != nil) { self.$parent.$id.value = parentid } + self.createuserid = createuserid + self.updateuserid = updateuserid + } +} +extension mdlDepartment{ + struct Create: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("department") + .field("id", .int, .identifier(auto: true)) + .field("name", .string) + .field("departmentId", .int) + .field("createDate", .datetime) + .field("createUserId", .int) + .field("updateDate", .datetime) + .field("updateUserId", .int) + .create() + } + + func revert(on database: Database) async throws { + try await database.schema("department").delete() + } + } + struct AddParentReference: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("department") + .deleteField("departmentId") + .field("departmentId", .int, .references("department", "id")) + .update() + } + + func revert(on database: Database) async throws { + try await database.schema("department") + .deleteField("departmentId") + .field("departmentId", .int) + .update() + } + } + public static func ObjQuery(req: Request) async throws -> QueryBuilder{ + + let query = mdlDepartment.query(on: req.db) + .with(\.$subdepartments) + .with(\.$parent) + .with(\.$associates) + .with(\.$documents){ + doc in doc + .with(\.$doctype) + .with(\.$parent) + .with(\.$subsequent) + } + + if let x = req.parameters.get("x"){ + let decryptedString = try CustomCrypto.DecryptString(input: x) + let array = decryptedString.components(separatedBy: ":") + ///This call is the standard get by id call + if (array.count == 1){ + let id = Int(array[0])! + return query.filter(\.$id == id) + } + ///Optional else if if there are multiple parameters in the call + ///You must include an else for each call that has parameters + ///Need to check the endpoint to get the right filter statements + ///else if(x.count == 2){ + /// let username = x[0] + /// let password = x[1] + /// return query.filter(\.$username == username).filter(\.$password == password) + ///} + else{ + throw Abort(.badRequest) + } + + } + else{ + return query + } + } +} + diff --git a/Sources/App/Models/mdlDocType.swift b/Sources/App/Models/mdlDocType.swift new file mode 100644 index 0000000..6638487 --- /dev/null +++ b/Sources/App/Models/mdlDocType.swift @@ -0,0 +1,95 @@ +// +// mdlDocType.swift +// +// +// Created by Michiel Carman on 2/16/24. +// + + +import Fluent +import Vapor +import Foundation +import FluentKit + +final class mdlDocType: Model, Content { + static let schema = "docType" + + @ID(custom: "id", generatedBy: .database) var id: Int? + + @Field(key: "name") var name: String? + + @Children(for: \.$doctype) var documents: [mdlDocument] + + @Timestamp(key: "createDate", on: .create) var createdate: Date? + @Field(key: "createUserId") var createuserid: Int? + @Timestamp(key: "updateDate", on: .update) var updatedate: Date? + @Field(key: "updateUserId") var updateuserid: Int? + + init() { } + + init(id: Int? = nil, + name: String? = nil, + createuserid: Int? = nil, + updateuserid: Int? = nil + ) { + self.id = id + self.name = name + self.createuserid = createuserid + self.updateuserid = updateuserid + } +} +extension mdlDocType{ + struct Create: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("docType") + .field("id", .int, .identifier(auto: true)) + .field("name", .string) + .field("createDate", .datetime) + .field("createUserId", .int) + .field("updateDate", .datetime) + .field("updateUserId", .int) + .create() + } + + func revert(on database: Database) async throws { + try await database.schema("docType").delete() + } + } + public static func ObjQuery(req: Request) async throws -> QueryBuilder{ + + let query = mdlDocType.query(on: req.db) + .with(\.$documents){ + doc in doc + .with(\.$parent) + .with(\.$subsequent) + .with(\.$department) + } + + + if let x = req.parameters.get("x"){ + let decryptedString = try CustomCrypto.DecryptString(input: x) + let array = decryptedString.components(separatedBy: ":") + ///This call is the standard get by id call + if (array.count == 1){ + let id = Int(array[0])! + return query.filter(\.$id == id) + } + ///Optional else if if there are multiple parameters in the call + ///You must include an else for each call that has parameters + ///Need to check the endpoint to get the right filter statements + ///else if(x.count == 2){ + /// let username = x[0] + /// let password = x[1] + /// return query.filter(\.$username == username).filter(\.$password == password) + ///} + else{ + throw Abort(.badRequest) + } + + } + else{ + return query + } + } +} + diff --git a/Sources/App/Models/mdlDocument.swift b/Sources/App/Models/mdlDocument.swift new file mode 100644 index 0000000..7156094 --- /dev/null +++ b/Sources/App/Models/mdlDocument.swift @@ -0,0 +1,107 @@ +// +// mdlDocument.swift +// +// +// Created by Michiel Carman on 2/16/24. +// + + +import Fluent +import Vapor +import Foundation +import FluentKit + +final class mdlDocument: Model, Content { + static let schema = "document" + + @ID(custom: "id", generatedBy: .database) var id: Int? + + @Field(key: "name") var name: String? + @Field(key: "number") var number: String? + @Parent(key: "docTypeId") var doctype: mdlDocType + @Parent(key: "departmentId") var department: mdlDepartment + @OptionalParent(key: "parentId") var parent: mdlDocument? + @Children(for: \.$parent) var subsequent: [mdlDocument] + + @Timestamp(key: "createDate", on: .create) var createdate: Date? + @Field(key: "createUserId") var createuserid: Int? + @Timestamp(key: "updateDate", on: .update) var updatedate: Date? + @Field(key: "updateUserId") var updateuserid: Int? + + init() { } + + init(id: Int? = nil, + name: String? = nil, + number: String? = nil, + doctypeid: Int, + departmentid: Int, + parentid: Int? = nil, + createuserid: Int? = nil, + updateuserid: Int? = nil + ) { + self.id = id + self.name = name + self.number = number + self.$doctype.$id.value = doctypeid + self.$department.$id.value = departmentid + if(parentid != nil) { self.$parent.$id.value = parentid } + self.createuserid = createuserid + self.updateuserid = updateuserid + } +} +extension mdlDocument{ + struct Create: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("document") + .field("id", .int, .identifier(auto: true)) + .field("name", .string) + .field("number", .string) + .field("docTypeId", .int, .references("docType", "id")) + .field("departmentId", .int, .references("department", "id")) + .field("parentId", .int, .references("document", "id")) + .field("createDate", .datetime) + .field("createUserId", .int) + .field("updateDate", .datetime) + .field("updateUserId", .int) + .create() + } + + func revert(on database: Database) async throws { + try await database.schema("document").delete() + } + } + public static func ObjQuery(req: Request) async throws -> QueryBuilder{ + + let query = mdlDocument.query(on: req.db) + .with(\.$doctype) + .with(\.$parent) + .with(\.$subsequent) + .with(\.$department) + + if let x = req.parameters.get("x"){ + let decryptedString = try CustomCrypto.DecryptString(input: x) + let array = decryptedString.components(separatedBy: ":") + ///This call is the standard get by id call + if (array.count == 1){ + let id = Int(array[0])! + return query.filter(\.$id == id) + } + ///Optional else if if there are multiple parameters in the call + ///You must include an else for each call that has parameters + ///Need to check the endpoint to get the right filter statements + ///else if(x.count == 2){ + /// let username = x[0] + /// let password = x[1] + /// return query.filter(\.$username == username).filter(\.$password == password) + ///} + else{ + throw Abort(.badRequest) + } + + } + else{ + return query + } + } +} + diff --git a/Sources/App/Models/mdlXAssocDept.swift b/Sources/App/Models/mdlXAssocDept.swift new file mode 100644 index 0000000..4424955 --- /dev/null +++ b/Sources/App/Models/mdlXAssocDept.swift @@ -0,0 +1,92 @@ +// +// mdlXAssocDept.swift +// +// +// Created by Michiel Carman on 2/16/24. +// + + +import Fluent +import Vapor +import Foundation +import FluentKit + +final class mdlXAssocDept: Model, Content { + static let schema = "xAssocDept" + + @ID(custom: "id", generatedBy: .database) var id: Int? + + @Parent(key: "associateId") var associate: mdlAssociate + @Parent(key: "departmentId") var department: mdlDepartment + + @Timestamp(key: "createDate", on: .create) var createdate: Date? + @Field(key: "createUserId") var createuserid: Int? + @Timestamp(key: "updateDate", on: .update) var updatedate: Date? + @Field(key: "updateUserId") var updateuserid: Int? + + init() { } + + init(id: Int? = nil, + associateid: Int, + departmentid: Int, + createuserid: Int? = nil, + updateuserid: Int? = nil + ) { + self.id = id + self.$associate.$id.value = associateid + self.$department.$id.value = departmentid + self.createuserid = createuserid + self.updateuserid = updateuserid + } +} +extension mdlXAssocDept{ + struct Create: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("xAssocDept") + .field("id", .int, .identifier(auto: true)) + .field("associateId", .int, .references("associate", "id")) + .field("departmentId", .int, .references("department", "id")) + .field("createDate", .datetime) + .field("createUserId", .int) + .field("updateDate", .datetime) + .field("updateUserId", .int) + .create() + } + + func revert(on database: Database) async throws { + try await database.schema("xAssocDept").delete() + } + } + public static func ObjQuery(req: Request) async throws -> QueryBuilder{ + + let query = mdlXAssocDept.query(on: req.db) + .with(\.$associate) + .with(\.$department) + + if let x = req.parameters.get("x"){ + let decryptedString = try CustomCrypto.DecryptString(input: x) + let array = decryptedString.components(separatedBy: ":") + ///This call is the standard get by id call + if (array.count == 1){ + let id = Int(array[0])! + return query.filter(\.$id == id) + } + ///Optional else if if there are multiple parameters in the call + ///You must include an else for each call that has parameters + ///Need to check the endpoint to get the right filter statements + ///else if(x.count == 2){ + /// let username = x[0] + /// let password = x[1] + /// return query.filter(\.$username == username).filter(\.$password == password) + ///} + else{ + throw Abort(.badRequest) + } + + } + else{ + return query + } + } +} + diff --git a/Sources/App/Models/mdlXDocDept.swift b/Sources/App/Models/mdlXDocDept.swift new file mode 100644 index 0000000..7bccd53 --- /dev/null +++ b/Sources/App/Models/mdlXDocDept.swift @@ -0,0 +1,92 @@ +// +// mdlXDocDept.swift +// +// +// Created by Michiel Carman on 2/16/24. +// + + +import Fluent +import Vapor +import Foundation +import FluentKit + +final class mdlXDocDept: Model, Content { + static let schema = "xDocDept" + + @ID(custom: "id", generatedBy: .database) var id: Int? + + @Parent(key: "documentId") var document: mdlDocument + @Parent(key: "departmentId") var department: mdlDepartment + + @Timestamp(key: "createDate", on: .create) var createdate: Date? + @Field(key: "createUserId") var createuserid: Int? + @Timestamp(key: "updateDate", on: .update) var updatedate: Date? + @Field(key: "updateUserId") var updateuserid: Int? + + init() { } + + init(id: Int? = nil, + documentid: Int, + departmentid: Int, + createuserid: Int? = nil, + updateuserid: Int? = nil + ) { + self.id = id + self.$document.$id.value = documentid + self.$department.$id.value = departmentid + self.createuserid = createuserid + self.updateuserid = updateuserid + } +} +extension mdlXDocDept{ + struct Create: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("xDocDept") + .field("id", .int, .identifier(auto: true)) + .field("documentId", .int, .references("document", "id")) + .field("departmentId", .int, .references("department", "id")) + .field("createDate", .datetime) + .field("createUserId", .int) + .field("updateDate", .datetime) + .field("updateUserId", .int) + .create() + } + + func revert(on database: Database) async throws { + try await database.schema("xDocDept").delete() + } + } + public static func ObjQuery(req: Request) async throws -> QueryBuilder{ + + let query = mdlXDocDept.query(on: req.db) + .with(\.$document) + .with(\.$department) + + if let x = req.parameters.get("x"){ + let decryptedString = try CustomCrypto.DecryptString(input: x) + let array = decryptedString.components(separatedBy: ":") + ///This call is the standard get by id call + if (array.count == 1){ + let id = Int(array[0])! + return query.filter(\.$id == id) + } + ///Optional else if if there are multiple parameters in the call + ///You must include an else for each call that has parameters + ///Need to check the endpoint to get the right filter statements + ///else if(x.count == 2){ + /// let username = x[0] + /// let password = x[1] + /// return query.filter(\.$username == username).filter(\.$password == password) + ///} + else{ + throw Abort(.badRequest) + } + + } + else{ + return query + } + } +} + diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 3b43411..76cf967 100644 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -5,20 +5,30 @@ import Vapor // configures your application public func configure(_ app: Application) async throws { - // uncomment to serve files from /Public folder - // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) - + app.middleware.use(CORSMiddleware()) + let corsConfiguration = CORSMiddleware.Configuration( + allowedOrigin: .all, + allowedMethods: [.GET, .POST, .PUT, .OPTIONS, .DELETE, .PATCH], + allowedHeaders: [.accept, .authorization, .contentType, .origin, .xRequestedWith, .userAgent, .accessControlAllowOrigin] + ) + let cors = CORSMiddleware(configuration: corsConfiguration) + app.middleware.use(cors, at: .beginning) + + app.http.server.configuration.port = 3004 app.databases.use(DatabaseConfigurationFactory.postgres(configuration: .init( hostname: Environment.get("DATABASE_HOST") ?? "localhost", port: Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) ?? SQLPostgresConfiguration.ianaPortNumber, - username: Environment.get("DATABASE_USERNAME") ?? "vapor_username", - password: Environment.get("DATABASE_PASSWORD") ?? "vapor_password", - database: Environment.get("DATABASE_NAME") ?? "vapor_database", - tls: .prefer(try .init(configuration: .clientDefault))) + username: Environment.get("DATABASE_USERNAME") ?? "mcarman", + password: Environment.get("DATABASE_PASSWORD") ?? "@ng31F@rm0823262", + database: Environment.get("DATABASE_NAME") ?? "trainingdb", + tls: .prefer(try .init(configuration: .clientDefault))) ), as: .psql) - app.migrations.add(CreateTodo()) + app.logger.logLevel = .debug + + try await doMigrations(app) + // register routes try routes(app) } diff --git a/Sources/App/routes.swift b/Sources/App/routes.swift index e06b66c..b9a5c5a 100644 --- a/Sources/App/routes.swift +++ b/Sources/App/routes.swift @@ -1,14 +1,14 @@ +import Foundation import Fluent import Vapor +import Crypto func routes(_ app: Application) throws { - app.get { req async in - "It works!" + app.routes.caseInsensitive = true + app.routes.defaultMaxBodySize = "64mb"; + let baseApp = app.grouped("api").grouped("v1.0") + + baseApp.get { req async in + "Training Services Version 1.0" } - - app.get("hello") { req async -> String in - "Hello, world!" - } - - try app.register(collection: TodoController()) }