Vapor providers are a convenient way to add functionality to your Vapor projects.
For a full list of providers, check out the vapor-service tag on GitHub.
+
+
diff --git a/build/3.0/search/search_index.json b/build/3.0/search/search_index.json
index f5a27c41..90c5cdbc 100644
--- a/build/3.0/search/search_index.json
+++ b/build/3.0/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Vapor Documentation This is the documentation for Vapor, a Web Framework for Swift that works on macOS and Ubuntu, and all of the packages that Vapor offers. Vapor is the most used web framework for Swift. It provides a beautifully expressive and easy to use foundation for your next website or API. Getting Started If this is your first time using Vapor, head to the Install macOS section to install Swift and Vapor. Once you have Vapor installed, check out Getting Started Hello, world to create your first Vapor app! Like Vapor? Our small team works hard to make Vapor awesome (and free). Support the framework by starring Vapor on GitHub or donating $1 monthly it helps us a lot. Thanks! Other Sources Here are some other great places to find information about Vapor. name description link Vapor Discord Chat with ~5,000 Vapor developers. visit API docs Auto-generated documentation from code comments. visit Stack Overflow Ask and answer questions with the vapor tag. visit Source Code Learn how Vapor works under the hood. visit GitHub Issues Report bugs or request features on GitHub. visit Service Providers Vapor providers are a convenient way to add functionality to your Vapor projects. For a full list of providers, check out the vapor-service tag on GitHub. Authors Tanner Nelson , Logan Wright , Joannis Orlandos , and the hundreds of members of Vapor.","title":"Overview"},{"location":"#vapor-documentation","text":"This is the documentation for Vapor, a Web Framework for Swift that works on macOS and Ubuntu, and all of the packages that Vapor offers. Vapor is the most used web framework for Swift. It provides a beautifully expressive and easy to use foundation for your next website or API.","title":"Vapor Documentation"},{"location":"#getting-started","text":"If this is your first time using Vapor, head to the Install macOS section to install Swift and Vapor. Once you have Vapor installed, check out Getting Started Hello, world to create your first Vapor app!","title":"Getting Started"},{"location":"#like-vapor","text":"Our small team works hard to make Vapor awesome (and free). Support the framework by starring Vapor on GitHub or donating $1 monthly it helps us a lot. Thanks!","title":"Like Vapor?"},{"location":"#other-sources","text":"Here are some other great places to find information about Vapor. name description link Vapor Discord Chat with ~5,000 Vapor developers. visit API docs Auto-generated documentation from code comments. visit Stack Overflow Ask and answer questions with the vapor tag. visit Source Code Learn how Vapor works under the hood. visit GitHub Issues Report bugs or request features on GitHub. visit","title":"Other Sources"},{"location":"#service-providers","text":"Vapor providers are a convenient way to add functionality to your Vapor projects. For a full list of providers, check out the vapor-service tag on GitHub.","title":"Service Providers"},{"location":"#authors","text":"Tanner Nelson , Logan Wright , Joannis Orlandos , and the hundreds of members of Vapor.","title":"Authors"},{"location":"async/getting-started/","text":"Getting Started with Async The Async module is provided as a part of Vapor Core ( vapor/core ). It is a collection of convenience APIs (mostly extensions) built on top of SwiftNIO . Tip You can read more about SwiftNIO's async types ( Future , Promise , EventLoop , and more) in its GitHub README or its API Docs . Usage This package is included with Vapor and exported by default. You will have access to all Async APIs when you import Vapor . import Vapor // implies `import Async` Standalone The Async module, part of the larger Vapor Core package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/core.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Async , ... ]) ] ) Use import Async to access the APIs. Overview Continue to Async Overview for an overview of Async's features.","title":"Getting Started"},{"location":"async/getting-started/#getting-started-with-async","text":"The Async module is provided as a part of Vapor Core ( vapor/core ). It is a collection of convenience APIs (mostly extensions) built on top of SwiftNIO . Tip You can read more about SwiftNIO's async types ( Future , Promise , EventLoop , and more) in its GitHub README or its API Docs .","title":"Getting Started with Async"},{"location":"async/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Async APIs when you import Vapor . import Vapor // implies `import Async`","title":"Usage"},{"location":"async/getting-started/#standalone","text":"The Async module, part of the larger Vapor Core package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/core.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Async , ... ]) ] ) Use import Async to access the APIs.","title":"Standalone"},{"location":"async/getting-started/#overview","text":"Continue to Async Overview for an overview of Async's features.","title":"Overview"},{"location":"async/overview/","text":"Async Overview You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. Promises and futures are related, but distinct, types. Promises are used to create futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises. type description mutability methods Future Reference to an object that may not be available yet. read-only .map(to:_:) .flatMap(to:_:) do(_:) catch(_:) Promise A promise to provide some object asynchronously. read/write succeed(_:) fail(_:) Futures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful. Transforming Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures. method signature description map to: U.Type, _: (T) - U Maps a future value to a different value. flatMap to: U.Type, _: (T) - Future U Maps a future value to different future value. transform to: U Maps a future to an already available value. If you look at the method signatures for map and flatMap on Optional T and Array T , you will see that they are very similar to the methods available on Future T . Map The .map(to:_:) method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int Flat Map The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your generic futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes! Transform The .transform(_:) method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of Future Void where the actual value of the future is not important. Tip Future Void , sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation. /// Assume we get a void future back from some API let userDidSave : Future Void = ... /// Transform the void future to an HTTP status let futureStatus = userDidSave . transform ( to : HTTPStatus . ok ) print ( futureStatus ) // Future HTTPStatus Even though we have supplied an already-available value to transform , this is still a transformation . The future will not complete until all previous futures have completed (or failed). Chaining The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown. Future Let's take a look at some other, less commonly used methods on Future T . Do / Catch Similar to Swift's do / catch syntax, futures have a do and catch method for awaiting the future's result. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . do { string in print ( string ) // The actual String }. catch { error in print ( error ) // A Swift Error } Info .do and .catch work together. If you forget .catch , the compiler will warn you about an unused result. Don't forget to handle the error case! Always You can use always to add a callback that will be executed whether the future succeeds or fails. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . always { print ( The future is complete! ) } Note You can add as many callbacks to a future as you want. Wait You can use .wait() to synchronously wait for the future to be completed. Since a future may fail, this call is throwing. /// Assume we get a future string back from some API let futureString : Future String = ... /// Block until the string is ready let string = try futureString . wait () print ( string ) /// String Warning Do not use this method in route closures or controllers. Read the section about Blocking for more information. Promise Most of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own. To create a promise, you will need access to an EventLoop . All containers in Vapor have an eventLoop property that you can use. Most commonly, this will be the current Request . /// Create a new promise for some string let promiseString = req . eventLoop . newPromise ( String . self ) print ( promiseString ) // Promise String print ( promiseString . futureResult ) // Future String /// Completes the associated future promiseString . succeed ( result : Hello ) /// Fails the associated future promiseString . fail ( error : ...) Info A promise can only be completed once. Any subsequent completions will be ignored. Thread Safety Promises can be completed ( succeed(result:) / fail(error:) ) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution. Event Loop When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading. Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed. Worker Things that have access to an event loop are called Workers . Every container in Vapor is a worker. The most common containers you will interact with in Vapor are: Application Request Response You can use the .eventLoop property on these containers to gain access to the event loop. print ( app . eventLoop ) // EventLoop There are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like on: Worker . If you are in a route closure or a controller, pass the current Request or Response . If you need a worker while booting your app, use the Application . Blocking An absolutely critical rule is the following: Danger Never make blocking calls directly on an event loop. An example of a blocking call would be something like libc.sleep(_:) . router . get ( hello ) { req in /// Puts the event loop s thread to sleep. sleep ( 5 ) /// Returns a simple string once the thread re-awakens. return Hello, world! } sleep(_:) is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do sleep(5) on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds. Make sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way. router . get ( hello ) { req in /// Create a new void promise let promise = req . eventLoop . newPromise ( Void . self ) /// Dispatch some work to happen on a background thread DispatchQueue . global () { /// Puts the background thread to sleep /// This will not affect any of the event loops sleep ( 5 ) /// When the blocking work has completed, /// complete the promise and its associated future. promise . succeed () } /// Wait for the future to be completed, /// then transform the result to a simple String return promise . futureResult . transform ( to : Hello, world! ) } Not all blocking calls will be as obvious as sleep(_:) . If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking. Info If doing blocking work is a central part of your application, you should consider using a BlockingIOThreadPool to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.","title":"Overview"},{"location":"async/overview/#async-overview","text":"You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. Promises and futures are related, but distinct, types. Promises are used to create futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises. type description mutability methods Future Reference to an object that may not be available yet. read-only .map(to:_:) .flatMap(to:_:) do(_:) catch(_:) Promise A promise to provide some object asynchronously. read/write succeed(_:) fail(_:) Futures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful.","title":"Async Overview"},{"location":"async/overview/#transforming","text":"Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures. method signature description map to: U.Type, _: (T) - U Maps a future value to a different value. flatMap to: U.Type, _: (T) - Future U Maps a future value to different future value. transform to: U Maps a future to an already available value. If you look at the method signatures for map and flatMap on Optional T and Array T , you will see that they are very similar to the methods available on Future T .","title":"Transforming"},{"location":"async/overview/#map","text":"The .map(to:_:) method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int","title":"Map"},{"location":"async/overview/#flat-map","text":"The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your generic futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes!","title":"Flat Map"},{"location":"async/overview/#transform","text":"The .transform(_:) method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of Future Void where the actual value of the future is not important. Tip Future Void , sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation. /// Assume we get a void future back from some API let userDidSave : Future Void = ... /// Transform the void future to an HTTP status let futureStatus = userDidSave . transform ( to : HTTPStatus . ok ) print ( futureStatus ) // Future HTTPStatus Even though we have supplied an already-available value to transform , this is still a transformation . The future will not complete until all previous futures have completed (or failed).","title":"Transform"},{"location":"async/overview/#chaining","text":"The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown.","title":"Chaining"},{"location":"async/overview/#future","text":"Let's take a look at some other, less commonly used methods on Future T .","title":"Future"},{"location":"async/overview/#do-catch","text":"Similar to Swift's do / catch syntax, futures have a do and catch method for awaiting the future's result. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . do { string in print ( string ) // The actual String }. catch { error in print ( error ) // A Swift Error } Info .do and .catch work together. If you forget .catch , the compiler will warn you about an unused result. Don't forget to handle the error case!","title":"Do / Catch"},{"location":"async/overview/#always","text":"You can use always to add a callback that will be executed whether the future succeeds or fails. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . always { print ( The future is complete! ) } Note You can add as many callbacks to a future as you want.","title":"Always"},{"location":"async/overview/#wait","text":"You can use .wait() to synchronously wait for the future to be completed. Since a future may fail, this call is throwing. /// Assume we get a future string back from some API let futureString : Future String = ... /// Block until the string is ready let string = try futureString . wait () print ( string ) /// String Warning Do not use this method in route closures or controllers. Read the section about Blocking for more information.","title":"Wait"},{"location":"async/overview/#promise","text":"Most of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own. To create a promise, you will need access to an EventLoop . All containers in Vapor have an eventLoop property that you can use. Most commonly, this will be the current Request . /// Create a new promise for some string let promiseString = req . eventLoop . newPromise ( String . self ) print ( promiseString ) // Promise String print ( promiseString . futureResult ) // Future String /// Completes the associated future promiseString . succeed ( result : Hello ) /// Fails the associated future promiseString . fail ( error : ...) Info A promise can only be completed once. Any subsequent completions will be ignored.","title":"Promise"},{"location":"async/overview/#thread-safety","text":"Promises can be completed ( succeed(result:) / fail(error:) ) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution.","title":"Thread Safety"},{"location":"async/overview/#event-loop","text":"When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading. Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed.","title":"Event Loop"},{"location":"async/overview/#worker","text":"Things that have access to an event loop are called Workers . Every container in Vapor is a worker. The most common containers you will interact with in Vapor are: Application Request Response You can use the .eventLoop property on these containers to gain access to the event loop. print ( app . eventLoop ) // EventLoop There are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like on: Worker . If you are in a route closure or a controller, pass the current Request or Response . If you need a worker while booting your app, use the Application .","title":"Worker"},{"location":"async/overview/#blocking","text":"An absolutely critical rule is the following: Danger Never make blocking calls directly on an event loop. An example of a blocking call would be something like libc.sleep(_:) . router . get ( hello ) { req in /// Puts the event loop s thread to sleep. sleep ( 5 ) /// Returns a simple string once the thread re-awakens. return Hello, world! } sleep(_:) is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do sleep(5) on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds. Make sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way. router . get ( hello ) { req in /// Create a new void promise let promise = req . eventLoop . newPromise ( Void . self ) /// Dispatch some work to happen on a background thread DispatchQueue . global () { /// Puts the background thread to sleep /// This will not affect any of the event loops sleep ( 5 ) /// When the blocking work has completed, /// complete the promise and its associated future. promise . succeed () } /// Wait for the future to be completed, /// then transform the result to a simple String return promise . futureResult . transform ( to : Hello, world! ) } Not all blocking calls will be as obvious as sleep(_:) . If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking. Info If doing blocking work is a central part of your application, you should consider using a BlockingIOThreadPool to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.","title":"Blocking"},{"location":"auth/api/","text":"API Authentication This guide will introduce you to stateless authentication a method of authentication commonly used for protecting API endpoints. Concept In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource This package allows you to implement stateless authorization using the following tools: \"Authorization\" header : Used to send credentials in an HTTP request. Middleware : Detects credentials in request and fetches authenticated user. Model : Represents an authenticated user and its identifying information. Authorization Header This packages makes use of two common authorization header formats: basic and bearer. Basic Basic authorization contains a username and password. They are joined together by a : and then base64 encoded. A basic authorization header containing the username Alladin and password OpenSesame would look like this: Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l Although basic authorization can be used to authenticate each request to your server, most web applications usually create an ephemeral token for this purpose instead. Bearer Bearer authorization simply contains a token. A bearer authorization header containing the token cn389ncoiwuencr would look like this: Authorization: Bearer cn389ncoiwuencr The bearer authorization header is very common in APIs since it can be sent easily with each request and contain an ephemeral token. Middleware The usage of Middleware is critical to this package. If you are not familiar with how Middleware works in Vapor, feel free to brush up by reading Vapor Middleware . Authentication middleware is responsible for reading the credentials from the request and fetching the identifier user. This usually means checking the \"Authorization\" header, parsing the credentials, and doing a database lookup. For each model / authentication method you use, you will add one middleware to your application. All of this package's middlewares are composable, meaning you can add multiple middlewares to one route and they will work together. If one middleware fails to authorize a user, it will simply forward the request for the next middleware to try. If you would like to ensure that a certain model's authentication has succeeded before running your route, you must add an instance of GuardAuthenticationMiddleware . Model Fluent models are what the middlewares authenticate. Learn more about models by reading Fluent Models . If authentication is succesful, the middleware will have fetched your model from the database and stored it on the request. This means you can access an authenticated model synchronously in your route. In your route closure, you use the following methods to check for authentication: authenticated(_:) : Returns type if authenticated, nil if not. isAuthenticated(_:) : Returns true if supplied type is authenticated. requireAuthenticated(_:) : Returns type if authenticated, throws if not. Typical usage looks like the following: // use middleware to protect a group let protectedGroup = router . group (...) // add a protected route protectedGroup . get ( test ) { req in // require that a User has been authed by middleware or throw let user = try req . requireAuthenticated ( User . self ) // say hello to the user return Hello, \\( user . name ) . } Methods This package supports two basic types of stateless authentication. Token : Uses the bearer authorization header. Password : Uses the basic authorization header. For each authentication type, there is a separate middleware and model protocol. Password Authentication Password authentication uses the basic authorization header (username and password) to verify a user. With this method, the username and password must be sent with each request to a protected endpoint. To use password authentication, you will first need to conform your Fluent model to PasswordAuthenticatable . extension User : PasswordAuthenticatable { /// See `PasswordAuthenticatable`. static var usernameKey : WritableKeyPath User , String { return \\ . email } /// See `PasswordAuthenticatable`. static var passwordKey : WritableKeyPath User , String { return \\ . passwordHash } } Note that the passwordKey should point to the hashed password. Never store passwords in plaintext. Once you have created an authenticatable model, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let password = User . basicAuthMiddleware ( using : BCryptDigest ()) // Create a route closure wrapped by this middleware router . grouped ( password ). get ( hello ) { req in /// } Here we are using BCryptDigest as the PasswordVerifier since we are assuming the user's password is stored as a BCrypt hash. Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required. Token Authentication Token authentication uses the bearer authorization header (token) to lookup a token and its related user. With this method, the token must be sent with each request to a protected endpoint. Unlike password authentication, token authentication relies on two Fluent models. One for the token and one for the user. The token model should be a child of the user model. Here is an example of a very basic User and associated UserToken . struct User : Model { var id : Int ? var name : String var email : String var passwordHash : String var tokens : Children User , UserToken { return children ( \\ . userID ) } } struct UserToken : Model { var id : Int ? var string : String var userID : User . ID var user : Parent UserToken , User { return parent ( \\ . userID ) } } The first step to using token authentication is to conform your user and token models to their respective Authenticatable protocols. extension UserToken : Token { /// See `Token`. typealias UserType = User /// See `Token`. static var tokenKey : WritableKeyPath UserToken , String { return \\ . string } /// See `Token`. static var userIDKey : WritableKeyPath UserToken , User . ID { return \\ . userID } } Once the token is conformed to Token , setting up the user model is easy. extension User : TokenAuthenticatable { /// See `TokenAuthenticatable`. typealias TokenType = UserToken } Once you have conformed your models, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let token = User . tokenAuthMiddleware () // Create a route closure wrapped by this middleware router . grouped ( token ). get ( hello ) { // } Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required.","title":"Stateless (API)"},{"location":"auth/api/#api-authentication","text":"This guide will introduce you to stateless authentication a method of authentication commonly used for protecting API endpoints.","title":"API Authentication"},{"location":"auth/api/#concept","text":"In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource This package allows you to implement stateless authorization using the following tools: \"Authorization\" header : Used to send credentials in an HTTP request. Middleware : Detects credentials in request and fetches authenticated user. Model : Represents an authenticated user and its identifying information.","title":"Concept"},{"location":"auth/api/#authorization-header","text":"This packages makes use of two common authorization header formats: basic and bearer.","title":"Authorization Header"},{"location":"auth/api/#basic","text":"Basic authorization contains a username and password. They are joined together by a : and then base64 encoded. A basic authorization header containing the username Alladin and password OpenSesame would look like this: Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l Although basic authorization can be used to authenticate each request to your server, most web applications usually create an ephemeral token for this purpose instead.","title":"Basic"},{"location":"auth/api/#bearer","text":"Bearer authorization simply contains a token. A bearer authorization header containing the token cn389ncoiwuencr would look like this: Authorization: Bearer cn389ncoiwuencr The bearer authorization header is very common in APIs since it can be sent easily with each request and contain an ephemeral token.","title":"Bearer"},{"location":"auth/api/#middleware","text":"The usage of Middleware is critical to this package. If you are not familiar with how Middleware works in Vapor, feel free to brush up by reading Vapor Middleware . Authentication middleware is responsible for reading the credentials from the request and fetching the identifier user. This usually means checking the \"Authorization\" header, parsing the credentials, and doing a database lookup. For each model / authentication method you use, you will add one middleware to your application. All of this package's middlewares are composable, meaning you can add multiple middlewares to one route and they will work together. If one middleware fails to authorize a user, it will simply forward the request for the next middleware to try. If you would like to ensure that a certain model's authentication has succeeded before running your route, you must add an instance of GuardAuthenticationMiddleware .","title":"Middleware"},{"location":"auth/api/#model","text":"Fluent models are what the middlewares authenticate. Learn more about models by reading Fluent Models . If authentication is succesful, the middleware will have fetched your model from the database and stored it on the request. This means you can access an authenticated model synchronously in your route. In your route closure, you use the following methods to check for authentication: authenticated(_:) : Returns type if authenticated, nil if not. isAuthenticated(_:) : Returns true if supplied type is authenticated. requireAuthenticated(_:) : Returns type if authenticated, throws if not. Typical usage looks like the following: // use middleware to protect a group let protectedGroup = router . group (...) // add a protected route protectedGroup . get ( test ) { req in // require that a User has been authed by middleware or throw let user = try req . requireAuthenticated ( User . self ) // say hello to the user return Hello, \\( user . name ) . }","title":"Model"},{"location":"auth/api/#methods","text":"This package supports two basic types of stateless authentication. Token : Uses the bearer authorization header. Password : Uses the basic authorization header. For each authentication type, there is a separate middleware and model protocol.","title":"Methods"},{"location":"auth/api/#password-authentication","text":"Password authentication uses the basic authorization header (username and password) to verify a user. With this method, the username and password must be sent with each request to a protected endpoint. To use password authentication, you will first need to conform your Fluent model to PasswordAuthenticatable . extension User : PasswordAuthenticatable { /// See `PasswordAuthenticatable`. static var usernameKey : WritableKeyPath User , String { return \\ . email } /// See `PasswordAuthenticatable`. static var passwordKey : WritableKeyPath User , String { return \\ . passwordHash } } Note that the passwordKey should point to the hashed password. Never store passwords in plaintext. Once you have created an authenticatable model, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let password = User . basicAuthMiddleware ( using : BCryptDigest ()) // Create a route closure wrapped by this middleware router . grouped ( password ). get ( hello ) { req in /// } Here we are using BCryptDigest as the PasswordVerifier since we are assuming the user's password is stored as a BCrypt hash. Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required.","title":"Password Authentication"},{"location":"auth/api/#token-authentication","text":"Token authentication uses the bearer authorization header (token) to lookup a token and its related user. With this method, the token must be sent with each request to a protected endpoint. Unlike password authentication, token authentication relies on two Fluent models. One for the token and one for the user. The token model should be a child of the user model. Here is an example of a very basic User and associated UserToken . struct User : Model { var id : Int ? var name : String var email : String var passwordHash : String var tokens : Children User , UserToken { return children ( \\ . userID ) } } struct UserToken : Model { var id : Int ? var string : String var userID : User . ID var user : Parent UserToken , User { return parent ( \\ . userID ) } } The first step to using token authentication is to conform your user and token models to their respective Authenticatable protocols. extension UserToken : Token { /// See `Token`. typealias UserType = User /// See `Token`. static var tokenKey : WritableKeyPath UserToken , String { return \\ . string } /// See `Token`. static var userIDKey : WritableKeyPath UserToken , User . ID { return \\ . userID } } Once the token is conformed to Token , setting up the user model is easy. extension User : TokenAuthenticatable { /// See `TokenAuthenticatable`. typealias TokenType = UserToken } Once you have conformed your models, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let token = User . tokenAuthMiddleware () // Create a route closure wrapped by this middleware router . grouped ( token ). get ( hello ) { // } Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required.","title":"Token Authentication"},{"location":"auth/getting-started/","text":"Getting Started with Auth Auth ( vapor/auth ) is a framework for adding authentication to your application. It builds on top of Fluent by using models as the basis of authentication. Tip There is a Vapor API template with Auth pre-configured available. See Getting Started Toolbox Templates . Let's take a look at how you can get started using Auth. Package The first step to using Auth is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc64 Authentication and Authorization framework for Fluent. . package ( url : https://github.com/vapor/auth.git , from : 2.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Authentication , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Auth currently provides one module Authentication . In the future, there will be a separate module named Authorization for performing more advanced auth. Provider Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Authentication // register Authentication provider try services . register ( AuthenticationProvider ()) That's it for basic setup. The next step is to create an authenticatable model.","title":"Getting Started"},{"location":"auth/getting-started/#getting-started-with-auth","text":"Auth ( vapor/auth ) is a framework for adding authentication to your application. It builds on top of Fluent by using models as the basis of authentication. Tip There is a Vapor API template with Auth pre-configured available. See Getting Started Toolbox Templates . Let's take a look at how you can get started using Auth.","title":"Getting Started with Auth"},{"location":"auth/getting-started/#package","text":"The first step to using Auth is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc64 Authentication and Authorization framework for Fluent. . package ( url : https://github.com/vapor/auth.git , from : 2.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Authentication , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Auth currently provides one module Authentication . In the future, there will be a separate module named Authorization for performing more advanced auth.","title":"Package"},{"location":"auth/getting-started/#provider","text":"Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Authentication // register Authentication provider try services . register ( AuthenticationProvider ()) That's it for basic setup. The next step is to create an authenticatable model.","title":"Provider"},{"location":"auth/web/","text":"Web Authentication This guide will introduce you to session-based authentication a method of authentication commonly used for protecting web (front-end) pages. Concept In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource Session-based authentication uses cookies to re-authenticate users with each request to your website. It performs this logic via a middleware that you add to your application or specific routes. You are responsible for initially authenticating the user to your application (either manually or by using methods from the Stateless (API) section). Once you have authenticated the user once, the middleware will use cookies to re-authenticate the user on subsequent requests automatically. Example Let's take a look at a simple session-based authentication example. Pre-requisites In order to do session-based authentication, you must have a way to initially authenticate your user. In other words, you need a method for logging them in. The Stateless (API) section covers some of these methods, but it's entirely up to you. You will also need to have sessions configured for your application. You can learn more about this in Vapor Sessions . Usually this will require adding the SessionsMiddleware and choosing a KeyedCache . config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) var middlewares = MiddlewareConfig () middlewares . use ( SessionsMiddleware . self ) // ... services . register ( middlewares ) Model Once you are ready to enable session-based authentication, the first step is to conform your user model to SessionAuthenticatable . extension User : SessionAuthenticatable { } The conformance is empty since all of the required methods have default implementations. Middleware Once your model is conformed, you can use it to create an AuthenticationSessionsMiddleware . // create auth sessions middleware for user let session = User . authSessionsMiddleware () // create a route group wrapped by this middleware let auth = router . grouped ( session ) // create new route in this route group auth . get ( hello ) { req - String in // } Create a route group wrapped by this middleware using the route grouping methods. Any routes you want to support session-based authentication should use this route group. You can also apply this middleware globally to your application if you'd like. Route Inside of any route closure wrapped by the session auth middleware, we can access our authenticated model using the authenticated(_:) methods. let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) ! Here we are using the method prefixed with require to throw an error if the user was not succesfully authenticated. If you visit this route now, you should see a message saying no user has been authenticated. Let's resolve this by creating a way for our user to login! Note Use GuardAuthenticationMiddleware to protect routes that do not call requireAuthenticated(_:) or otherwise require authentication. Login For the sake of this example, we will just log in a pre-defined user with a fixed ID. auth . get ( login ) { req - Future String in return User . find ( 1 , on : req ). map { user in guard let user = user else { throw Abort (. badRequest ) } try req . authenticate ( user ) return Logged in } } Remember that this login route must go through the AuthenticationSessionsMiddleware . The middleware is what will detect that we have authenticated a user and later restore the authentication automatically. Upon visiting /hello , you should recieve an error message stating that you are not logged in. If you then visit /login first, followed by /hello you should see that you are now successfully logged in! If you open the inspector, you should notice a new cookie named \"vapor-session\" has been added to your browser.","title":"Sessions (Web)"},{"location":"auth/web/#web-authentication","text":"This guide will introduce you to session-based authentication a method of authentication commonly used for protecting web (front-end) pages.","title":"Web Authentication"},{"location":"auth/web/#concept","text":"In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource Session-based authentication uses cookies to re-authenticate users with each request to your website. It performs this logic via a middleware that you add to your application or specific routes. You are responsible for initially authenticating the user to your application (either manually or by using methods from the Stateless (API) section). Once you have authenticated the user once, the middleware will use cookies to re-authenticate the user on subsequent requests automatically.","title":"Concept"},{"location":"auth/web/#example","text":"Let's take a look at a simple session-based authentication example.","title":"Example"},{"location":"auth/web/#pre-requisites","text":"In order to do session-based authentication, you must have a way to initially authenticate your user. In other words, you need a method for logging them in. The Stateless (API) section covers some of these methods, but it's entirely up to you. You will also need to have sessions configured for your application. You can learn more about this in Vapor Sessions . Usually this will require adding the SessionsMiddleware and choosing a KeyedCache . config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) var middlewares = MiddlewareConfig () middlewares . use ( SessionsMiddleware . self ) // ... services . register ( middlewares )","title":"Pre-requisites"},{"location":"auth/web/#model","text":"Once you are ready to enable session-based authentication, the first step is to conform your user model to SessionAuthenticatable . extension User : SessionAuthenticatable { } The conformance is empty since all of the required methods have default implementations.","title":"Model"},{"location":"auth/web/#middleware","text":"Once your model is conformed, you can use it to create an AuthenticationSessionsMiddleware . // create auth sessions middleware for user let session = User . authSessionsMiddleware () // create a route group wrapped by this middleware let auth = router . grouped ( session ) // create new route in this route group auth . get ( hello ) { req - String in // } Create a route group wrapped by this middleware using the route grouping methods. Any routes you want to support session-based authentication should use this route group. You can also apply this middleware globally to your application if you'd like.","title":"Middleware"},{"location":"auth/web/#route","text":"Inside of any route closure wrapped by the session auth middleware, we can access our authenticated model using the authenticated(_:) methods. let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) ! Here we are using the method prefixed with require to throw an error if the user was not succesfully authenticated. If you visit this route now, you should see a message saying no user has been authenticated. Let's resolve this by creating a way for our user to login! Note Use GuardAuthenticationMiddleware to protect routes that do not call requireAuthenticated(_:) or otherwise require authentication.","title":"Route"},{"location":"auth/web/#login","text":"For the sake of this example, we will just log in a pre-defined user with a fixed ID. auth . get ( login ) { req - Future String in return User . find ( 1 , on : req ). map { user in guard let user = user else { throw Abort (. badRequest ) } try req . authenticate ( user ) return Logged in } } Remember that this login route must go through the AuthenticationSessionsMiddleware . The middleware is what will detect that we have authenticated a user and later restore the authentication automatically. Upon visiting /hello , you should recieve an error message stating that you are not logged in. If you then visit /login first, followed by /hello you should see that you are now successfully logged in! If you open the inspector, you should notice a new cookie named \"vapor-session\" has been added to your browser.","title":"Login"},{"location":"command/getting-started/","text":"Getting Started with Command The Command module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for creating command-line interfaces (CLIs). It's what powers the Vapor Toolbox . Tip For an in-depth look at all of Command's APIs, check out the Command API docs . Usage This package is included with Vapor and exported by default. You will have access to all Command APIs when you import Vapor . import Vapor // implies import Command Standalone The Command module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Command , ... ]) ] ) Use import Command to access the APIs. Overview Continue to Command \u2192 Overview for an overview of Command's features.","title":"Getting Started"},{"location":"command/getting-started/#getting-started-with-command","text":"The Command module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for creating command-line interfaces (CLIs). It's what powers the Vapor Toolbox . Tip For an in-depth look at all of Command's APIs, check out the Command API docs .","title":"Getting Started with Command"},{"location":"command/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Command APIs when you import Vapor . import Vapor // implies import Command","title":"Usage"},{"location":"command/getting-started/#standalone","text":"The Command module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Command , ... ]) ] ) Use import Command to access the APIs.","title":"Standalone"},{"location":"command/getting-started/#overview","text":"Continue to Command \u2192 Overview for an overview of Command's features.","title":"Overview"},{"location":"command/overview/","text":"Command Overview This guide will introduce you to the Command module by showing you how to create your own CLI. For this example, we will implement cowsay , a command that prints an ASCII picture of a cow with a message. Tip You can install the real cowsay program using brew install cowsay . $ cowsay Hello ----- Hello ----- \\ ^__^ \\ ( oo \\_ ______ ( __ ) \\ ) \\/\\ || ----w | || || Command The first step is to create a type that conforms to Command . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... } Now let's implement the required methods. Arguments Commands can have zero or more CommandArgument s. These arguments will be required for the command to run. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { /// See `Command` var arguments : [ CommandArgument ] { return [. argument ( name : message )] } ... } Here we are defining one argument, the message that the cow will say. This is required to run the cowsay command. Options Commands can have zero or more CommandOption s. These options are not required for the command to run and can be passed using -- or - syntax. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var options : [ CommandOption ] { return [ . value ( name : eyes , short : e , default : oo , help : [ Change cow s eyes ]), . value ( name : tongue , short : t , default : , help : [ Change cow s tongue ]), ] } ... } Here we are defining two options, eyes and tongue . These will let the user optionally change how the cow looks. Help Next we can define an optional help message to display when the user passes --help . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var help : [ String ] { return [ Generates ASCII picture of a cow with a message. ] } ... } Let's take a look at how this will look once our command is complete: Usage: executable cowsay message [ --eyes,-e ] [ --tongue,-t ] Generates ASCII picture of a cow with a message. Arguments: message n/a Options: eyes Change cow s eyes tongue Change cow s tongue Run Finally, we need to write our implementation: /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command`. func run ( using context : CommandContext ) throws - Future Void { let message = try context . argument ( message ) /// We can use requireOption here since both options have default values let eyes = try context . requireOption ( eyes ) let tongue = try context . requireOption ( tongue ) let padding = String ( repeating : - , count : message . count ) let text : String = \\( padding ) \\( message ) \\( padding ) \\\\ ^__^ \\\\ ( \\( eyes ) \\\\ _______ (__) \\\\ ) \\\\ / \\\\ \\( tongue ) ||----w | || || context . console . print ( text ) return . done ( on : context . container ) } } The CommandContext gives you access to everything you will need, including a Container . Now that we have a complete Command , the next step is to configure it. Config Use the CommandConfig struct to register commands to your container. This is usually done in configure.swift /// Create a `CommandConfig` with default commands. var commandConfig = CommandConfig . default () /// Add the `CowsayCommand`. commandConfig . use ( CowsayCommand (), as : cowsay ) /// Register this `CommandConfig` to services. services . register ( commandConfig ) Check that your command was properly configured using --help . swift run Run cowsay -- help That's it! $ swift run Run cowsay Good job ! - e ^^ - t U --------- Good job ! --------- \\ ^ __ ^ \\ ( ^^ \\ _______ ( __ ) \\ ) \\ / \\ U ||---- w | || ||","title":"Overview"},{"location":"command/overview/#command-overview","text":"This guide will introduce you to the Command module by showing you how to create your own CLI. For this example, we will implement cowsay , a command that prints an ASCII picture of a cow with a message. Tip You can install the real cowsay program using brew install cowsay . $ cowsay Hello ----- Hello ----- \\ ^__^ \\ ( oo \\_ ______ ( __ ) \\ ) \\/\\ || ----w | || ||","title":"Command Overview"},{"location":"command/overview/#command","text":"The first step is to create a type that conforms to Command . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... } Now let's implement the required methods.","title":"Command"},{"location":"command/overview/#arguments","text":"Commands can have zero or more CommandArgument s. These arguments will be required for the command to run. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { /// See `Command` var arguments : [ CommandArgument ] { return [. argument ( name : message )] } ... } Here we are defining one argument, the message that the cow will say. This is required to run the cowsay command.","title":"Arguments"},{"location":"command/overview/#options","text":"Commands can have zero or more CommandOption s. These options are not required for the command to run and can be passed using -- or - syntax. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var options : [ CommandOption ] { return [ . value ( name : eyes , short : e , default : oo , help : [ Change cow s eyes ]), . value ( name : tongue , short : t , default : , help : [ Change cow s tongue ]), ] } ... } Here we are defining two options, eyes and tongue . These will let the user optionally change how the cow looks.","title":"Options"},{"location":"command/overview/#help","text":"Next we can define an optional help message to display when the user passes --help . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var help : [ String ] { return [ Generates ASCII picture of a cow with a message. ] } ... } Let's take a look at how this will look once our command is complete: Usage: executable cowsay message [ --eyes,-e ] [ --tongue,-t ] Generates ASCII picture of a cow with a message. Arguments: message n/a Options: eyes Change cow s eyes tongue Change cow s tongue","title":"Help"},{"location":"command/overview/#run","text":"Finally, we need to write our implementation: /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command`. func run ( using context : CommandContext ) throws - Future Void { let message = try context . argument ( message ) /// We can use requireOption here since both options have default values let eyes = try context . requireOption ( eyes ) let tongue = try context . requireOption ( tongue ) let padding = String ( repeating : - , count : message . count ) let text : String = \\( padding ) \\( message ) \\( padding ) \\\\ ^__^ \\\\ ( \\( eyes ) \\\\ _______ (__) \\\\ ) \\\\ / \\\\ \\( tongue ) ||----w | || || context . console . print ( text ) return . done ( on : context . container ) } } The CommandContext gives you access to everything you will need, including a Container . Now that we have a complete Command , the next step is to configure it.","title":"Run"},{"location":"command/overview/#config","text":"Use the CommandConfig struct to register commands to your container. This is usually done in configure.swift /// Create a `CommandConfig` with default commands. var commandConfig = CommandConfig . default () /// Add the `CowsayCommand`. commandConfig . use ( CowsayCommand (), as : cowsay ) /// Register this `CommandConfig` to services. services . register ( commandConfig ) Check that your command was properly configured using --help . swift run Run cowsay -- help That's it! $ swift run Run cowsay Good job ! - e ^^ - t U --------- Good job ! --------- \\ ^ __ ^ \\ ( ^^ \\ _______ ( __ ) \\ ) \\ / \\ U ||---- w | || ||","title":"Config"},{"location":"console/getting-started/","text":"Getting Started with Console The Console module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for performing console I/O including things like outputting stylized text, requesting user input, and displaying activity indicators like loading bars. Tip For an in-depth look at all of Console's APIs, check out the Console API docs . Usage This package is included with Vapor and exported by default. You will have access to all Console APIs when you import Vapor . import Vapor // implies import Console Standalone The Console module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Console , ... ]) ] ) Use import Console to access the APIs. Overview Continue to Console \u2192 Overview for an overview of Console's features.","title":"Getting Started"},{"location":"console/getting-started/#getting-started-with-console","text":"The Console module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for performing console I/O including things like outputting stylized text, requesting user input, and displaying activity indicators like loading bars. Tip For an in-depth look at all of Console's APIs, check out the Console API docs .","title":"Getting Started with Console"},{"location":"console/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Console APIs when you import Vapor . import Vapor // implies import Console","title":"Usage"},{"location":"console/getting-started/#standalone","text":"The Console module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Console , ... ]) ] ) Use import Console to access the APIs.","title":"Standalone"},{"location":"console/getting-started/#overview","text":"Continue to Console \u2192 Overview for an overview of Console's features.","title":"Overview"},{"location":"console/overview/","text":"Console Overview This guide will give you a brief introduction to the Console module, showing you how to output stylized text and request user input. Terminal A default implementation of the Console protocol called Terminal is provided for you to use. let terminal = Terminal () print ( terminal is Console ) // true terminal . print ( Hello ) The rest of this guide will assume a generic Console , but using Terminal directly will also work fine. You can use any available Container to create a console. let console = try req . make ( Console . self ) console . print ( Hello ) Output Console provides several convenience methods for outputting strings, like print(_:) and warning(_:) . All of these methods eventually call output(_:) which is the most powerful output method. This method accepts ConsoleText which supports independently styled string components. /// Prints Hello, world , but the word world is blue. console . output ( Hello, + world . consoleText ( color : . blue )) You can combine as many differently styled fragments to a ConsoleText as you like. All Console methods that output text should have an overload for accepting ConsoleText . Input Console offers several methods for requesting input from the user, the most basic of which is input(isSecure:) . /// Accepts input from the terminal until the first newline. let input = console . input () console . print ( You wrote: \\( input ) ) Ask Use ask(_:) to supply a prompt and input indicator to the user. /// Outputs the prompt then requests input. let name = console . ask ( What is your name? ) console . print ( You said: \\( name ) ) The above code will output: What is your name? Vapor You said: Vapor Confirm Use confirm(_:) to prompt the user for yes / no input. /// Prompts the user for yes / no input. if console . confirm ( Are you sure? ) { // they are sure } else { // don t do it! } The above code will output: Are you sure ? y / n yes Note confirm(_:) will continue to prompt the user until they respond with something recognized as yes or no.","title":"Overview"},{"location":"console/overview/#console-overview","text":"This guide will give you a brief introduction to the Console module, showing you how to output stylized text and request user input.","title":"Console Overview"},{"location":"console/overview/#terminal","text":"A default implementation of the Console protocol called Terminal is provided for you to use. let terminal = Terminal () print ( terminal is Console ) // true terminal . print ( Hello ) The rest of this guide will assume a generic Console , but using Terminal directly will also work fine. You can use any available Container to create a console. let console = try req . make ( Console . self ) console . print ( Hello )","title":"Terminal"},{"location":"console/overview/#output","text":"Console provides several convenience methods for outputting strings, like print(_:) and warning(_:) . All of these methods eventually call output(_:) which is the most powerful output method. This method accepts ConsoleText which supports independently styled string components. /// Prints Hello, world , but the word world is blue. console . output ( Hello, + world . consoleText ( color : . blue )) You can combine as many differently styled fragments to a ConsoleText as you like. All Console methods that output text should have an overload for accepting ConsoleText .","title":"Output"},{"location":"console/overview/#input","text":"Console offers several methods for requesting input from the user, the most basic of which is input(isSecure:) . /// Accepts input from the terminal until the first newline. let input = console . input () console . print ( You wrote: \\( input ) )","title":"Input"},{"location":"console/overview/#ask","text":"Use ask(_:) to supply a prompt and input indicator to the user. /// Outputs the prompt then requests input. let name = console . ask ( What is your name? ) console . print ( You said: \\( name ) ) The above code will output: What is your name? Vapor You said: Vapor","title":"Ask"},{"location":"console/overview/#confirm","text":"Use confirm(_:) to prompt the user for yes / no input. /// Prompts the user for yes / no input. if console . confirm ( Are you sure? ) { // they are sure } else { // don t do it! } The above code will output: Are you sure ? y / n yes Note confirm(_:) will continue to prompt the user until they respond with something recognized as yes or no.","title":"Confirm"},{"location":"crypto/asymmetric/","text":"Asymmetric Cryptography Asymmetric cryptography (also called public-key cryptography) is a cryptographic system that uses multiple keys usually a \"public\" and \"private\" key. Read more about public-key cryptography on Wikipedia. RSA A popular asymmetric cryptography algorithm is RSA. RSA has two key types: public and private. RSA can create signatures from any data using a private key. let privateKey : String = ... let signature = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) Info Only private keys can create signatures. These signatures can be verified against the same data later using either the public or private key. let publicKey : String = ... try RSA . SHA512 . verify ( signature , signs : vapor , key : . public ( pem : publicKey )) // true If RSA verifies that a signature matches input data for a public key, you can be sure that whoever generated that signature had access to that key's private key. Algorithms RSA supports any of the Crypto module's DigestAlgorithm . let privateKey : String = ... let signature512 = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) let signature256 = try RSA . SHA256 . sign ( vapor , key : . private ( pem : privateKey ))","title":"Asymmetric"},{"location":"crypto/asymmetric/#asymmetric-cryptography","text":"Asymmetric cryptography (also called public-key cryptography) is a cryptographic system that uses multiple keys usually a \"public\" and \"private\" key. Read more about public-key cryptography on Wikipedia.","title":"Asymmetric Cryptography"},{"location":"crypto/asymmetric/#rsa","text":"A popular asymmetric cryptography algorithm is RSA. RSA has two key types: public and private. RSA can create signatures from any data using a private key. let privateKey : String = ... let signature = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) Info Only private keys can create signatures. These signatures can be verified against the same data later using either the public or private key. let publicKey : String = ... try RSA . SHA512 . verify ( signature , signs : vapor , key : . public ( pem : publicKey )) // true If RSA verifies that a signature matches input data for a public key, you can be sure that whoever generated that signature had access to that key's private key.","title":"RSA"},{"location":"crypto/asymmetric/#algorithms","text":"RSA supports any of the Crypto module's DigestAlgorithm . let privateKey : String = ... let signature512 = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) let signature256 = try RSA . SHA256 . sign ( vapor , key : . private ( pem : privateKey ))","title":"Algorithms"},{"location":"crypto/ciphers/","text":"Cipher Algorithms Ciphers allow you to encrypt plaintext data with a key yielding ciphertext. This ciphertext can be later decrypted by the same cipher using the same key. Read more about ciphers on Wikipedia. Encrypt Use the global convenience variables for encrypting data with common algorithms. let ciphertext = try AES128 . encrypt ( vapor , key : secret ) print ( ciphertext ) /// Data Decrypt Decryption works very similarly to encryption . The following snippet shows how to decrypt the ciphertext from our previous example. let plaintext = try AES128 . decrypt ( ciphertext , key : secret ) print ( plaintext ) /// vapor See the Crypto module's global variables for a list of all available cipher algorithms. Streaming Both encryption and decryption can work in a streaming mode that allows data to be chunked. This is useful for controlling memory usage while encrypting large amounts of data. let key : Data // 16-bytes let aes128 = Cipher ( algorithm : . aes128ecb ) try aes128 . reset ( key : key , mode : . encrypt ) var buffer = Data () try aes128 . update ( data : hello , into : buffer ) try aes128 . update ( data : world , into : buffer ) try aes128 . finish ( into : buffer ) print ( buffer ) // Completed ciphertext","title":"Ciphers"},{"location":"crypto/ciphers/#cipher-algorithms","text":"Ciphers allow you to encrypt plaintext data with a key yielding ciphertext. This ciphertext can be later decrypted by the same cipher using the same key. Read more about ciphers on Wikipedia.","title":"Cipher Algorithms"},{"location":"crypto/ciphers/#encrypt","text":"Use the global convenience variables for encrypting data with common algorithms. let ciphertext = try AES128 . encrypt ( vapor , key : secret ) print ( ciphertext ) /// Data","title":"Encrypt"},{"location":"crypto/ciphers/#decrypt","text":"Decryption works very similarly to encryption . The following snippet shows how to decrypt the ciphertext from our previous example. let plaintext = try AES128 . decrypt ( ciphertext , key : secret ) print ( plaintext ) /// vapor See the Crypto module's global variables for a list of all available cipher algorithms.","title":"Decrypt"},{"location":"crypto/ciphers/#streaming","text":"Both encryption and decryption can work in a streaming mode that allows data to be chunked. This is useful for controlling memory usage while encrypting large amounts of data. let key : Data // 16-bytes let aes128 = Cipher ( algorithm : . aes128ecb ) try aes128 . reset ( key : key , mode : . encrypt ) var buffer = Data () try aes128 . update ( data : hello , into : buffer ) try aes128 . update ( data : world , into : buffer ) try aes128 . finish ( into : buffer ) print ( buffer ) // Completed ciphertext","title":"Streaming"},{"location":"crypto/digests/","text":"Message Digests Cryptographic hash functions (also known as message digest algorithms) convert data of arbitrary size to a fixed-size digest. These are most often used for generating checksums or identifiers for large data blobs. Read more about Cryptographic hash functions on Wikipedia. Hash Use the global convenience variables to create hashes using common algorithms. import Crypto let digest = try SHA1 . hash ( hello ) print ( digest . hexEncodedString ()) // aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d See the Crypto module's global variables for a list of all available hash algorithms. Streaming You can create a Digest manually and use its instance methods to create a hash for one or more data chunks. var sha256 = try Digest ( algorithm : . sha256 ) try sha256 . reset () try sha256 . update ( data : hello ) try sha256 . update ( data : world ) let digest = try sha256 . finish () print ( digest ) /// Data BCrypt BCrypt is a popular hashing algorithm that has configurable complexity and handles salting automatically. Hash Use the hash(_:cost:salt:) method to create BCrypt hashes. let digest = try BCrypt . hash ( vapor , cost : 4 ) print ( digest ) /// data Increasing the cost value will make hashing and verification take longer. Verify Use the verify(_:created:) method to verify that a BCrypt hash was created by a given plaintext input. let hash = try BCrypt . hash ( vapor , cost : 4 ) try BCrypt . verify ( vapor , created : hash ) // true try BCrypt . verify ( foo , created : hash ) // false HMAC HMAC is an algorithm for creating keyed hashes. HMAC will generate different hashes for the same input if different keys are used. let digest = try HMAC . SHA1 . authenticate ( vapor , key : secret ) print ( digest . hexEncodedString ()) // digest See the HMAC class for a list of all available hash algorithms. Streaming HMAC hashes can also be streamed. The API is identical to hash streaming .","title":"Digests"},{"location":"crypto/digests/#message-digests","text":"Cryptographic hash functions (also known as message digest algorithms) convert data of arbitrary size to a fixed-size digest. These are most often used for generating checksums or identifiers for large data blobs. Read more about Cryptographic hash functions on Wikipedia.","title":"Message Digests"},{"location":"crypto/digests/#hash","text":"Use the global convenience variables to create hashes using common algorithms. import Crypto let digest = try SHA1 . hash ( hello ) print ( digest . hexEncodedString ()) // aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d See the Crypto module's global variables for a list of all available hash algorithms.","title":"Hash"},{"location":"crypto/digests/#streaming","text":"You can create a Digest manually and use its instance methods to create a hash for one or more data chunks. var sha256 = try Digest ( algorithm : . sha256 ) try sha256 . reset () try sha256 . update ( data : hello ) try sha256 . update ( data : world ) let digest = try sha256 . finish () print ( digest ) /// Data","title":"Streaming"},{"location":"crypto/digests/#bcrypt","text":"BCrypt is a popular hashing algorithm that has configurable complexity and handles salting automatically.","title":"BCrypt"},{"location":"crypto/digests/#hash_1","text":"Use the hash(_:cost:salt:) method to create BCrypt hashes. let digest = try BCrypt . hash ( vapor , cost : 4 ) print ( digest ) /// data Increasing the cost value will make hashing and verification take longer.","title":"Hash"},{"location":"crypto/digests/#verify","text":"Use the verify(_:created:) method to verify that a BCrypt hash was created by a given plaintext input. let hash = try BCrypt . hash ( vapor , cost : 4 ) try BCrypt . verify ( vapor , created : hash ) // true try BCrypt . verify ( foo , created : hash ) // false","title":"Verify"},{"location":"crypto/digests/#hmac","text":"HMAC is an algorithm for creating keyed hashes. HMAC will generate different hashes for the same input if different keys are used. let digest = try HMAC . SHA1 . authenticate ( vapor , key : secret ) print ( digest . hexEncodedString ()) // digest See the HMAC class for a list of all available hash algorithms.","title":"HMAC"},{"location":"crypto/digests/#streaming_1","text":"HMAC hashes can also be streamed. The API is identical to hash streaming .","title":"Streaming"},{"location":"crypto/getting-started/","text":"Using Crypto Crypto ( vapor/crypto ) is a library containing common APIs related to cryptography and data generation. The package contains two modules: Crypto Random With Vapor This package is included with Vapor by default, just add: import Crypto import Random Without Vapor To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/crypto.git , . upToNextMajor ( from : x.0.0 )), ], targets : [ . target ( name : Project , dependencies : [ Crypto , Random , ... ]) ] ) Use import Crypto to access Crypto's APIs and import Random to access Random's APIs.","title":"Getting Started"},{"location":"crypto/getting-started/#using-crypto","text":"Crypto ( vapor/crypto ) is a library containing common APIs related to cryptography and data generation. The package contains two modules: Crypto Random","title":"Using Crypto"},{"location":"crypto/getting-started/#with-vapor","text":"This package is included with Vapor by default, just add: import Crypto import Random","title":"With Vapor"},{"location":"crypto/getting-started/#without-vapor","text":"To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/crypto.git , . upToNextMajor ( from : x.0.0 )), ], targets : [ . target ( name : Project , dependencies : [ Crypto , Random , ... ]) ] ) Use import Crypto to access Crypto's APIs and import Random to access Random's APIs.","title":"Without Vapor"},{"location":"crypto/otp/","text":"TOTP and HOTP One-time passwords (OTPs) are commonly used as a form of two-factor authentication . Crypto can be used to generate both TOTP and HOTP in accordance with RFC 6238 and RFC 4226 respectively. TOTP : Time-based One-Time Password. Generates password by combining shared secret with unix timestamp. HOTP : HMAC-Based One-Time Password. Similar to TOTP, except an incrementing counter is used instead of a timestamp. Each time a new OTP is generated, the counter increments. Generating OTP OTP generation is similar for both TOTP and HOTP. The only difference is that HOTP requires the current counter to be passed. import Crypto // Generate TOTP let code = TOTP . SHA1 . generate ( secret : hi ) print ( code ) 123456 // Generate HOTP let code = HOTP . SHA1 . generate ( secret : hi , counter : 0 ) print ( code ) 208503 View the API docs for TOTP and HOTP for more information. Base 32 TOTP and HOTP shared secrets are commonly transferred using Base32 encoding. Crypto provides conveniences for converting to/from Base32. import Crypto // shared secret let secret : Data = ... // base32 encoded secret let encodedSecret = secret . base32EncodedString () See Crypto's Data extensions for more information.","title":"TOTP & HOTP"},{"location":"crypto/otp/#totp-and-hotp","text":"One-time passwords (OTPs) are commonly used as a form of two-factor authentication . Crypto can be used to generate both TOTP and HOTP in accordance with RFC 6238 and RFC 4226 respectively. TOTP : Time-based One-Time Password. Generates password by combining shared secret with unix timestamp. HOTP : HMAC-Based One-Time Password. Similar to TOTP, except an incrementing counter is used instead of a timestamp. Each time a new OTP is generated, the counter increments.","title":"TOTP and HOTP"},{"location":"crypto/otp/#generating-otp","text":"OTP generation is similar for both TOTP and HOTP. The only difference is that HOTP requires the current counter to be passed. import Crypto // Generate TOTP let code = TOTP . SHA1 . generate ( secret : hi ) print ( code ) 123456 // Generate HOTP let code = HOTP . SHA1 . generate ( secret : hi , counter : 0 ) print ( code ) 208503 View the API docs for TOTP and HOTP for more information.","title":"Generating OTP"},{"location":"crypto/otp/#base-32","text":"TOTP and HOTP shared secrets are commonly transferred using Base32 encoding. Crypto provides conveniences for converting to/from Base32. import Crypto // shared secret let secret : Data = ... // base32 encoded secret let encodedSecret = secret . base32EncodedString () See Crypto's Data extensions for more information.","title":"Base 32"},{"location":"crypto/random/","text":"Random The Random module deals with random data generation including random number generation. Data Generator The DataGenerator class powers all of the random data generators. Implementations OSRandom : Provides a random data generator using a platform-specific method. URandom provides random data generation based on the /dev/urandom file. CryptoRandom from the Crypto module provides cryptographically-secure random data using OpenSSL. let random : DataGenerator ... let data = try random . generateData ( bytes : 8 ) Generate DataGenerator s are capable of generating random primitive types using the generate(_:) method. let int = try OSRandom (). generate ( Int . self ) print ( int ) // Int","title":"Random"},{"location":"crypto/random/#random","text":"The Random module deals with random data generation including random number generation.","title":"Random"},{"location":"crypto/random/#data-generator","text":"The DataGenerator class powers all of the random data generators.","title":"Data Generator"},{"location":"crypto/random/#implementations","text":"OSRandom : Provides a random data generator using a platform-specific method. URandom provides random data generation based on the /dev/urandom file. CryptoRandom from the Crypto module provides cryptographically-secure random data using OpenSSL. let random : DataGenerator ... let data = try random . generateData ( bytes : 8 )","title":"Implementations"},{"location":"crypto/random/#generate","text":"DataGenerator s are capable of generating random primitive types using the generate(_:) method. let int = try OSRandom (). generate ( Int . self ) print ( int ) // Int","title":"Generate"},{"location":"database-kit/getting-started/","text":"Getting Started with Database Kit Database Kit ( vapor/database-kit ) is a framework for configuring and working with database connections. It includes core services like caching, logging, and connection pooling. Tip If you use Fluent, you will usually not need to use Database Kit manually. But learning the APIs may come in handy. Package The Database Kit package is lightweight, pure Swift, and has few dependencies. This means it can be used as a core database framework for any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/database-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ DatabaseKit , ... ]) ] ) Use import DatabaseKit to access the APIs. API Docs The rest of this guide will give you an overview of what is available in the DatabaseKit package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"database-kit/getting-started/#getting-started-with-database-kit","text":"Database Kit ( vapor/database-kit ) is a framework for configuring and working with database connections. It includes core services like caching, logging, and connection pooling. Tip If you use Fluent, you will usually not need to use Database Kit manually. But learning the APIs may come in handy.","title":"Getting Started with Database Kit"},{"location":"database-kit/getting-started/#package","text":"The Database Kit package is lightweight, pure Swift, and has few dependencies. This means it can be used as a core database framework for any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/database-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ DatabaseKit , ... ]) ] ) Use import DatabaseKit to access the APIs.","title":"Package"},{"location":"database-kit/getting-started/#api-docs","text":"The rest of this guide will give you an overview of what is available in the DatabaseKit package. As always, feel free to visit the API docs for more in-depth information.","title":"API Docs"},{"location":"database-kit/overview/","text":"Using Database Kit Database Kit is a framework for configuring and working with database connections. It helps you do things like manage and pool connections, create keyed caches, and log queries. Many of Vapor's packages such as the Fluent drivers, Redis, and Vapor core are built on top of Database Kit. This guide will walk you through some of the common APIs you might encounter when using Database Kit. Config Your first interaction with Database Kit will most likely be with the DatabasesConfig struct. This type helps you configure one or more databases to your application and will ultimately yield a Databases struct. This usually takes place in configure.swift . // Create a SQLite database. let sqliteDB = SQLiteDatabase (...) // Create a new, empty DatabasesConfig. var dbsConfig = DatabasesConfig () // Register the SQLite database using .sqlite as an identifier. dbsConfig . add ( sqliteDB , as : . sqlite ) // Register more DBs here if you want // Register the DatabaseConfig to services. services . register ( dbsConfig ) Using the add(...) methods, you can register Database s to the config. You can register instances of a database, a database type, or a closure that creates a database. The latter two methods will be resolved when your container boots. You can also configure options on your databases, such as enabling logging. // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) See the section on logging for more information. Identifier Most database integrations will provide a default DatabaseIdentifier to use. However, you can always create your own. This is usually done by creating a static extension. extension DatabaseIdentifier { /// Test database. static var testing : DatabaseIdentifier MySQLDatabase { return testing } } DatabaseIdentifier is ExpressibleByStringLiteral which allows you to create one with just a String . Databases Once you have registered a DatabasesConfig to your services and booted a container, you can take advantage of the convenience extensions on Container to start creating connections. // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } Read more about creating and managing connections in the next section. Connections Database Kit's main focus is on creating, managing, and pooling connections. Creating new connections takes a non-trivial amount of time for your application and many cloud services limit the total number of connections to a service that can be open. Because of this, it is important for high-concurrency web applications to manage their connections carefully. Pools A common solution to connection management is the use of connection pools. These pools usually have a set maximum number of connections that are allowed to be open at once. Each time the pool is asked for a connection, it will first check if one is available before creating a new connection. If none are available, it will create a new one. If no connections are available and the pool is already at its maximum, the request for a new connection will wait for a connection to be returned. The easiest way to request and release a pooled connection is the method withPooledConnection(...) . // Requests a pooled connection to `.psql` db req . withPooledConnection ( to : . psql ) { conn in return conn . query (...) // do some db query } This method will request a pooled connection to the identified database and call the provided closure when the connection is available. When the Future returned by the closure has completed, the connection will automatically be returned to the pool. If you need access to a connection outside of a closure, you can use the related request / release methods instead. // Request a connection from the pool and wait for it to be ready. let conn = try app . requestPooledConnection ( to : . psql ). wait () // Ensure the connection is released when we exit this scope. defer { app . releasePooledConnection ( conn , to : . psql ) } You can configure your connection pools using the DatabaseConnectionPoolConfig struct. // Create a new, empty pool config. var poolConfig = DatabaseConnectionPoolConfig () // Set max connections per pool to 8. poolConfig . maxConnections = 8 // Register the pool config. services . register ( poolConfig ) To prevent race conditions, pools are never shared between event loops. There is usually one pool per database per event loop. This means that the amount of connections your application can potentially open to a given database is equal to numThreads * maxConns . New You can always create a new connection to your databases if you need to. This will not affect your pooled connections. Creating new connections is especially useful during testing and app boot. But try not to do it in route closures since heavy traffic to your app could end up creating a lot of connections! Similar to pooled connections, opening and closing new connections can be done using withNewConnection(...) . // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } This method will create a new connection, calling the supplied closure when the connection is open. When the Future returned in the closure completes, the connection will be closed automatically. You can also simply open a new connection with newConnection(...) . // Creates a new connection to `.sqlite` db let conn = try app . newConnection ( to : . sqlite ). wait () // Ensure the connection is closed when we exit this scope. defer { conn . close () } Logging Databases can opt into supporting query logging via the LogSupporting protocol. Databases that conform to this protocol can have loggers configured via DatabasesConfig . // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) By default, a simple print logger will be used, but you can pass a custom DatabaseLogHandler . // Create a custom log handler. let myLogger : DatabaseLogHandler = ... // Enable logging on SQLite w/ custom logger. dbsConfig . enableLogging ( for : . sqlite , logger : myLogger ) Log handlers will receive an instance of DatabaseLog for each logged query. This contains information such as the query, parameterized values, database id, and time. Keyed Cache Databases can opt into supporting keyed-caching via the KeyedCacheSupporting protocol. Databases that conform to this protocol can be used to create instances of DatabaseKeyedCache . Keyed caches are capable of getting, setting, and removing Codable values at keys. They are sometimes called \"key value stores\". To create a keyed cache, you can use the extensions on Container . // Creates a DatabaseKeyedCache with .redis connection pool let cache = try app . keyedCache ( for : . redis ) // Sets hello = world try cache . set ( hello , to : world ). wait () // Gets hello let world = try cache . get ( hello , as : String . self ). wait () print ( world ) // world // Removes hello try cache . remove ( hello ). wait () See the KeyedCache protocol for more information. API Docs Check out the API docs for more in-depth information about DatabaseKit's APIs.","title":"Overview"},{"location":"database-kit/overview/#using-database-kit","text":"Database Kit is a framework for configuring and working with database connections. It helps you do things like manage and pool connections, create keyed caches, and log queries. Many of Vapor's packages such as the Fluent drivers, Redis, and Vapor core are built on top of Database Kit. This guide will walk you through some of the common APIs you might encounter when using Database Kit.","title":"Using Database Kit"},{"location":"database-kit/overview/#config","text":"Your first interaction with Database Kit will most likely be with the DatabasesConfig struct. This type helps you configure one or more databases to your application and will ultimately yield a Databases struct. This usually takes place in configure.swift . // Create a SQLite database. let sqliteDB = SQLiteDatabase (...) // Create a new, empty DatabasesConfig. var dbsConfig = DatabasesConfig () // Register the SQLite database using .sqlite as an identifier. dbsConfig . add ( sqliteDB , as : . sqlite ) // Register more DBs here if you want // Register the DatabaseConfig to services. services . register ( dbsConfig ) Using the add(...) methods, you can register Database s to the config. You can register instances of a database, a database type, or a closure that creates a database. The latter two methods will be resolved when your container boots. You can also configure options on your databases, such as enabling logging. // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) See the section on logging for more information.","title":"Config"},{"location":"database-kit/overview/#identifier","text":"Most database integrations will provide a default DatabaseIdentifier to use. However, you can always create your own. This is usually done by creating a static extension. extension DatabaseIdentifier { /// Test database. static var testing : DatabaseIdentifier MySQLDatabase { return testing } } DatabaseIdentifier is ExpressibleByStringLiteral which allows you to create one with just a String .","title":"Identifier"},{"location":"database-kit/overview/#databases","text":"Once you have registered a DatabasesConfig to your services and booted a container, you can take advantage of the convenience extensions on Container to start creating connections. // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } Read more about creating and managing connections in the next section.","title":"Databases"},{"location":"database-kit/overview/#connections","text":"Database Kit's main focus is on creating, managing, and pooling connections. Creating new connections takes a non-trivial amount of time for your application and many cloud services limit the total number of connections to a service that can be open. Because of this, it is important for high-concurrency web applications to manage their connections carefully.","title":"Connections"},{"location":"database-kit/overview/#pools","text":"A common solution to connection management is the use of connection pools. These pools usually have a set maximum number of connections that are allowed to be open at once. Each time the pool is asked for a connection, it will first check if one is available before creating a new connection. If none are available, it will create a new one. If no connections are available and the pool is already at its maximum, the request for a new connection will wait for a connection to be returned. The easiest way to request and release a pooled connection is the method withPooledConnection(...) . // Requests a pooled connection to `.psql` db req . withPooledConnection ( to : . psql ) { conn in return conn . query (...) // do some db query } This method will request a pooled connection to the identified database and call the provided closure when the connection is available. When the Future returned by the closure has completed, the connection will automatically be returned to the pool. If you need access to a connection outside of a closure, you can use the related request / release methods instead. // Request a connection from the pool and wait for it to be ready. let conn = try app . requestPooledConnection ( to : . psql ). wait () // Ensure the connection is released when we exit this scope. defer { app . releasePooledConnection ( conn , to : . psql ) } You can configure your connection pools using the DatabaseConnectionPoolConfig struct. // Create a new, empty pool config. var poolConfig = DatabaseConnectionPoolConfig () // Set max connections per pool to 8. poolConfig . maxConnections = 8 // Register the pool config. services . register ( poolConfig ) To prevent race conditions, pools are never shared between event loops. There is usually one pool per database per event loop. This means that the amount of connections your application can potentially open to a given database is equal to numThreads * maxConns .","title":"Pools"},{"location":"database-kit/overview/#new","text":"You can always create a new connection to your databases if you need to. This will not affect your pooled connections. Creating new connections is especially useful during testing and app boot. But try not to do it in route closures since heavy traffic to your app could end up creating a lot of connections! Similar to pooled connections, opening and closing new connections can be done using withNewConnection(...) . // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } This method will create a new connection, calling the supplied closure when the connection is open. When the Future returned in the closure completes, the connection will be closed automatically. You can also simply open a new connection with newConnection(...) . // Creates a new connection to `.sqlite` db let conn = try app . newConnection ( to : . sqlite ). wait () // Ensure the connection is closed when we exit this scope. defer { conn . close () }","title":"New"},{"location":"database-kit/overview/#logging","text":"Databases can opt into supporting query logging via the LogSupporting protocol. Databases that conform to this protocol can have loggers configured via DatabasesConfig . // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) By default, a simple print logger will be used, but you can pass a custom DatabaseLogHandler . // Create a custom log handler. let myLogger : DatabaseLogHandler = ... // Enable logging on SQLite w/ custom logger. dbsConfig . enableLogging ( for : . sqlite , logger : myLogger ) Log handlers will receive an instance of DatabaseLog for each logged query. This contains information such as the query, parameterized values, database id, and time.","title":"Logging"},{"location":"database-kit/overview/#keyed-cache","text":"Databases can opt into supporting keyed-caching via the KeyedCacheSupporting protocol. Databases that conform to this protocol can be used to create instances of DatabaseKeyedCache . Keyed caches are capable of getting, setting, and removing Codable values at keys. They are sometimes called \"key value stores\". To create a keyed cache, you can use the extensions on Container . // Creates a DatabaseKeyedCache with .redis connection pool let cache = try app . keyedCache ( for : . redis ) // Sets hello = world try cache . set ( hello , to : world ). wait () // Gets hello let world = try cache . get ( hello , as : String . self ). wait () print ( world ) // world // Removes hello try cache . remove ( hello ). wait () See the KeyedCache protocol for more information.","title":"Keyed Cache"},{"location":"database-kit/overview/#api-docs","text":"Check out the API docs for more in-depth information about DatabaseKit's APIs.","title":"API Docs"},{"location":"fluent/getting-started/","text":"Getting Started with Fluent Fluent ( vapor/fluent ) is a type-safe, fast, and easy-to-use ORM framework built for Swift. It takes advantage of Swift's strong type system to provide an elegant foundation for building database integrations. Choosing a Driver Fluent is a framework for building ORMs, not an ORM itself. To use Fluent, you will first need to choose a database driver to use. Fluent can support multiple databases and database drivers per application. Below is a list of officially supported database drivers for Fluent. database repo version dbid notes PostgreSQL fluent-postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL fluent-mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite fluent-sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. MongoDB fluent-mongo n/a mongo Coming soon. Popular NoSQL database. Note Replace any Xcode placholders ( #...# ) in the code snippets below with information from the above table. You can search GitHub for the tag fluent-database for a full list of official and third-party Fluent database drivers. Package Once you have decided which driver you want, the next step is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/ #repo# .git , from : #version# ), ], targets : [ . target ( name : App , dependencies : [ Fluent #Database# , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Creating a Model Now let's create your first model. Models represent tables in your database and they are the primary method of interacting with your data. Each driver provides convenience model protocols ( PostgreSQLModel , SQLiteModel , etc) that extend Fluent's base Model protocol. These convenience types make declaring models more concise by using standard values for ID key and type. Fill in the Xcode placeholders below with the name of your chosen database, i.e., PostgreSQL . import Fluent # Database # import Vapor /// A simple user. final class User : # Database # Model { /// The unique identifier for this user. var id : ID ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : ID ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } The example above shows a simple model representing a user. You can make both structs and classes a model. You can even conform types that come from external modules. The only requirement is that these types conform to Codable , which must be declared on the base type for synthesized (automatic) conformance. Take a look at Fluent Model for more information on creating models with custom ID types and keys. Configuring the Database Now that you have a model, you can configure your database. This is done in configure.swift . Register Provider The first step is to register your database driver's provider. import Fluent # Database # import Vapor // Register providers first try services . register ( Fluent # Database # Provider ()) // Other services.... Registering the provider will add all of the services required for your Fluent database to work properly. It also includes a default database config struct that uses typical development environment credentials. Custom Credentials If you are using default configuration for your database (such as default credentials or other config) then this may be the only setup you need to perform. See the documentation for your specific database type for more information about custom configuration. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDatabase MySQL MySQL Getting Started MySQLDatabase SQLite SQLite Getting Started SQLiteDatabase Creating a Migration If your database driver uses schemas (is a SQL database), you will need to create a Migration for your new model. Migrations allow Fluent to create a table for your model in a reliable, testable way. You can later create additional migrations to update or delete the model's table or even manipulate data in the table. To create a migration, you will normally first create a new struct or class to hold the migration. However, models can take advantage of a convenient shortcut. When you create a migration from an existing model type, Fluent can infer an appropriate schema from the model's codable properties. You can add the migration conformance to a model as an extension or on the base type declaration. import Fluent # Database # import Vapor extension User : # Database # Migration { } Take a look at Fluent Migration if you are interested in learning more about custom migrations. Configuring Migrations Once you have created a migration, you must register it to Fluent using MigrationConfig . This is done in configure.swift . Fill in the database ID ( dbid ) from the table above, i.e., psql . import Fluent # Database # import Vapor // Configure migrations var migrations = MigrationConfig () migrations . add ( model : User . self , database : . # dbid # ) services . register ( migrations ) // Other services.... Tip If the migration you are adding is also a model, you can use the add(model:on:) convenience to automatically set the model's defaultDatabase property. Otherwise, use the add(migration:on) method. Once you have the MigrationConfig added, you should be able to run your application and see the following: Migrating #dbid# DB Migrations complete Server starting on http://localhost:8080 Performing a Query Now that you have created a model and a corresponding schema in your database, let's make your first query. router . get ( users ) { req in return User . query ( on : req ). all () } If you run your app, and query that route, you should see an empty array returned. Now you just need to add some users! Congratulations on getting your first Fluent model working. Raw Queries With Fluent, you always have access to the underlying database driver. Using this underlying driver to perform a query is sometimes called a \"raw query\". To perform raw queries, you need access to a database connection. Vapor's Request type has a number of conveniences for creating new database connections. The recommended method is withPooledConnection(to:) . Learn about other methods in DatabaseKit Overview Connections . router . get ( raw ) { req - Future String in return req . withPooledConnection ( to : . # dbid # ) { conn in // perform raw query using conn } } Once you have the database connection, you can perform a query on it. You can learn more about the methods available in the database's documentation.","title":"Getting Started"},{"location":"fluent/getting-started/#getting-started-with-fluent","text":"Fluent ( vapor/fluent ) is a type-safe, fast, and easy-to-use ORM framework built for Swift. It takes advantage of Swift's strong type system to provide an elegant foundation for building database integrations.","title":"Getting Started with Fluent"},{"location":"fluent/getting-started/#choosing-a-driver","text":"Fluent is a framework for building ORMs, not an ORM itself. To use Fluent, you will first need to choose a database driver to use. Fluent can support multiple databases and database drivers per application. Below is a list of officially supported database drivers for Fluent. database repo version dbid notes PostgreSQL fluent-postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL fluent-mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite fluent-sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. MongoDB fluent-mongo n/a mongo Coming soon. Popular NoSQL database. Note Replace any Xcode placholders ( #...# ) in the code snippets below with information from the above table. You can search GitHub for the tag fluent-database for a full list of official and third-party Fluent database drivers.","title":"Choosing a Driver"},{"location":"fluent/getting-started/#package","text":"Once you have decided which driver you want, the next step is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/ #repo# .git , from : #version# ), ], targets : [ . target ( name : App , dependencies : [ Fluent #Database# , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"fluent/getting-started/#creating-a-model","text":"Now let's create your first model. Models represent tables in your database and they are the primary method of interacting with your data. Each driver provides convenience model protocols ( PostgreSQLModel , SQLiteModel , etc) that extend Fluent's base Model protocol. These convenience types make declaring models more concise by using standard values for ID key and type. Fill in the Xcode placeholders below with the name of your chosen database, i.e., PostgreSQL . import Fluent # Database # import Vapor /// A simple user. final class User : # Database # Model { /// The unique identifier for this user. var id : ID ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : ID ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } The example above shows a simple model representing a user. You can make both structs and classes a model. You can even conform types that come from external modules. The only requirement is that these types conform to Codable , which must be declared on the base type for synthesized (automatic) conformance. Take a look at Fluent Model for more information on creating models with custom ID types and keys.","title":"Creating a Model"},{"location":"fluent/getting-started/#configuring-the-database","text":"Now that you have a model, you can configure your database. This is done in configure.swift .","title":"Configuring the Database"},{"location":"fluent/getting-started/#register-provider","text":"The first step is to register your database driver's provider. import Fluent # Database # import Vapor // Register providers first try services . register ( Fluent # Database # Provider ()) // Other services.... Registering the provider will add all of the services required for your Fluent database to work properly. It also includes a default database config struct that uses typical development environment credentials.","title":"Register Provider"},{"location":"fluent/getting-started/#custom-credentials","text":"If you are using default configuration for your database (such as default credentials or other config) then this may be the only setup you need to perform. See the documentation for your specific database type for more information about custom configuration. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDatabase MySQL MySQL Getting Started MySQLDatabase SQLite SQLite Getting Started SQLiteDatabase","title":"Custom Credentials"},{"location":"fluent/getting-started/#creating-a-migration","text":"If your database driver uses schemas (is a SQL database), you will need to create a Migration for your new model. Migrations allow Fluent to create a table for your model in a reliable, testable way. You can later create additional migrations to update or delete the model's table or even manipulate data in the table. To create a migration, you will normally first create a new struct or class to hold the migration. However, models can take advantage of a convenient shortcut. When you create a migration from an existing model type, Fluent can infer an appropriate schema from the model's codable properties. You can add the migration conformance to a model as an extension or on the base type declaration. import Fluent # Database # import Vapor extension User : # Database # Migration { } Take a look at Fluent Migration if you are interested in learning more about custom migrations.","title":"Creating a Migration"},{"location":"fluent/getting-started/#configuring-migrations","text":"Once you have created a migration, you must register it to Fluent using MigrationConfig . This is done in configure.swift . Fill in the database ID ( dbid ) from the table above, i.e., psql . import Fluent # Database # import Vapor // Configure migrations var migrations = MigrationConfig () migrations . add ( model : User . self , database : . # dbid # ) services . register ( migrations ) // Other services.... Tip If the migration you are adding is also a model, you can use the add(model:on:) convenience to automatically set the model's defaultDatabase property. Otherwise, use the add(migration:on) method. Once you have the MigrationConfig added, you should be able to run your application and see the following: Migrating #dbid# DB Migrations complete Server starting on http://localhost:8080","title":"Configuring Migrations"},{"location":"fluent/getting-started/#performing-a-query","text":"Now that you have created a model and a corresponding schema in your database, let's make your first query. router . get ( users ) { req in return User . query ( on : req ). all () } If you run your app, and query that route, you should see an empty array returned. Now you just need to add some users! Congratulations on getting your first Fluent model working.","title":"Performing a Query"},{"location":"fluent/getting-started/#raw-queries","text":"With Fluent, you always have access to the underlying database driver. Using this underlying driver to perform a query is sometimes called a \"raw query\". To perform raw queries, you need access to a database connection. Vapor's Request type has a number of conveniences for creating new database connections. The recommended method is withPooledConnection(to:) . Learn about other methods in DatabaseKit Overview Connections . router . get ( raw ) { req - Future String in return req . withPooledConnection ( to : . # dbid # ) { conn in // perform raw query using conn } } Once you have the database connection, you can perform a query on it. You can learn more about the methods available in the database's documentation.","title":"Raw Queries"},{"location":"fluent/migrations/","text":"Fluent Migrations Migrations allow you to make organized, testable, and reliable changes to your database's structure-- even while it's in production. Migrations are often used for preparing a database schema for your models. However, they can also be used to make normal queries to your database. In this guide we will cover creating both types of migrations. Creating and Deleting Schemas Let's take a look at how we can use migrations to prepare a schema supporting database to store a theoretical Galaxy model. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String } Automatic Model Migrations Models provide a shortcut for declaring database migrations. If you conform a type that conforms to Model to Migration , Fluent can infer the model's properties and automatically implement the prepare(...) and revert(...) methods. import Fluent # Database # extension Galaxy : # Database # Migration { } This method is especially useful for quick prototyping and simple setups. For most other situations you should consider creating a normal, custom migration. Add this automatic migration to your MigrationConfig using the add(model:database:) method. This is done in configure.swift . var migrations = MigrationConfig () migrations . add ( model : Galaxy . self , database : . # dbid # ) services . register ( migrations ) The add(model:database:) method will automatically set the model's defaultDatabase property. Custom Migrations We can customize the table created for our model by creating a migration and using the static create and delete methods on Database . import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... } Creating a Schema The most important method in a migration is prepare(...) . This is responsible for effecting the migration's changes. For our CreateGalaxy migration, we will use our database's static create method to create a schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . create ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . id , isIdentifier : true ) builder . field ( for : \\ . name ) } } } To create a schema, you must pass a model type and connection as the first two parameters. The third parameter is a closure that accepts the SchemaBuilder . This builder has convenience methods for declaring fields in the schema. You can use the field(for: #KeyPath# ) method to quickly create fields for each of your model's properties. Since this method accepts key paths to the model (indicated by \\. ), Fluent can see what type those properties are. For most common types ( String , Int , Double , etc) Fluent will automatically be able to determine the best database field type to use. You can also choose to manually select which database field type to use for a given field. try builder . field ( for : \\ . name , type : # DataType # ) Each database has it's own unique data types, so refer to your database's documentation for more information. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDataType MySQL MySQL Getting Started MySQLDataType SQLite SQLite Getting Started SQLiteDataType Deleting a Schema Each migration should also include a method for reverting the changes it makes. It is used when you boot your app with the --revert option. For a migration that creates a table in the database, the reversion is quite simple: delete the table. To implement revert for our model, we can use our database's static delete(...) method to indicate that we would like to delete the schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func revert ( on connection : # Database # Connection ) - Future Void { return # Database # Database . delete ( Galaxy . self , on : connection ) } } To delete a schema, you pass a model type and connection as the two required parameters. That's it. You can always choose to skip a reversion by simplying returning conn.future(()) . But note that they are especially useful when testing and debugging your migrations. Add this custom migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () migrations . add ( migration : CreateGalaxy . self , database : . # dbid # ) services . register ( migrations ) Make sure to also set the defaultDatabase property on your model when using a custom migration. Galaxy . defaultDatabase = . # dbid # Updating a Schema After you deploy your application to production, you may find it necessary to add or remove fields on an existing model. You can achieve this by creating a new migration. For this example, let's assume we want to add a new property mass to the Galaxy model from the previous section. import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String var mass : Int } Since our previous migration created a table with fields for both id and name , we need to update that table and add a field for mass . We can do this by using the static update method on Database . import Fluent # Database # struct AddGalaxyMass : # Database # Migration { // ... } Our prepare method will look very similar to the prepare method for a new table, except it will only contain our newly added field. struct AddGalaxyMass : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . mass ) } } } All methods available when creating a schema will be available while updating alongside some new methods for deleting fields. See SchemaUpdater for a list of all available methods. To revert this change, we must delete the mass field from the table. struct AddGalaxyMass : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . deleteField ( for : \\ . mass ) } } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () // ... migrations . add ( migration : AddGalaxyMass . self , database : . # dbid # ) services . register ( migrations ) Migrating Data While migrations are useful for creating and updating schemas in SQL databases, they can also be used for more general purposes in any database. Migrations are passed a connection upon running which can be used to perform arbitrary database queries. For this example, let's assume we want to do a data cleanup migration on our Galaxy model and delete any galaxies with a mass of 0 . The first step is to create our new migration type. struct GalaxyMassCleanup : # Database # Migration { // ... } In the prepare method of this migration, we will perform a query to delete all galaxies which have a mass equal to 0 . struct GalaxyMassCleanup : # Database # Migration { static func prepare ( on conn : # Database # Connection ) - Future Void { return Galaxy . query ( on : conn ). filter ( \\ . mass == 0 ). delete () } // ... } There is no way to undo this migration since it is destructive. You can omit the revert(...) method by returning a pre-completed future. struct GalaxyMassCleanup : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return conn . future (()) } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in configure.swift . var migrations = MigrationConfig () // ... migrations . add ( migration : GalaxyMassCleanup . self , database : . # dbid # ) services . register ( migrations )","title":"Migrations"},{"location":"fluent/migrations/#fluent-migrations","text":"Migrations allow you to make organized, testable, and reliable changes to your database's structure-- even while it's in production. Migrations are often used for preparing a database schema for your models. However, they can also be used to make normal queries to your database. In this guide we will cover creating both types of migrations.","title":"Fluent Migrations"},{"location":"fluent/migrations/#creating-and-deleting-schemas","text":"Let's take a look at how we can use migrations to prepare a schema supporting database to store a theoretical Galaxy model. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String }","title":"Creating and Deleting Schemas"},{"location":"fluent/migrations/#automatic-model-migrations","text":"Models provide a shortcut for declaring database migrations. If you conform a type that conforms to Model to Migration , Fluent can infer the model's properties and automatically implement the prepare(...) and revert(...) methods. import Fluent # Database # extension Galaxy : # Database # Migration { } This method is especially useful for quick prototyping and simple setups. For most other situations you should consider creating a normal, custom migration. Add this automatic migration to your MigrationConfig using the add(model:database:) method. This is done in configure.swift . var migrations = MigrationConfig () migrations . add ( model : Galaxy . self , database : . # dbid # ) services . register ( migrations ) The add(model:database:) method will automatically set the model's defaultDatabase property.","title":"Automatic Model Migrations"},{"location":"fluent/migrations/#custom-migrations","text":"We can customize the table created for our model by creating a migration and using the static create and delete methods on Database . import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... }","title":"Custom Migrations"},{"location":"fluent/migrations/#creating-a-schema","text":"The most important method in a migration is prepare(...) . This is responsible for effecting the migration's changes. For our CreateGalaxy migration, we will use our database's static create method to create a schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . create ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . id , isIdentifier : true ) builder . field ( for : \\ . name ) } } } To create a schema, you must pass a model type and connection as the first two parameters. The third parameter is a closure that accepts the SchemaBuilder . This builder has convenience methods for declaring fields in the schema. You can use the field(for: #KeyPath# ) method to quickly create fields for each of your model's properties. Since this method accepts key paths to the model (indicated by \\. ), Fluent can see what type those properties are. For most common types ( String , Int , Double , etc) Fluent will automatically be able to determine the best database field type to use. You can also choose to manually select which database field type to use for a given field. try builder . field ( for : \\ . name , type : # DataType # ) Each database has it's own unique data types, so refer to your database's documentation for more information. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDataType MySQL MySQL Getting Started MySQLDataType SQLite SQLite Getting Started SQLiteDataType","title":"Creating a Schema"},{"location":"fluent/migrations/#deleting-a-schema","text":"Each migration should also include a method for reverting the changes it makes. It is used when you boot your app with the --revert option. For a migration that creates a table in the database, the reversion is quite simple: delete the table. To implement revert for our model, we can use our database's static delete(...) method to indicate that we would like to delete the schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func revert ( on connection : # Database # Connection ) - Future Void { return # Database # Database . delete ( Galaxy . self , on : connection ) } } To delete a schema, you pass a model type and connection as the two required parameters. That's it. You can always choose to skip a reversion by simplying returning conn.future(()) . But note that they are especially useful when testing and debugging your migrations. Add this custom migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () migrations . add ( migration : CreateGalaxy . self , database : . # dbid # ) services . register ( migrations ) Make sure to also set the defaultDatabase property on your model when using a custom migration. Galaxy . defaultDatabase = . # dbid #","title":"Deleting a Schema"},{"location":"fluent/migrations/#updating-a-schema","text":"After you deploy your application to production, you may find it necessary to add or remove fields on an existing model. You can achieve this by creating a new migration. For this example, let's assume we want to add a new property mass to the Galaxy model from the previous section. import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String var mass : Int } Since our previous migration created a table with fields for both id and name , we need to update that table and add a field for mass . We can do this by using the static update method on Database . import Fluent # Database # struct AddGalaxyMass : # Database # Migration { // ... } Our prepare method will look very similar to the prepare method for a new table, except it will only contain our newly added field. struct AddGalaxyMass : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . mass ) } } } All methods available when creating a schema will be available while updating alongside some new methods for deleting fields. See SchemaUpdater for a list of all available methods. To revert this change, we must delete the mass field from the table. struct AddGalaxyMass : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . deleteField ( for : \\ . mass ) } } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () // ... migrations . add ( migration : AddGalaxyMass . self , database : . # dbid # ) services . register ( migrations )","title":"Updating a Schema"},{"location":"fluent/migrations/#migrating-data","text":"While migrations are useful for creating and updating schemas in SQL databases, they can also be used for more general purposes in any database. Migrations are passed a connection upon running which can be used to perform arbitrary database queries. For this example, let's assume we want to do a data cleanup migration on our Galaxy model and delete any galaxies with a mass of 0 . The first step is to create our new migration type. struct GalaxyMassCleanup : # Database # Migration { // ... } In the prepare method of this migration, we will perform a query to delete all galaxies which have a mass equal to 0 . struct GalaxyMassCleanup : # Database # Migration { static func prepare ( on conn : # Database # Connection ) - Future Void { return Galaxy . query ( on : conn ). filter ( \\ . mass == 0 ). delete () } // ... } There is no way to undo this migration since it is destructive. You can omit the revert(...) method by returning a pre-completed future. struct GalaxyMassCleanup : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return conn . future (()) } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in configure.swift . var migrations = MigrationConfig () // ... migrations . add ( migration : GalaxyMassCleanup . self , database : . # dbid # ) services . register ( migrations )","title":"Migrating Data"},{"location":"fluent/models/","text":"Fluent Models Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages. Info This guide provides an overview of the Model protocol and its associated methods and properties. If you are just getting started, check out the guide for your database at Fluent Getting Started . Model is a protocol in the Fluent module. It extends the AnyModel protocol which can be used for type-erasure. Conformance Both struct s and class es can conform to Model , however you must pay special attention to Fluent's return types if you use a struct . Since Fluent works asynchronously, any mutations to a value-type ( struct ) model must return a new copy of the model as a future result. Normally, you will conform your model to one of the convenience models available in your database-specific package (i.e., PostgreSQLModel ). However, if you want to customize additional properties, such as the model's idKey , you will want to use the Model protocol itself. Let's take a look at what a basic Model conformance looks like. /// A simple user. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// See `Model.ID` typealias ID = Int /// See `Model.idKey` static let idKey : IDKey = \\ . id /// The unique identifier for this user. var id : Int ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : Int ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } Tip Using final prevents your class from being sub-classed. This makes your life easier. Associated Types Model defines a few associated types that help Fluent create type-safe APIs for you to use. Take a look at AnyModel if you need a type-erased version with no associated types. Database This type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any QueryBuilder s you create with this model. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// ... } It is possible to make this associated type generic by adding a generic type to your class or struct (i.e, User T ). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider. final class User D : Model where D : Database { /// See `Model.Database` typealias Database = D /// ... } You can add further conditions to D , such as QuerySupporting or SchemaSupporting . You can also dynamically extend and conform your generic model using extension User where D: ... { } . That said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver. ID This property defines the type your model will use for its unique identifier. final class User : Model { /// See `Model.ID` typealias ID = UUID /// ... } This will usually be something like Int , UUID , or String although you can theoretically use any type you like. Properties There are several overridable properties on Model that you can use to customize how Fluent interacts with your database. Name This String will be used as a unique identifier for your model whenever Fluent needs one. final class User : Model { /// See `Model.name` static let name = user /// ... } By default, this is the type name of your model. Entity Entity is a generic word used to mean either \"table\" or \"collection\", depending on which type of backend you are using for Fluent. final class Goose : Model { /// See `Model.entity` static let entity = geese /// ... } By default, this property will be name . ID Key The ID key is a writeable key path that points to your model's unique identifier property. Usually this will be a property named id (for some databases it is _id ). However you can theoretically use any key you like. final class User : Model { /// See `Model.ID` typealias ID = String /// See `Model.entity` static let idKey = \\ . username /// The user s unique username var username : String ? /// ... } The idKey property must point to an optional, writeable ( var ) property with type matching ID . Lifecycle There are several lifecycle methods on Model that you can override to hook into Fluent events. method description throwing willCreate Called before Fluent saves your model (for the first time) Cancels the save. didCreate Called after Fluent saves your model (for the first time) Save completes. Query fails. willUpdate Called before Fluent saves your model (subsequent saves) Cancels the save. didUpdate Called after Fluent saves your model (subsequent saves) Save completes. Query fails. willRead Called before Fluent returns your model from a fetch query. Cancels the fetch. willDelete Called before Fluent deletes your model. Cancels the delete. Here's an example of overriding the willUpdate(on:) method. final class User : Model { /// ... /// See `Model.willUpdate(on:)` func willUpdate ( on connection : Database . Connection ) throws - Future Self { /// Throws an error if the username is invalid try validateUsername () /// Return the user. No async work is being done, so we must create a future manually. return Future . map ( on : connection ) { self } } } CRUD The model offers basic CRUD method (create, read, update, delete). Create This method creates a new row / item for an instance of your model in the database. If your model does not have an ID, calls to .save(on:) will redirect to this method. let didCreate = user . create ( on : req ) print ( didCreate ) /// Future User Info If you are using a value-type ( struct ), the instance of your model returned by .create(on:) will contain the model's new ID. Read Two methods are important for reading your model from the database, find(_:on:) and query(on:) . /// Finds a user with ID == 1 let user = User . find ( 1 , on : req ) print ( user ) /// Future User? /// Finds all users with name == Vapor let users = User . query ( on : req ). filter ( \\ . name == Vapor ). all () print ( users ) /// Future [User] Update This method updates the existing row / item associated with an instance of your model in the database. If your model already has an ID, calls to .save(on:) will redirect to this method. /// Updates the user let didUpdate = user . update ( on : req ) print ( didUpdate ) /// Future User Delete This method deletes the existing row / item associated with an instance of your model from the database. /// Deletes the user let didDelete = user . delete ( on : req ) print ( didDelete ) /// Future Void Methods Model offers some convenience methods to make working with it easier. Require ID This method return's the models ID or throws an error. let id = try user . requireID ()","title":"Models"},{"location":"fluent/models/#fluent-models","text":"Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages. Info This guide provides an overview of the Model protocol and its associated methods and properties. If you are just getting started, check out the guide for your database at Fluent Getting Started . Model is a protocol in the Fluent module. It extends the AnyModel protocol which can be used for type-erasure.","title":"Fluent Models"},{"location":"fluent/models/#conformance","text":"Both struct s and class es can conform to Model , however you must pay special attention to Fluent's return types if you use a struct . Since Fluent works asynchronously, any mutations to a value-type ( struct ) model must return a new copy of the model as a future result. Normally, you will conform your model to one of the convenience models available in your database-specific package (i.e., PostgreSQLModel ). However, if you want to customize additional properties, such as the model's idKey , you will want to use the Model protocol itself. Let's take a look at what a basic Model conformance looks like. /// A simple user. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// See `Model.ID` typealias ID = Int /// See `Model.idKey` static let idKey : IDKey = \\ . id /// The unique identifier for this user. var id : Int ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : Int ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } Tip Using final prevents your class from being sub-classed. This makes your life easier.","title":"Conformance"},{"location":"fluent/models/#associated-types","text":"Model defines a few associated types that help Fluent create type-safe APIs for you to use. Take a look at AnyModel if you need a type-erased version with no associated types.","title":"Associated Types"},{"location":"fluent/models/#database","text":"This type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any QueryBuilder s you create with this model. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// ... } It is possible to make this associated type generic by adding a generic type to your class or struct (i.e, User T ). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider. final class User D : Model where D : Database { /// See `Model.Database` typealias Database = D /// ... } You can add further conditions to D , such as QuerySupporting or SchemaSupporting . You can also dynamically extend and conform your generic model using extension User where D: ... { } . That said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver.","title":"Database"},{"location":"fluent/models/#id","text":"This property defines the type your model will use for its unique identifier. final class User : Model { /// See `Model.ID` typealias ID = UUID /// ... } This will usually be something like Int , UUID , or String although you can theoretically use any type you like.","title":"ID"},{"location":"fluent/models/#properties","text":"There are several overridable properties on Model that you can use to customize how Fluent interacts with your database.","title":"Properties"},{"location":"fluent/models/#name","text":"This String will be used as a unique identifier for your model whenever Fluent needs one. final class User : Model { /// See `Model.name` static let name = user /// ... } By default, this is the type name of your model.","title":"Name"},{"location":"fluent/models/#entity","text":"Entity is a generic word used to mean either \"table\" or \"collection\", depending on which type of backend you are using for Fluent. final class Goose : Model { /// See `Model.entity` static let entity = geese /// ... } By default, this property will be name .","title":"Entity"},{"location":"fluent/models/#id-key","text":"The ID key is a writeable key path that points to your model's unique identifier property. Usually this will be a property named id (for some databases it is _id ). However you can theoretically use any key you like. final class User : Model { /// See `Model.ID` typealias ID = String /// See `Model.entity` static let idKey = \\ . username /// The user s unique username var username : String ? /// ... } The idKey property must point to an optional, writeable ( var ) property with type matching ID .","title":"ID Key"},{"location":"fluent/models/#lifecycle","text":"There are several lifecycle methods on Model that you can override to hook into Fluent events. method description throwing willCreate Called before Fluent saves your model (for the first time) Cancels the save. didCreate Called after Fluent saves your model (for the first time) Save completes. Query fails. willUpdate Called before Fluent saves your model (subsequent saves) Cancels the save. didUpdate Called after Fluent saves your model (subsequent saves) Save completes. Query fails. willRead Called before Fluent returns your model from a fetch query. Cancels the fetch. willDelete Called before Fluent deletes your model. Cancels the delete. Here's an example of overriding the willUpdate(on:) method. final class User : Model { /// ... /// See `Model.willUpdate(on:)` func willUpdate ( on connection : Database . Connection ) throws - Future Self { /// Throws an error if the username is invalid try validateUsername () /// Return the user. No async work is being done, so we must create a future manually. return Future . map ( on : connection ) { self } } }","title":"Lifecycle"},{"location":"fluent/models/#crud","text":"The model offers basic CRUD method (create, read, update, delete).","title":"CRUD"},{"location":"fluent/models/#create","text":"This method creates a new row / item for an instance of your model in the database. If your model does not have an ID, calls to .save(on:) will redirect to this method. let didCreate = user . create ( on : req ) print ( didCreate ) /// Future User Info If you are using a value-type ( struct ), the instance of your model returned by .create(on:) will contain the model's new ID.","title":"Create"},{"location":"fluent/models/#read","text":"Two methods are important for reading your model from the database, find(_:on:) and query(on:) . /// Finds a user with ID == 1 let user = User . find ( 1 , on : req ) print ( user ) /// Future User? /// Finds all users with name == Vapor let users = User . query ( on : req ). filter ( \\ . name == Vapor ). all () print ( users ) /// Future [User]","title":"Read"},{"location":"fluent/models/#update","text":"This method updates the existing row / item associated with an instance of your model in the database. If your model already has an ID, calls to .save(on:) will redirect to this method. /// Updates the user let didUpdate = user . update ( on : req ) print ( didUpdate ) /// Future User","title":"Update"},{"location":"fluent/models/#delete","text":"This method deletes the existing row / item associated with an instance of your model from the database. /// Deletes the user let didDelete = user . delete ( on : req ) print ( didDelete ) /// Future Void","title":"Delete"},{"location":"fluent/models/#methods","text":"Model offers some convenience methods to make working with it easier.","title":"Methods"},{"location":"fluent/models/#require-id","text":"This method return's the models ID or throws an error. let id = try user . requireID ()","title":"Require ID"},{"location":"fluent/querying/","text":"Fluent Queries Once you have a model you can start querying your database to create, read, update, and delete data. Connection The first thing you need to query your database, is a connection to it. Luckily, they are easy to get. Request The easiest way to connect to your database is simply using the incoming Request . This will use the model's defaultDatabase property to automatically fetch a pooled connection to the database. router . get ( galaxies ) { req in return Galaxy . query ( on : req ). all () } You can use convenience methods on a Container to create connections manually. Learn more about that in DatabaseKit Overview Connections . Create One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling create(on:) . router . post ( galaxies ) { req in let galaxy : Galaxy = ... return galaxy . create ( on : req ) } The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values. If your model also conforms to Content you can return the result of the Fluent query directly. Read To read models from the database, you can use query(on:) or find(_:on:) . Find The easiest way to find a single model is by passing its ID to find(_:on:) . Galaxy . find ( 42 , on : conn ) The result will be a future containing an optional value. You can use unwrap(or:) to unwrap the future value or throw an error. Galaxy . find ( 42 , on : conn ). unwrap ( or : Abort (...)) Query You can use the query(on:) method to build database queries with filters, joins, sorts, and more. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way ) Filter The filter(_:) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries. Calls to filter can be chained and even grouped. Galaxy . query ( on : conn ). filter ( \\ . mass = 500 ). filter ( \\ . type == . spiral ) Below is a list of all supported operators. operator type == Equal != Not equal Greater than Less than = Greater than or equal = Less than or equal By default, all chained filters will be used to limit the result set. You can use filter groups to change this behavior. Galaxy . query ( on : conn ). group (. or ) { $0 . filter ( \\ . mass = 250 ). filter ( \\ . mass = 500 ) }. filter ( \\ . type == . spiral ) The above query will include results where the galaxy's mass is below 250 or above 500 and the type is spiral. Range You can apply Swift ranges to a query builder to limit the result set. Galaxy . query ( on : conn ). range (.. 50 ) The above query will include only the first 50 results. For more information on ranges, see docs for Swift's Range type. Sort Query results can be sorted by a given field. Galaxy . query ( on : conn ). sort ( \\ . name , . descending ) You can sort by multiple fields to perform tie breaking behavior where there is duplicate information in the one of the sorted fields. Join Other models can be joined to an existing query in order to further filter the results. Galaxy . query ( on : conn ). join ( \\ Planet . galaxyID , to : \\ Galaxy . id ) . filter ( \\ Planet . name == Earth ) Once a table has been joined using join(_:to:) , you can use fully-qualified key paths to filter results based on data in the joined table. The above query fetches all galaxies that have a planet named Earth. You can even decode the joined models using alsoDecode(...) . Galaxy . query ( on : conn ) // join Planet and filter . alsoDecode ( Planet . self ). all () The above query will decode an array of (Galaxy, Planet) tuples. Fetch To fetch the results of a query, use all() , chunk(max:closure:) , first() or an aggregate method. All The most common method for fetching results is with all() . This will return all matching results according to any fliters applied. Galaxy . query ( on : conn ). all () When combined with range(_:) , you can efficiently limit how many results are returned by the database. Galaxy . query ( on : conn ). range (.. 50 ). all () Chunk For situations where memory conservation is important, use chunk(...) . This method returns the result set in multiple calls of a maximum chunk size. Galaxy . query ( on : conn ). chunk ( max : 32 ) { galaxies in print ( galaxies ) // Array of 32 or less galaxies } First The first() method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way ). first () This method is more efficient than calling all and getting the first item in the array. Update After a model has been fetched from the database and mutated, you can use update(on:) to save the changes. var planet : Planet ... // fetched from database planet . name = Earth planet . update ( on : conn ) Delete After a model has been fetched from the database, you can use delete(on:) to delete it. var planet : Planet ... // fetched from database planet . delete ( on : conn )","title":"Querying"},{"location":"fluent/querying/#fluent-queries","text":"Once you have a model you can start querying your database to create, read, update, and delete data.","title":"Fluent Queries"},{"location":"fluent/querying/#connection","text":"The first thing you need to query your database, is a connection to it. Luckily, they are easy to get.","title":"Connection"},{"location":"fluent/querying/#request","text":"The easiest way to connect to your database is simply using the incoming Request . This will use the model's defaultDatabase property to automatically fetch a pooled connection to the database. router . get ( galaxies ) { req in return Galaxy . query ( on : req ). all () } You can use convenience methods on a Container to create connections manually. Learn more about that in DatabaseKit Overview Connections .","title":"Request"},{"location":"fluent/querying/#create","text":"One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling create(on:) . router . post ( galaxies ) { req in let galaxy : Galaxy = ... return galaxy . create ( on : req ) } The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values. If your model also conforms to Content you can return the result of the Fluent query directly.","title":"Create"},{"location":"fluent/querying/#read","text":"To read models from the database, you can use query(on:) or find(_:on:) .","title":"Read"},{"location":"fluent/querying/#find","text":"The easiest way to find a single model is by passing its ID to find(_:on:) . Galaxy . find ( 42 , on : conn ) The result will be a future containing an optional value. You can use unwrap(or:) to unwrap the future value or throw an error. Galaxy . find ( 42 , on : conn ). unwrap ( or : Abort (...))","title":"Find"},{"location":"fluent/querying/#query","text":"You can use the query(on:) method to build database queries with filters, joins, sorts, and more. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way )","title":"Query"},{"location":"fluent/querying/#filter","text":"The filter(_:) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries. Calls to filter can be chained and even grouped. Galaxy . query ( on : conn ). filter ( \\ . mass = 500 ). filter ( \\ . type == . spiral ) Below is a list of all supported operators. operator type == Equal != Not equal Greater than Less than = Greater than or equal = Less than or equal By default, all chained filters will be used to limit the result set. You can use filter groups to change this behavior. Galaxy . query ( on : conn ). group (. or ) { $0 . filter ( \\ . mass = 250 ). filter ( \\ . mass = 500 ) }. filter ( \\ . type == . spiral ) The above query will include results where the galaxy's mass is below 250 or above 500 and the type is spiral.","title":"Filter"},{"location":"fluent/querying/#range","text":"You can apply Swift ranges to a query builder to limit the result set. Galaxy . query ( on : conn ). range (.. 50 ) The above query will include only the first 50 results. For more information on ranges, see docs for Swift's Range type.","title":"Range"},{"location":"fluent/querying/#sort","text":"Query results can be sorted by a given field. Galaxy . query ( on : conn ). sort ( \\ . name , . descending ) You can sort by multiple fields to perform tie breaking behavior where there is duplicate information in the one of the sorted fields.","title":"Sort"},{"location":"fluent/querying/#join","text":"Other models can be joined to an existing query in order to further filter the results. Galaxy . query ( on : conn ). join ( \\ Planet . galaxyID , to : \\ Galaxy . id ) . filter ( \\ Planet . name == Earth ) Once a table has been joined using join(_:to:) , you can use fully-qualified key paths to filter results based on data in the joined table. The above query fetches all galaxies that have a planet named Earth. You can even decode the joined models using alsoDecode(...) . Galaxy . query ( on : conn ) // join Planet and filter . alsoDecode ( Planet . self ). all () The above query will decode an array of (Galaxy, Planet) tuples.","title":"Join"},{"location":"fluent/querying/#fetch","text":"To fetch the results of a query, use all() , chunk(max:closure:) , first() or an aggregate method.","title":"Fetch"},{"location":"fluent/querying/#all","text":"The most common method for fetching results is with all() . This will return all matching results according to any fliters applied. Galaxy . query ( on : conn ). all () When combined with range(_:) , you can efficiently limit how many results are returned by the database. Galaxy . query ( on : conn ). range (.. 50 ). all ()","title":"All"},{"location":"fluent/querying/#chunk","text":"For situations where memory conservation is important, use chunk(...) . This method returns the result set in multiple calls of a maximum chunk size. Galaxy . query ( on : conn ). chunk ( max : 32 ) { galaxies in print ( galaxies ) // Array of 32 or less galaxies }","title":"Chunk"},{"location":"fluent/querying/#first","text":"The first() method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way ). first () This method is more efficient than calling all and getting the first item in the array.","title":"First"},{"location":"fluent/querying/#update","text":"After a model has been fetched from the database and mutated, you can use update(on:) to save the changes. var planet : Planet ... // fetched from database planet . name = Earth planet . update ( on : conn )","title":"Update"},{"location":"fluent/querying/#delete","text":"After a model has been fetched from the database, you can use delete(on:) to delete it. var planet : Planet ... // fetched from database planet . delete ( on : conn )","title":"Delete"},{"location":"fluent/relations/","text":"Fluent Relations Fluent supports two methods for relating models: one-to-many (parent-child) and many-to-many (siblings). These relations help make working with a normalized data structure easy. Parent-Child The most common model relation is the one-to-many or parent-child relation. In this relation, each child model stores at most one identifier of a parent model. In most cases, multiple child models can store the same parent identifier at the same time. This means that any given parent can have zero or more related child models. Hence the name, one (parent) to many (children). Note If each child must store a unique parent ID, this relation is called a one-to-one relation. Take a look at the following diagram in which an example parent-child relation between two models ( Galaxy and Planet ) is shown. In the example above, Galaxy is the parent and Planet is the child. Planets store an identifier referencing exactly one galaxy (the galaxy they are in). In turn, each galaxy has zero or more planets that belong to it. Let's take a look at what these models would look like in Fluent. struct Galaxy : Model { // ... var id : Int ? var name : String } struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } For more information on defining models see Fluent Models . Fluent provides two helpers for working with parent-child relations: Parent and Children . These helpers can be created using extensions on the related models for convenient access. extension Galaxy { // this galaxy s related planets var planets : Children Galaxy , Planet { return children ( \\ . galaxyID ) } } Here the children(_:) method is used on Galaxy to create the relation. The resulting type has two generic arguments in the signature that can be thought of as From, To . Since this relation goes from galaxy to planet, they are ordered as such in the generic arguments. Note that this method is not static. That is because it must access the galaxy's identifier to perform the relation lookup. extension Planet { // this planet s related galaxy var galaxy : Parent Planet , Galaxy { return parent ( \\ . galaxyID ) } } Here the parent(_:) method is used on Planet to create the inverse relation. The resulting type also has two generic arguments. In this case, they are reversed since this relation now goes from planet to galaxy. Note that this method is also not static. That is because it must access the referenced identifier to perform the relation lookup. Now that the models and relation properties are created, they can be used to create, read, update, and delete related data. let galaxy : Galaxy = ... let planets = galaxy . planets . query ( on : ...). all () The query(on:) method on a relation creates an instance of QueryBuilder filtered to the related models. See Fluent Querying for more information on working with the query builder. let planet : Planet = ... let galaxy = planet . galaxy . get ( on : ...) Since the child can have at most one parent, the most useful method is [ get(on:) ] which simply returns the parent model. Siblings A more powerful (and complex) relation is the many-to-many or siblings relation. In this relation, two models are related by a third model called a pivot . The pivot is a simple model that carries one identifier for each of the two related models. Because a third model (the pivot) stores identifiers, each model can be related to zero or more models on the other side of the relation. Take a look at the following diagram in which an example siblings relation between two models ( Planet and Tag ) and a pivot ( PlanetTag ) is shown. A siblings relation is required for the above example because: Both Earth and Venus have the Earth Sized tag. Earth has both the Earth Sized and Liquid Water tag. In other words, two planets can share one tag and two tags can share one planet. This is a many-to-many relation. Let's take a look at what these models would look like in Fluent. struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } struct Tag : Model { // ... var id : Int ? var name : String } For more information on defining models see Fluent Models . Now let's take a look at the pivot. It may seem a bit intimidating at first, but it's really quite simple. struct PlanetTag : Pivot { // ... typealias Left = Planet typealias Right = Tag static var leftIDKey : LeftIDKey = \\ . planetID static var rightIDKey : RightIDKey = \\ . tagID var id : Int ? var planetID : Int var tagID : Int } A pivot must have Left and Right model types. In this case, those model types are Planet and Tag . Although it is arbitrary which model is left vs. right, a good rule of thumb is to order things alphabetically for consistency. Once the left and right models are defined, we must supply Fluent with key paths to the stored properties for each ID. We can use the LeftIDKey and RightIDKey type-aliases to do this. A Pivot is also a Model itself. You are free to store any additional properties here if you like. Don't forget to create a migration for it if you are using a database that supports schemas. Once the pivot and your models are created, you can add convenience extensions for interacting with the relation just like the parent-child relation. extension Planet { // this planet s related tags var tags : Siblings Planet , Tag , PlanetTag { return siblings () } } Because the siblings relation requires three models, it has three generic arguments. You can think of the arguments as From, To, Through . This relation goes from a planet to tags through the planet tag pivot. The other side of the relation (on tag) is similar. Only the first two generic arguments are flipped. extension Tag { // all planets that have this tag var planets : Siblings Tag , Planet , PlanetTag { return siblings () } } Now that the relations are setup, we can query a planet's tags. This works just like the Children type in the parent-child relationship. let planet : Planet = ... planet . tags . query ( on : ...). all () Modifiable Pivot If the pivot conforms to ModifiablePivot , then Fluent can help to create and delete pivots (called attaching and detaching). Conforming a pivot is fairly simple. Fluent just needs to be able to initialize the pivot from two related models. extension PlanetTag : ModifiablePivot { init ( _ planet : Planet , _ tag : Tag ) throws { planetID = try planet . requireID () tagID = try tag . requireID () } } Once the pivot type conforms, there will be extra methods available on the siblings relation. let planet : Planet = ... let tag : Tag = ... planet . tags . attach ( tag , on : ...)","title":"Relations"},{"location":"fluent/relations/#fluent-relations","text":"Fluent supports two methods for relating models: one-to-many (parent-child) and many-to-many (siblings). These relations help make working with a normalized data structure easy.","title":"Fluent Relations"},{"location":"fluent/relations/#parent-child","text":"The most common model relation is the one-to-many or parent-child relation. In this relation, each child model stores at most one identifier of a parent model. In most cases, multiple child models can store the same parent identifier at the same time. This means that any given parent can have zero or more related child models. Hence the name, one (parent) to many (children). Note If each child must store a unique parent ID, this relation is called a one-to-one relation. Take a look at the following diagram in which an example parent-child relation between two models ( Galaxy and Planet ) is shown. In the example above, Galaxy is the parent and Planet is the child. Planets store an identifier referencing exactly one galaxy (the galaxy they are in). In turn, each galaxy has zero or more planets that belong to it. Let's take a look at what these models would look like in Fluent. struct Galaxy : Model { // ... var id : Int ? var name : String } struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } For more information on defining models see Fluent Models . Fluent provides two helpers for working with parent-child relations: Parent and Children . These helpers can be created using extensions on the related models for convenient access. extension Galaxy { // this galaxy s related planets var planets : Children Galaxy , Planet { return children ( \\ . galaxyID ) } } Here the children(_:) method is used on Galaxy to create the relation. The resulting type has two generic arguments in the signature that can be thought of as From, To . Since this relation goes from galaxy to planet, they are ordered as such in the generic arguments. Note that this method is not static. That is because it must access the galaxy's identifier to perform the relation lookup. extension Planet { // this planet s related galaxy var galaxy : Parent Planet , Galaxy { return parent ( \\ . galaxyID ) } } Here the parent(_:) method is used on Planet to create the inverse relation. The resulting type also has two generic arguments. In this case, they are reversed since this relation now goes from planet to galaxy. Note that this method is also not static. That is because it must access the referenced identifier to perform the relation lookup. Now that the models and relation properties are created, they can be used to create, read, update, and delete related data. let galaxy : Galaxy = ... let planets = galaxy . planets . query ( on : ...). all () The query(on:) method on a relation creates an instance of QueryBuilder filtered to the related models. See Fluent Querying for more information on working with the query builder. let planet : Planet = ... let galaxy = planet . galaxy . get ( on : ...) Since the child can have at most one parent, the most useful method is [ get(on:) ] which simply returns the parent model.","title":"Parent-Child"},{"location":"fluent/relations/#siblings","text":"A more powerful (and complex) relation is the many-to-many or siblings relation. In this relation, two models are related by a third model called a pivot . The pivot is a simple model that carries one identifier for each of the two related models. Because a third model (the pivot) stores identifiers, each model can be related to zero or more models on the other side of the relation. Take a look at the following diagram in which an example siblings relation between two models ( Planet and Tag ) and a pivot ( PlanetTag ) is shown. A siblings relation is required for the above example because: Both Earth and Venus have the Earth Sized tag. Earth has both the Earth Sized and Liquid Water tag. In other words, two planets can share one tag and two tags can share one planet. This is a many-to-many relation. Let's take a look at what these models would look like in Fluent. struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } struct Tag : Model { // ... var id : Int ? var name : String } For more information on defining models see Fluent Models . Now let's take a look at the pivot. It may seem a bit intimidating at first, but it's really quite simple. struct PlanetTag : Pivot { // ... typealias Left = Planet typealias Right = Tag static var leftIDKey : LeftIDKey = \\ . planetID static var rightIDKey : RightIDKey = \\ . tagID var id : Int ? var planetID : Int var tagID : Int } A pivot must have Left and Right model types. In this case, those model types are Planet and Tag . Although it is arbitrary which model is left vs. right, a good rule of thumb is to order things alphabetically for consistency. Once the left and right models are defined, we must supply Fluent with key paths to the stored properties for each ID. We can use the LeftIDKey and RightIDKey type-aliases to do this. A Pivot is also a Model itself. You are free to store any additional properties here if you like. Don't forget to create a migration for it if you are using a database that supports schemas. Once the pivot and your models are created, you can add convenience extensions for interacting with the relation just like the parent-child relation. extension Planet { // this planet s related tags var tags : Siblings Planet , Tag , PlanetTag { return siblings () } } Because the siblings relation requires three models, it has three generic arguments. You can think of the arguments as From, To, Through . This relation goes from a planet to tags through the planet tag pivot. The other side of the relation (on tag) is similar. Only the first two generic arguments are flipped. extension Tag { // all planets that have this tag var planets : Siblings Tag , Planet , PlanetTag { return siblings () } } Now that the relations are setup, we can query a planet's tags. This works just like the Children type in the parent-child relationship. let planet : Planet = ... planet . tags . query ( on : ...). all ()","title":"Siblings"},{"location":"fluent/relations/#modifiable-pivot","text":"If the pivot conforms to ModifiablePivot , then Fluent can help to create and delete pivots (called attaching and detaching). Conforming a pivot is fairly simple. Fluent just needs to be able to initialize the pivot from two related models. extension PlanetTag : ModifiablePivot { init ( _ planet : Planet , _ tag : Tag ) throws { planetID = try planet . requireID () tagID = try tag . requireID () } } Once the pivot type conforms, there will be extra methods available on the siblings relation. let planet : Planet = ... let tag : Tag = ... planet . tags . attach ( tag , on : ...)","title":"Modifiable Pivot"},{"location":"fluent/transaction/","text":"Fluent Transactions Transactions allow you to ensure multiple operations complete succesfully before saving data to your database. Once a transaction is started, you may run Fluent queries normally. However, no data will be saved to the database until the transaction completes. If an error is thrown at any point during the transaction (by you or the database), none of the changes will take effect. To perform a transaction, you need access to something that can connect to the database. This is usually an incoming HTTP request. Use the transaction(on:_:) method. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . req . transaction ( on : . # dbid # ) { conn in // use conn as your connection } Once inside the transaction closure, you must use the supplied connection (named conn in the example) to perform queries. The closure expects a generic future return value. Once this future completes succesfully, the transaction will be committed. var userA : User = ... var userB : User = ... return req . transaction ( on : . # dbid # ) { conn in return userA . save ( on : conn ). flatMap { _ in return userB . save ( on : conn ) }. transform ( to : HTTPStatus . ok ) } The above example will save User A then User B before completing the transaction. If either user fails to save, neither will save. Once the transaction has completed, the result is transformed to a simple HTTP status response indicating completion.","title":"Transaction"},{"location":"fluent/transaction/#fluent-transactions","text":"Transactions allow you to ensure multiple operations complete succesfully before saving data to your database. Once a transaction is started, you may run Fluent queries normally. However, no data will be saved to the database until the transaction completes. If an error is thrown at any point during the transaction (by you or the database), none of the changes will take effect. To perform a transaction, you need access to something that can connect to the database. This is usually an incoming HTTP request. Use the transaction(on:_:) method. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . req . transaction ( on : . # dbid # ) { conn in // use conn as your connection } Once inside the transaction closure, you must use the supplied connection (named conn in the example) to perform queries. The closure expects a generic future return value. Once this future completes succesfully, the transaction will be committed. var userA : User = ... var userB : User = ... return req . transaction ( on : . # dbid # ) { conn in return userA . save ( on : conn ). flatMap { _ in return userB . save ( on : conn ) }. transform ( to : HTTPStatus . ok ) } The above example will save User A then User B before completing the transaction. If either user fails to save, neither will save. Once the transaction has completed, the result is transformed to a simple HTTP status response indicating completion.","title":"Fluent Transactions"},{"location":"getting-started/application/","text":"Application Every Vapor project has an Application . You use the application to run your server and create any services you might need at boot time. The best place to access the application is in your project's boot.swift file. import Vapor public func boot ( _ app : Application ) throws { // your code here } Unlike some other web frameworks, Vapor doesn't support statically accessing the application. If you need to access it from another class or struct, you should pass through a method or initializer. Info Avoiding static access to variables helps make Vapor performant by preventing the need for thread-safe locks or semaphores. Services The application's main function is to boot your server. try app . run () However, the application is also a container. You may use it to create services required to boot your application. Warning Do not use the application, or any services created from it, inside a route closure. Use the Request to create services instead. let client = try app . make ( Client . self ) let res = try client . get ( http://vapor.codes ). wait () print ( res ) // Response Tip It's okay to use .wait() here instead of .map / .flatMap because we are not inside of a route closure. Learn more about services in Getting Started Services .","title":"Application"},{"location":"getting-started/application/#application","text":"Every Vapor project has an Application . You use the application to run your server and create any services you might need at boot time. The best place to access the application is in your project's boot.swift file. import Vapor public func boot ( _ app : Application ) throws { // your code here } Unlike some other web frameworks, Vapor doesn't support statically accessing the application. If you need to access it from another class or struct, you should pass through a method or initializer. Info Avoiding static access to variables helps make Vapor performant by preventing the need for thread-safe locks or semaphores.","title":"Application"},{"location":"getting-started/application/#services","text":"The application's main function is to boot your server. try app . run () However, the application is also a container. You may use it to create services required to boot your application. Warning Do not use the application, or any services created from it, inside a route closure. Use the Request to create services instead. let client = try app . make ( Client . self ) let res = try client . get ( http://vapor.codes ). wait () print ( res ) // Response Tip It's okay to use .wait() here instead of .map / .flatMap because we are not inside of a route closure. Learn more about services in Getting Started Services .","title":"Services"},{"location":"getting-started/async/","text":"Async You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. This guide will give you a quick introduction to working with Async. Check out Async \u2192 Overview for more information. Futures Since Future s work asynchronously, we must use closures to interact with and transform their values. Just like optionals in Swift, futures can be mapped and flat-mapped. Map The .map(to:_:) method allows you to transform the future's value to another value. The closure provided will be called once the Future 's data becomes available. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int Flat Map The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes! Chaining The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown. Worker You may see methods in Vapor that have an on: Worker parameter. These are usually methods that perform asynchronous work and require access to the EventLoop . The most common Worker s you will interact with in Vapor are: Application Request Response /// Assume we have a Request and some ViewRenderer let req : Request = ... let view : ViewRenderer = ... /// Render the view, using the Request as a worker. /// This ensures the async work happens on the correct event loop. /// /// This assumes the signature is: /// func render(_: String, on: Worker) view . render ( home.html , on : req )","title":"Async"},{"location":"getting-started/async/#async","text":"You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. This guide will give you a quick introduction to working with Async. Check out Async \u2192 Overview for more information.","title":"Async"},{"location":"getting-started/async/#futures","text":"Since Future s work asynchronously, we must use closures to interact with and transform their values. Just like optionals in Swift, futures can be mapped and flat-mapped.","title":"Futures"},{"location":"getting-started/async/#map","text":"The .map(to:_:) method allows you to transform the future's value to another value. The closure provided will be called once the Future 's data becomes available. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int","title":"Map"},{"location":"getting-started/async/#flat-map","text":"The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes!","title":"Flat Map"},{"location":"getting-started/async/#chaining","text":"The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown.","title":"Chaining"},{"location":"getting-started/async/#worker","text":"You may see methods in Vapor that have an on: Worker parameter. These are usually methods that perform asynchronous work and require access to the EventLoop . The most common Worker s you will interact with in Vapor are: Application Request Response /// Assume we have a Request and some ViewRenderer let req : Request = ... let view : ViewRenderer = ... /// Render the view, using the Request as a worker. /// This ensures the async work happens on the correct event loop. /// /// This assumes the signature is: /// func render(_: String, on: Worker) view . render ( home.html , on : req )","title":"Worker"},{"location":"getting-started/cache/","text":"TODO","title":"Cache"},{"location":"getting-started/cloud/","text":"Deployment Deploying code is the process of making your Vapor project publically available. It can be one of the most difficult aspects of web development. Fortunately, there are services to help. Vapor Cloud The best way to deploy your application is through Vapor Cloud. It's a cloud platform built specifically for the Vapor web framework. This means it's incredibly easy to deploy your project quickly and be confident that it will be fast and stable. Deploying your project to Vapor Cloud is simple, it's built right into the Vapor Toolbox . Just run this command from within the root directory of your project. vapor cloud deploy For a detailed guide, visit Vapor Cloud Quick Start . Other Options Vapor can be deployed anywhere that supports Ubuntu (basically everywhere). Guides on deploying to other systems are coming soon (contributions welcome)!","title":"Deployment"},{"location":"getting-started/cloud/#deployment","text":"Deploying code is the process of making your Vapor project publically available. It can be one of the most difficult aspects of web development. Fortunately, there are services to help.","title":"Deployment"},{"location":"getting-started/cloud/#vapor-cloud","text":"The best way to deploy your application is through Vapor Cloud. It's a cloud platform built specifically for the Vapor web framework. This means it's incredibly easy to deploy your project quickly and be confident that it will be fast and stable. Deploying your project to Vapor Cloud is simple, it's built right into the Vapor Toolbox . Just run this command from within the root directory of your project. vapor cloud deploy For a detailed guide, visit Vapor Cloud Quick Start .","title":"Vapor Cloud"},{"location":"getting-started/cloud/#other-options","text":"Vapor can be deployed anywhere that supports Ubuntu (basically everywhere). Guides on deploying to other systems are coming soon (contributions welcome)!","title":"Other Options"},{"location":"getting-started/content/","text":"Content In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use JSON as an example. But keep in mind the API is the same for any supported content type. Request Let's take a look at how you would parse the following HTTP request. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Then simply conform this struct or class to Content . Now we are ready to decode that HTTP request. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map ( to : HTTPStatus . self ) { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return . ok } } We use .map(to:) here since req.content.decode(_:) returns a future . Response Let's take a look at how you would create the following HTTP response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content . Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } Great job! Now you know how to encode and decode data in Vapor. Tip See Vapor Content for more in-depth information. The next section in this guide is Async .","title":"Content"},{"location":"getting-started/content/#content","text":"In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use JSON as an example. But keep in mind the API is the same for any supported content type.","title":"Content"},{"location":"getting-started/content/#request","text":"Let's take a look at how you would parse the following HTTP request. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Then simply conform this struct or class to Content . Now we are ready to decode that HTTP request. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map ( to : HTTPStatus . self ) { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return . ok } } We use .map(to:) here since req.content.decode(_:) returns a future .","title":"Request"},{"location":"getting-started/content/#response","text":"Let's take a look at how you would create the following HTTP response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content . Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } Great job! Now you know how to encode and decode data in Vapor. Tip See Vapor Content for more in-depth information. The next section in this guide is Async .","title":"Response"},{"location":"getting-started/controllers/","text":"Controllers Controllers are a great way to organize your code. They are collections of methods that accept a request and return a response. A good place to put your controllers is in the Controllers folder. Methods Let's take a look at an example controller. import Vapor final class HelloController { func greet ( _ req : Request ) throws - String { return Hello! } } Controller methods should always accept a Request and return something ResponseEncodable . Note Futures whose expectations are ResponseEncodable (i.e, Future String ) are also ResponseEncodable . To use this controller, we can simply initialize it, then pass the method to a router. let helloController = HelloController () router . get ( greet , use : helloController . greet ) Using Services You will probably want to access your services from within your controllers. Just use the Request as a container to create services from within your route closures. Vapor will take care of caching the services. final class HelloController { func greet ( _ req : Request ) throws - String { return try req . make ( BCryptHasher . self ). hash ( hello ) } }","title":"Controllers"},{"location":"getting-started/controllers/#controllers","text":"Controllers are a great way to organize your code. They are collections of methods that accept a request and return a response. A good place to put your controllers is in the Controllers folder.","title":"Controllers"},{"location":"getting-started/controllers/#methods","text":"Let's take a look at an example controller. import Vapor final class HelloController { func greet ( _ req : Request ) throws - String { return Hello! } } Controller methods should always accept a Request and return something ResponseEncodable . Note Futures whose expectations are ResponseEncodable (i.e, Future String ) are also ResponseEncodable . To use this controller, we can simply initialize it, then pass the method to a router. let helloController = HelloController () router . get ( greet , use : helloController . greet )","title":"Methods"},{"location":"getting-started/controllers/#using-services","text":"You will probably want to access your services from within your controllers. Just use the Request as a container to create services from within your route closures. Vapor will take care of caching the services. final class HelloController { func greet ( _ req : Request ) throws - String { return try req . make ( BCryptHasher . self ). hash ( hello ) } }","title":"Using Services"},{"location":"getting-started/databases/","text":"Databases Databases are an important choice for many applications. They come in many flavours for many different use cases. This article covers the four most popular databases used by our users. Database terminology Databases are a data management system. They allow storing data such as users, articles, relations (such as friends) and any other data structures. Databases allow querying and managing (large) data sets efficiently. Queries are a request for (mutation of) information. The most popular query language is SQL, a simple, string based and easily readable query language. NoSQL databases are databases which do not query using the SQL syntax. They often also serve a more specific use case. MongoDB MongoDB is the only database in this list that is not an SQL database (or NoSQL). It is designed for extremely large datasets, often with a complex structure. MongoDB supports recursive structures, unlike SQL databases which are one-dimensional. MongoDB's advantages lie in its architectural difference. It's more easily integrated in data models and more scalable. The downsides of MongoDB are that the familiar SQL syntax and some table joins are not supported. MongoDB is also a fairly new player, so although it has become very stable and mature it is not as battle tested over the years compared to MySQL. MongoDB does not support auto incremented integers. MySQL MySQL is one of the oldest and most robust databases in this list. Its old age has proven the database to be stable and trustworthy. It is an SQL database, meaning its queries are standardized, widely used, familiar and supported. This makes it extremely attractive to established businesses running SQL. MySQL documentation can be found here. SQLite SQLite is a database that is designed for small applications. It is extremely easy to use in that it only requires a filesystem. It must not be used on cloud services such as Vapor cloud or heroku as those don't persist the SQLite file. SQLite is very limited in its supported datatypes and should only be used for the most basic applications that should be developed in little time. SQLite databases aren't scalable across multiple servers. Using SQLite is described more thoroughly here.","title":"Databases"},{"location":"getting-started/databases/#databases","text":"Databases are an important choice for many applications. They come in many flavours for many different use cases. This article covers the four most popular databases used by our users.","title":"Databases"},{"location":"getting-started/databases/#database-terminology","text":"Databases are a data management system. They allow storing data such as users, articles, relations (such as friends) and any other data structures. Databases allow querying and managing (large) data sets efficiently. Queries are a request for (mutation of) information. The most popular query language is SQL, a simple, string based and easily readable query language. NoSQL databases are databases which do not query using the SQL syntax. They often also serve a more specific use case.","title":"Database terminology"},{"location":"getting-started/databases/#mongodb","text":"MongoDB is the only database in this list that is not an SQL database (or NoSQL). It is designed for extremely large datasets, often with a complex structure. MongoDB supports recursive structures, unlike SQL databases which are one-dimensional. MongoDB's advantages lie in its architectural difference. It's more easily integrated in data models and more scalable. The downsides of MongoDB are that the familiar SQL syntax and some table joins are not supported. MongoDB is also a fairly new player, so although it has become very stable and mature it is not as battle tested over the years compared to MySQL. MongoDB does not support auto incremented integers.","title":"MongoDB"},{"location":"getting-started/databases/#mysql","text":"MySQL is one of the oldest and most robust databases in this list. Its old age has proven the database to be stable and trustworthy. It is an SQL database, meaning its queries are standardized, widely used, familiar and supported. This makes it extremely attractive to established businesses running SQL. MySQL documentation can be found here.","title":"MySQL"},{"location":"getting-started/databases/#sqlite","text":"SQLite is a database that is designed for small applications. It is extremely easy to use in that it only requires a filesystem. It must not be used on cloud services such as Vapor cloud or heroku as those don't persist the SQLite file. SQLite is very limited in its supported datatypes and should only be used for the most basic applications that should be developed in little time. SQLite databases aren't scalable across multiple servers. Using SQLite is described more thoroughly here.","title":"SQLite"},{"location":"getting-started/hello-world/","text":"Hello, world Now that you've installed Vapor, let's create your first Vapor app! This guide will take you step by step through creating a new project, building, and running it. New Project The first step is to create a new Vapor project on your computer. For this guide, we will call the project Hello . Open up your terminal, and use Vapor Toolbox's new command. vapor new Hello Once that finishes, change into the newly created directory. cd Hello Generate Xcode Project Let's now use the Vapor Toolbox's xcode command to generate an Xcode project. This will allow us to build and run our app from inside of Xcode, just like an iOS app. vapor xcode The toolbox will ask you if you'd like to open Xcode automatically, select yes . Build Run You should now have Xcode open and running. Select the run scheme from the scheme menu and My Mac as the deployment target, then click the play button. You should see the terminal pop up at the bottom of the screen. Server starting on http://localhost:8080 Visit Localhost Open your web browser, and visit localhost:8080/hello You should see the following page. Hello, world! Congratulations on creating, building, and running your first Vapor app! \ud83c\udf89","title":"Hello, world"},{"location":"getting-started/hello-world/#hello-world","text":"Now that you've installed Vapor, let's create your first Vapor app! This guide will take you step by step through creating a new project, building, and running it.","title":"Hello, world"},{"location":"getting-started/hello-world/#new-project","text":"The first step is to create a new Vapor project on your computer. For this guide, we will call the project Hello . Open up your terminal, and use Vapor Toolbox's new command. vapor new Hello Once that finishes, change into the newly created directory. cd Hello","title":"New Project"},{"location":"getting-started/hello-world/#generate-xcode-project","text":"Let's now use the Vapor Toolbox's xcode command to generate an Xcode project. This will allow us to build and run our app from inside of Xcode, just like an iOS app. vapor xcode The toolbox will ask you if you'd like to open Xcode automatically, select yes .","title":"Generate Xcode Project"},{"location":"getting-started/hello-world/#build-run","text":"You should now have Xcode open and running. Select the run scheme from the scheme menu and My Mac as the deployment target, then click the play button. You should see the terminal pop up at the bottom of the screen. Server starting on http://localhost:8080","title":"Build & Run"},{"location":"getting-started/hello-world/#visit-localhost","text":"Open your web browser, and visit localhost:8080/hello You should see the following page. Hello, world! Congratulations on creating, building, and running your first Vapor app! \ud83c\udf89","title":"Visit Localhost"},{"location":"getting-started/routing/","text":"Routing Routing is the process of finding the appropriate response to an incoming request. Making a Router In Vapor the default Router is the EngineRouter . You can implement custom routers by implementing one conforming to the Router protocol. let router = try EngineRouter . default () This is usually done in your configure.swift file. Registering a route Imagine you want to return a list of users when someone visits GET /users . Leaving authorization aside, that would look something like this. router . get ( users ) { req in return // fetch the users } In Vapor, routing is usually done using the .get , .put , .post , .patch and .delete shorthands. You can supply the path as / or comma-separated strings. We recommend comma separated, as it's more readable. router . get ( path , to , something ) { ... } Routes The best place to add routes is in the routes.swift file. Use the router supplied as a parameter to this function to register your routes. import Vapor public func routes ( _ router : Router ) throws { // Basic Hello, world! example router . get ( hello ) { req in return Hello, world! } /// ... } See Getting Started Content for more information about what can be returned in a route closure. Parameters Sometimes you may want one of the components of your route path to be dynamic. This is often used when you want to get an item with a supplied identifier, e.g., GET /users/:id router . get ( users , Int . parameter ) { req - String in let id = try req . parameters . next ( Int . self ) return requested id # \\( id ) } Instead of passing a string, pass the type of parameter you expect. In this case, our User has an Int ID. Tip You can define your own custom parameter types as well. After registering your routes After registering your routes you must register the Router as a Getting Started Services","title":"Routing"},{"location":"getting-started/routing/#routing","text":"Routing is the process of finding the appropriate response to an incoming request.","title":"Routing"},{"location":"getting-started/routing/#making-a-router","text":"In Vapor the default Router is the EngineRouter . You can implement custom routers by implementing one conforming to the Router protocol. let router = try EngineRouter . default () This is usually done in your configure.swift file.","title":"Making a Router"},{"location":"getting-started/routing/#registering-a-route","text":"Imagine you want to return a list of users when someone visits GET /users . Leaving authorization aside, that would look something like this. router . get ( users ) { req in return // fetch the users } In Vapor, routing is usually done using the .get , .put , .post , .patch and .delete shorthands. You can supply the path as / or comma-separated strings. We recommend comma separated, as it's more readable. router . get ( path , to , something ) { ... }","title":"Registering a route"},{"location":"getting-started/routing/#routes","text":"The best place to add routes is in the routes.swift file. Use the router supplied as a parameter to this function to register your routes. import Vapor public func routes ( _ router : Router ) throws { // Basic Hello, world! example router . get ( hello ) { req in return Hello, world! } /// ... } See Getting Started Content for more information about what can be returned in a route closure.","title":"Routes"},{"location":"getting-started/routing/#parameters","text":"Sometimes you may want one of the components of your route path to be dynamic. This is often used when you want to get an item with a supplied identifier, e.g., GET /users/:id router . get ( users , Int . parameter ) { req - String in let id = try req . parameters . next ( Int . self ) return requested id # \\( id ) } Instead of passing a string, pass the type of parameter you expect. In this case, our User has an Int ID. Tip You can define your own custom parameter types as well.","title":"Parameters"},{"location":"getting-started/routing/#after-registering-your-routes","text":"After registering your routes you must register the Router as a Getting Started Services","title":"After registering your routes"},{"location":"getting-started/services/","text":"Services Services is a dependency injection (also called inversion of control) framework for Vapor. The services framework allows you to register, configure, and initialize anything you might need in your application. Container Most of your interaction with services will happen through a container. A container is a combination of the following: Services : A collection of registered services. Config : Declared preferences for certain services over others. Environment : The application's current environment type (testing, production, etc) Worker : The event loop associated with this container. The most common containers you will interact with in Vapor are: Application Request Response You should use the Application as a container to create services required for booting your app. You should use the Request or Response containers to create services for responding to requests (in route closures and controllers). Make Making services is simple, just call .make(_:) on a container and pass the type you want, usually a protocol like Client . let client = try req . make ( Client . self ) You can also specify a concrete type if you know exactly what you want. let leaf = try req . make ( LeafRenderer . self ) print ( leaf ) /// Definitely a LeafRenderer let view = try req . make ( ViewRenderer . self ) print ( view ) /// ViewRenderer, might be a LeafRenderer Tip Try to rely on protocols over concrete types if you can. This will make testing your code easier (you can easily swap in dummy implementations) and it can help keep your code decoupled. Services The Services struct contains all of the services you or the service providers you have added have registered. You will usually register and configure your services in configure.swift . Instance You can register initialized service instances using .register(_:) . /// Create an in-memory SQLite database let sqlite = SQLiteDatabase ( storage : . memory ) /// Register to sevices. services . register ( sqlite ) After you register a service, it will be available for creation by a Container . let db = app . make ( SQLiteDatabase . self ) print ( db ) // SQLiteDatabase (the one we registered earlier) Protocol When registering services, you can also declare conformance to a particular protocol. You might have noticed that this is how Vapor registers its main router. /// Register routes to the router let router = EngineRouter . default () try routes ( router ) services . register ( router , as : Router . self ) Since we register the router variable with as: Router.self , it can be created using either the concrete type or the protocol. let router = app . make ( Router . self ) let engineRouter = app . make ( EngineRouter . self ) print ( router ) // Router (actually EngineRouter) print ( engineRouter ) // EngineRouter print ( router === engineRouter ) // true Environment The environment is used to dynamically change how your Vapor app behaves in certain situations. For example, you probably want to use a different username and password for your database when your application is deployed. The Environment type makes managing this easy. When you run your Vapor app from the command line, you can pass an optional --env flag to specify the environment. By default, the environment will be .development . swift run Run --env prod In the above example, we are running Vapor in the .production environment. This environment specifies isRelease = true . You can use the environment passed into configure.swift to dynamically register services. let sqlite : SQLiteDatabase if env . isRelease { /// Create file-based SQLite db using $SQLITE_PATH from process env sqlite = try SQLiteDatabase ( storage : . file ( path : Environment . get ( SQLITE_PATH ) ! )) } else { /// Create an in-memory SQLite database sqlite = try SQLiteDatabase ( storage : . memory ) } services . register ( sqlite ) Info Use the static method Environment.get(_:) to fetch string values from the process environment. You can also dynamically register services based on environment using the factory .register(_:) method. services . register { container - BCryptConfig in let cost : Int switch container . environment { case . production : cost = 12 default : cost = 4 } return BCryptConfig ( cost : cost ) } Config If multiple services are available for a given protocol, you will need to use the Config struct to declare which service you prefer. ServiceError.ambiguity: Please choose which KeyedCache you prefer, multiple are available: MemoryKeyedCache, FluentCache SQLiteDatabase . This is also done in configure.swift , just use the config.prefer(_:for:) method. /// Declare preference for MemoryKeyedCache anytime a container is asked to create a KeyedCache config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) /// ... /// Create a KeyedCache using the Request container let cache = req . make ( KeyedCache . self ) print ( cache is MemoryKeyedCache ) // true","title":"Services"},{"location":"getting-started/services/#services","text":"Services is a dependency injection (also called inversion of control) framework for Vapor. The services framework allows you to register, configure, and initialize anything you might need in your application.","title":"Services"},{"location":"getting-started/services/#container","text":"Most of your interaction with services will happen through a container. A container is a combination of the following: Services : A collection of registered services. Config : Declared preferences for certain services over others. Environment : The application's current environment type (testing, production, etc) Worker : The event loop associated with this container. The most common containers you will interact with in Vapor are: Application Request Response You should use the Application as a container to create services required for booting your app. You should use the Request or Response containers to create services for responding to requests (in route closures and controllers).","title":"Container"},{"location":"getting-started/services/#make","text":"Making services is simple, just call .make(_:) on a container and pass the type you want, usually a protocol like Client . let client = try req . make ( Client . self ) You can also specify a concrete type if you know exactly what you want. let leaf = try req . make ( LeafRenderer . self ) print ( leaf ) /// Definitely a LeafRenderer let view = try req . make ( ViewRenderer . self ) print ( view ) /// ViewRenderer, might be a LeafRenderer Tip Try to rely on protocols over concrete types if you can. This will make testing your code easier (you can easily swap in dummy implementations) and it can help keep your code decoupled.","title":"Make"},{"location":"getting-started/services/#services_1","text":"The Services struct contains all of the services you or the service providers you have added have registered. You will usually register and configure your services in configure.swift .","title":"Services"},{"location":"getting-started/services/#instance","text":"You can register initialized service instances using .register(_:) . /// Create an in-memory SQLite database let sqlite = SQLiteDatabase ( storage : . memory ) /// Register to sevices. services . register ( sqlite ) After you register a service, it will be available for creation by a Container . let db = app . make ( SQLiteDatabase . self ) print ( db ) // SQLiteDatabase (the one we registered earlier)","title":"Instance"},{"location":"getting-started/services/#protocol","text":"When registering services, you can also declare conformance to a particular protocol. You might have noticed that this is how Vapor registers its main router. /// Register routes to the router let router = EngineRouter . default () try routes ( router ) services . register ( router , as : Router . self ) Since we register the router variable with as: Router.self , it can be created using either the concrete type or the protocol. let router = app . make ( Router . self ) let engineRouter = app . make ( EngineRouter . self ) print ( router ) // Router (actually EngineRouter) print ( engineRouter ) // EngineRouter print ( router === engineRouter ) // true","title":"Protocol"},{"location":"getting-started/services/#environment","text":"The environment is used to dynamically change how your Vapor app behaves in certain situations. For example, you probably want to use a different username and password for your database when your application is deployed. The Environment type makes managing this easy. When you run your Vapor app from the command line, you can pass an optional --env flag to specify the environment. By default, the environment will be .development . swift run Run --env prod In the above example, we are running Vapor in the .production environment. This environment specifies isRelease = true . You can use the environment passed into configure.swift to dynamically register services. let sqlite : SQLiteDatabase if env . isRelease { /// Create file-based SQLite db using $SQLITE_PATH from process env sqlite = try SQLiteDatabase ( storage : . file ( path : Environment . get ( SQLITE_PATH ) ! )) } else { /// Create an in-memory SQLite database sqlite = try SQLiteDatabase ( storage : . memory ) } services . register ( sqlite ) Info Use the static method Environment.get(_:) to fetch string values from the process environment. You can also dynamically register services based on environment using the factory .register(_:) method. services . register { container - BCryptConfig in let cost : Int switch container . environment { case . production : cost = 12 default : cost = 4 } return BCryptConfig ( cost : cost ) }","title":"Environment"},{"location":"getting-started/services/#config","text":"If multiple services are available for a given protocol, you will need to use the Config struct to declare which service you prefer. ServiceError.ambiguity: Please choose which KeyedCache you prefer, multiple are available: MemoryKeyedCache, FluentCache SQLiteDatabase . This is also done in configure.swift , just use the config.prefer(_:for:) method. /// Declare preference for MemoryKeyedCache anytime a container is asked to create a KeyedCache config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) /// ... /// Create a KeyedCache using the Request container let cache = req . make ( KeyedCache . self ) print ( cache is MemoryKeyedCache ) // true","title":"Config"},{"location":"getting-started/spm/","text":"Managing your project The Swift Package Manager (SPM for short) is used for building your project's source code and dependencies. It's a similar idea to Cocoapods, Ruby gems, and NPM. Most of the time the Vapor Toolbox will interact with SPM on your behalf. However, it's important to understand the basics. Tip Learn more about SPM on Swift.org Package Manifest The first place SPM looks in your project is the package manifest. This should always be located in the root directory of your project and named Package.swift . Dependencies Dependencies are other SPM packages that your package relies on. All Vapor applications rely on the Vapor package, but you can add as many other dependencies as you want. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ // \ud83d\udca7 A server-side Swift web framework. . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0-rc ), ], targets : [ ... ] ) In the above example, you can see vapor/vapor version 3.0 or later is a dependency of this package. When you add a dependency to your package, you must next signal which targets depend on the newly available modules. Warning Anytime you modify the package manifest, call vapor update to effect the changes. Targets Targets are all of the modules, executables, and tests that your package contains. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ ... ], targets : [ . target ( name : App , dependencies : [ Vapor ]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Most Vapor apps will have three targets, although you can add as many as you like to organize your code. Each target declares which modules it depends on. You must add module names here in order to import them in your code. A target can depend on other targets in your project or any modules exposed by packages you've added to the main dependencies array. Tip Executable targets (targets that contain a main.swift file) cannot be imported by other modules. This is why Vapor has both an App and a Run target. Any code you include in App can be tested in the AppTests . Folder Structure Below is the typical folder structure for an SPM package. . \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u2514\u2500\u2500 (Source code) \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Each .target corresponds to a folder in the Sources folder. Each .testTarget corresponds to a folder in the Tests folder. Troubleshooting If you are experiencing problems with SPM, sometimes cleaning your project can help. vapor clean","title":"SPM"},{"location":"getting-started/spm/#managing-your-project","text":"The Swift Package Manager (SPM for short) is used for building your project's source code and dependencies. It's a similar idea to Cocoapods, Ruby gems, and NPM. Most of the time the Vapor Toolbox will interact with SPM on your behalf. However, it's important to understand the basics. Tip Learn more about SPM on Swift.org","title":"Managing your project"},{"location":"getting-started/spm/#package-manifest","text":"The first place SPM looks in your project is the package manifest. This should always be located in the root directory of your project and named Package.swift .","title":"Package Manifest"},{"location":"getting-started/spm/#dependencies","text":"Dependencies are other SPM packages that your package relies on. All Vapor applications rely on the Vapor package, but you can add as many other dependencies as you want. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ // \ud83d\udca7 A server-side Swift web framework. . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0-rc ), ], targets : [ ... ] ) In the above example, you can see vapor/vapor version 3.0 or later is a dependency of this package. When you add a dependency to your package, you must next signal which targets depend on the newly available modules. Warning Anytime you modify the package manifest, call vapor update to effect the changes.","title":"Dependencies"},{"location":"getting-started/spm/#targets","text":"Targets are all of the modules, executables, and tests that your package contains. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ ... ], targets : [ . target ( name : App , dependencies : [ Vapor ]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Most Vapor apps will have three targets, although you can add as many as you like to organize your code. Each target declares which modules it depends on. You must add module names here in order to import them in your code. A target can depend on other targets in your project or any modules exposed by packages you've added to the main dependencies array. Tip Executable targets (targets that contain a main.swift file) cannot be imported by other modules. This is why Vapor has both an App and a Run target. Any code you include in App can be tested in the AppTests .","title":"Targets"},{"location":"getting-started/spm/#folder-structure","text":"Below is the typical folder structure for an SPM package. . \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u2514\u2500\u2500 (Source code) \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Each .target corresponds to a folder in the Sources folder. Each .testTarget corresponds to a folder in the Tests folder.","title":"Folder Structure"},{"location":"getting-started/spm/#troubleshooting","text":"If you are experiencing problems with SPM, sometimes cleaning your project can help. vapor clean","title":"Troubleshooting"},{"location":"getting-started/structure/","text":"Structure This section explains the structure of a typical Vapor application to help get you familiar with where things go. Folder Structure Vapor's folder structure builds on top of SPM's folder structure . . \u251c\u2500\u2500 Public \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u251c\u2500\u2500 Controllers \u2502 \u2502 \u251c\u2500\u2500 Models \u2502 \u2502 \u251c\u2500\u2500 boot.swift \u2502 \u2502 \u251c\u2500\u2500 configure.swift \u2502 \u2502 \u2514\u2500\u2500 routes.swift \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Let's take a look at what each of these folders and files does. Public This folder contains any public files that will be served by your app. This is usually images, style sheets, and browser scripts. Whenever Vapor responds to a request, it will first check if the requested item is in this folder. If it is, it skips your application logic and returns the file immediately. For example, a request to localhost:8080/favicon.ico will check to see if Public/favicon.ico exists. If it does, Vapor will return it. Sources This folder contains all of the Swift source files for your project. The top level folders ( App and Run ) reflect your package's modules, as declared in the package manifest . App This is the most important folder in your application, it's where all of the application logic goes! Controllers Controllers are great way of grouping together application logic. Most controllers have many functions that accept a request and return some sort of response. Tip Vapor supports, but does not enforce the MVC pattern Models The Models folder is a great place to store your Content structs or Fluent Model s. boot.swift This file contains a function that will be called after your application has booted, but before it has started running. This is a great place do things that should happen every time your application starts. You have access to the Application here which you can use to create any services you might need. configure.swift This file contains a function that receives the config, environment, and services for your application as input. This is a great place to make changes to your config or register services to your application. routes.swift This file contains a function for adding routes to your router. You will notice there's one example route in there that returns the \"hello, world\" response we saw earlier. You can create as many methods as you want to further organize your code. Just make sure to call them in this main route collection. Tests Each non-executable module in your Sources folder should have a corresponding ...Tests folder. AppTests This folder contains the unit tests for code in your App module. Learn more about testing in Testing Getting Started . Package.swift Finally is SPM's package manifest .","title":"Folder Structure"},{"location":"getting-started/structure/#structure","text":"This section explains the structure of a typical Vapor application to help get you familiar with where things go.","title":"Structure"},{"location":"getting-started/structure/#folder-structure","text":"Vapor's folder structure builds on top of SPM's folder structure . . \u251c\u2500\u2500 Public \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u251c\u2500\u2500 Controllers \u2502 \u2502 \u251c\u2500\u2500 Models \u2502 \u2502 \u251c\u2500\u2500 boot.swift \u2502 \u2502 \u251c\u2500\u2500 configure.swift \u2502 \u2502 \u2514\u2500\u2500 routes.swift \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Let's take a look at what each of these folders and files does.","title":"Folder Structure"},{"location":"getting-started/structure/#public","text":"This folder contains any public files that will be served by your app. This is usually images, style sheets, and browser scripts. Whenever Vapor responds to a request, it will first check if the requested item is in this folder. If it is, it skips your application logic and returns the file immediately. For example, a request to localhost:8080/favicon.ico will check to see if Public/favicon.ico exists. If it does, Vapor will return it.","title":"Public"},{"location":"getting-started/structure/#sources","text":"This folder contains all of the Swift source files for your project. The top level folders ( App and Run ) reflect your package's modules, as declared in the package manifest .","title":"Sources"},{"location":"getting-started/structure/#app","text":"This is the most important folder in your application, it's where all of the application logic goes!","title":"App"},{"location":"getting-started/structure/#controllers","text":"Controllers are great way of grouping together application logic. Most controllers have many functions that accept a request and return some sort of response. Tip Vapor supports, but does not enforce the MVC pattern","title":"Controllers"},{"location":"getting-started/structure/#models","text":"The Models folder is a great place to store your Content structs or Fluent Model s.","title":"Models"},{"location":"getting-started/structure/#bootswift","text":"This file contains a function that will be called after your application has booted, but before it has started running. This is a great place do things that should happen every time your application starts. You have access to the Application here which you can use to create any services you might need.","title":"boot.swift"},{"location":"getting-started/structure/#configureswift","text":"This file contains a function that receives the config, environment, and services for your application as input. This is a great place to make changes to your config or register services to your application.","title":"configure.swift"},{"location":"getting-started/structure/#routesswift","text":"This file contains a function for adding routes to your router. You will notice there's one example route in there that returns the \"hello, world\" response we saw earlier. You can create as many methods as you want to further organize your code. Just make sure to call them in this main route collection.","title":"routes.swift"},{"location":"getting-started/structure/#tests","text":"Each non-executable module in your Sources folder should have a corresponding ...Tests folder.","title":"Tests"},{"location":"getting-started/structure/#apptests","text":"This folder contains the unit tests for code in your App module. Learn more about testing in Testing Getting Started .","title":"AppTests"},{"location":"getting-started/structure/#packageswift","text":"Finally is SPM's package manifest .","title":"Package.swift"},{"location":"getting-started/toolbox/","text":"Install Toolbox Vapor's command line interface provides shortcuts and assistance for common tasks. Help prints useful information about available commands and flags. vapor --help You can also run the --help option on any Toolbox command. vapor new --help The --help flag should be your goto for learning about the toolbox as it is the most up-to-date. New The Toolbox's most important feature is helping you create a new project. vapor new name Just pass the name of your project as the first argument to the new command. Note Project names should be PascalCase , like HelloWorld or MyProject . Templates By default, Vapor will create your new project from the API template. You can choose a different template by passing the --template flag. Name Flag Description API --template=api JSON API with Fluent database. Web --template=web HTML website with Leaf templates. Auth --template=auth-template JSON API with Fluent DB and Auth. Info There are lots of unofficial Vapor templates on GitHub under the vapor + template topcs . You can use these by passing the full GitHub URL to the --template option. Build Run You can use the toolbox to build and run your Vapor app. vapor build vapor run Tip We recommend building and running through Xcode if you have a Mac. It's a bit faster and you can set breakpoints! Just use vapor xcode to generate an Xcode project. Updating The toolbox should be updated by the package manager it was installed with. Homebrew brew upgrade vapor APT sudo apt-get update sudo apt-get install vapor","title":"Toolbox"},{"location":"getting-started/toolbox/#install-toolbox","text":"Vapor's command line interface provides shortcuts and assistance for common tasks. Help prints useful information about available commands and flags. vapor --help You can also run the --help option on any Toolbox command. vapor new --help The --help flag should be your goto for learning about the toolbox as it is the most up-to-date.","title":"Install Toolbox"},{"location":"getting-started/toolbox/#new","text":"The Toolbox's most important feature is helping you create a new project. vapor new name Just pass the name of your project as the first argument to the new command. Note Project names should be PascalCase , like HelloWorld or MyProject .","title":"New"},{"location":"getting-started/toolbox/#templates","text":"By default, Vapor will create your new project from the API template. You can choose a different template by passing the --template flag. Name Flag Description API --template=api JSON API with Fluent database. Web --template=web HTML website with Leaf templates. Auth --template=auth-template JSON API with Fluent DB and Auth. Info There are lots of unofficial Vapor templates on GitHub under the vapor + template topcs . You can use these by passing the full GitHub URL to the --template option.","title":"Templates"},{"location":"getting-started/toolbox/#build-run","text":"You can use the toolbox to build and run your Vapor app. vapor build vapor run Tip We recommend building and running through Xcode if you have a Mac. It's a bit faster and you can set breakpoints! Just use vapor xcode to generate an Xcode project.","title":"Build & Run"},{"location":"getting-started/toolbox/#updating","text":"The toolbox should be updated by the package manager it was installed with.","title":"Updating"},{"location":"getting-started/toolbox/#homebrew","text":"brew upgrade vapor","title":"Homebrew"},{"location":"getting-started/toolbox/#apt","text":"sudo apt-get update sudo apt-get install vapor","title":"APT"},{"location":"getting-started/xcode/","text":"Xcode If you're on a Mac, you can develop your Vapor project using Xcode. You can build, run, and stop your server from within Xcode, as well as use breakpoints and instruments to debug your code. Xcode is a great way to develop Vapor apps, but you can use any text editor you like. Generate Project To use Xcode, you just need to generate an Xcode project using Vapor Toolbox . vapor xcode Tip Don't worry about comitting the generated Xcode Project to git, just generate a new one whenever you need it. Run To build and run your Vapor app, first make sure you have the Run scheme selected from the schemes menu. Also make sure to select \"My Mac\" as the device. Once that's selected, just click the play button or press Command + R on your keyboard. Test To run your unit tests, select the scheme ending in -Package and press Command + U . Warning There may be a few extraneous schemes in the dropdown menu. Ignore them!","title":"Xcode"},{"location":"getting-started/xcode/#xcode","text":"If you're on a Mac, you can develop your Vapor project using Xcode. You can build, run, and stop your server from within Xcode, as well as use breakpoints and instruments to debug your code. Xcode is a great way to develop Vapor apps, but you can use any text editor you like.","title":"Xcode"},{"location":"getting-started/xcode/#generate-project","text":"To use Xcode, you just need to generate an Xcode project using Vapor Toolbox . vapor xcode Tip Don't worry about comitting the generated Xcode Project to git, just generate a new one whenever you need it.","title":"Generate Project"},{"location":"getting-started/xcode/#run","text":"To build and run your Vapor app, first make sure you have the Run scheme selected from the schemes menu. Also make sure to select \"My Mac\" as the device. Once that's selected, just click the play button or press Command + R on your keyboard.","title":"Run"},{"location":"getting-started/xcode/#test","text":"To run your unit tests, select the scheme ending in -Package and press Command + U . Warning There may be a few extraneous schemes in the dropdown menu. Ignore them!","title":"Test"},{"location":"http/client/","text":"Using HTTPClient HTTP clients send requests to remote HTTP servers which then generate and return responses. HTTP clients are usually only active for a matter of seconds to minutes and may send one or more requests. The HTTPClient type is what powers Vapor's higher-level client. This short guide will show you how to send HTTP requests to servers manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Client for the more convenient APIs. For this example, we will fetch Vapor's homepage. The first step is to create a connected HTTP client. Use the static connect(...) method to do this. // Connect a new client to the supplied hostname. let client = try HTTPClient . connect ( hostname : vapor.codes , on : ...). wait () print ( client ) // HTTPClient // Create an HTTP request: GET / let httpReq = HTTPRequest ( method : . GET , url : / ) // Send the HTTP request, fetching a response let httpRes = try client . send ( httpReq ). wait () print ( httpRes ) // HTTPResponse Take note that we are passing the hostname . This is different from a full URL. You can use URL and URLComponents from Foundation to parse out a hostname. Vapor's convenience APIs do this automatically. Warning This guide assumes you are on the main thread. Don't use wait() if you are inside of a route closure. See Async Overview for more information. After we have a connected HTTP client, we can send an HTTPRequest using send(...) . This will return an HTTPResponse containing the headers and body sent back from the server. See HTTP Message for more information on HTTP messages. API Docs That's it! Congratulations on making your first HTTP request. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"Client"},{"location":"http/client/#using-httpclient","text":"HTTP clients send requests to remote HTTP servers which then generate and return responses. HTTP clients are usually only active for a matter of seconds to minutes and may send one or more requests. The HTTPClient type is what powers Vapor's higher-level client. This short guide will show you how to send HTTP requests to servers manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Client for the more convenient APIs. For this example, we will fetch Vapor's homepage. The first step is to create a connected HTTP client. Use the static connect(...) method to do this. // Connect a new client to the supplied hostname. let client = try HTTPClient . connect ( hostname : vapor.codes , on : ...). wait () print ( client ) // HTTPClient // Create an HTTP request: GET / let httpReq = HTTPRequest ( method : . GET , url : / ) // Send the HTTP request, fetching a response let httpRes = try client . send ( httpReq ). wait () print ( httpRes ) // HTTPResponse Take note that we are passing the hostname . This is different from a full URL. You can use URL and URLComponents from Foundation to parse out a hostname. Vapor's convenience APIs do this automatically. Warning This guide assumes you are on the main thread. Don't use wait() if you are inside of a route closure. See Async Overview for more information. After we have a connected HTTP client, we can send an HTTPRequest using send(...) . This will return an HTTPResponse containing the headers and body sent back from the server. See HTTP Message for more information on HTTP messages.","title":"Using HTTPClient"},{"location":"http/client/#api-docs","text":"That's it! Congratulations on making your first HTTP request. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"API Docs"},{"location":"http/getting-started/","text":"Getting Started with HTTP HTTP ( vapor/http ) is a non-blocking, event-driven HTTP library built on SwiftNIO. It makes working with SwiftNIO's HTTP handlers easy and offers higher-level functionality like media types, client upgrading, streaming bodies, and more. Creating an HTTP echo server takes just a few lines of code. Tip If you use Vapor, most of HTTP's APIs will be wrapped by more convenient methods. Usually the only HTTP type you will interact with is the http property of Request or Response . Vapor This package is included with Vapor and exported by default. You will have access to all HTTP APIs when you import Vapor . import Vapor Standalone The HTTP package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as an HTTP framework in any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/http.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ HTTP , ... ]) ] ) Use import HTTP to access the APIs. The rest of this guide will give you an overview of what is available in the HTTP package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"http/getting-started/#getting-started-with-http","text":"HTTP ( vapor/http ) is a non-blocking, event-driven HTTP library built on SwiftNIO. It makes working with SwiftNIO's HTTP handlers easy and offers higher-level functionality like media types, client upgrading, streaming bodies, and more. Creating an HTTP echo server takes just a few lines of code. Tip If you use Vapor, most of HTTP's APIs will be wrapped by more convenient methods. Usually the only HTTP type you will interact with is the http property of Request or Response .","title":"Getting Started with HTTP"},{"location":"http/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all HTTP APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"http/getting-started/#standalone","text":"The HTTP package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as an HTTP framework in any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/http.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ HTTP , ... ]) ] ) Use import HTTP to access the APIs. The rest of this guide will give you an overview of what is available in the HTTP package. As always, feel free to visit the API docs for more in-depth information.","title":"Standalone"},{"location":"http/message/","text":"Using HTTP Message There are two types of HTTP messages, HTTPRequest and HTTPResponse . For the most part they are very similar, but there are a couple of differences. Request HTTP requests are sent by clients to a server and they should always receive exactly one HTTP response. HTTP requests contain two unique fields over a standard HTTP message: method url The method and URL define what content on the server is being requested. /// GET /hello let httpReq = HTTPRequest ( method : . GET , url : /hello ) You can define these when initializing an HTTP request, or set them later if the request is mutable. var httpReq : HTTPRequest = ... httpReq . method = . POST httpReq . url = URL (...) You can use Foundation's URLComponents to create URL s from their base components. HTTP request also has a property urlString that you can use to set a custom URL String manually, without going through URL . Here is what a serialized HTTP request looks like. This one is querying /hello . GET /hello HTTP / 1.1 Content-Length : 0 Response HTTP responses are generated by servers in response to an HTTP request. HTTP response only has one unique field over general HTTP messages: status The HTTP status is used to inform the client of any errors. The status consists of a status code and a reason. The code is always a three digit number and the reason is a short string explaining the code. You can see all of the status codes on httpstatuses.com . let httpRes = HTTPResponse ( status : . ok , body : hello ) All of the commonly used HTTP statuses will have pre-defined values you can use, like .ok for 200 OK . You can also define your own custom status codes. You can define the status when initializing an HTTP response, or set it later if the response is mutable. var httpRes : HTTPResponse = ... httpRes . status = . notFound Here is an example of a serialized HTTP response. HTTP / 1.1 200 OK Content-Length : 5 Content-Type : text/plain hello Headers Every HTTP message has a collection of headers. Headers contain metadata about the message and help to explain what is in the message's body. Content-Length: 5 Content-Type: text/plain There must be at least a \"Content-Length\" or \"Transfer-Encoding\" header to define how long the message's body is. There is almost always a \"Content-Type\" header that explains what type of data the body contains. There are many other common headers such as \"Date\" which specifies when the message was created, and more. You can access an HTTP message's headers using the headers property. var message : HTTPMessage ... message . headers . firstValue ( for : . contentLength ) // 5 If you are interacting with common HTTP headers, you can use the convenience HTTP names instead of a raw String . Body HTTP messages can have an HTTPBody containing arbitrary data. This data can be either static or streaming and can be in whatever format you want. Use the contentType header to describe the type of data. var message : HTTPMessage = ... message . body = HTTPBody ( string : Hello, world! ) message . contentType = . plainText Tip Setting the body property will automatically update the \"Content-Length\" or \"Transfer-Encoding\" headers if required. var message : HTTPMessage = ... message . body = HTTPBody ( string : { message : Hello , world ! } ) message . contentType = . json Codable Two protocols are defined for making it easy to use Codable with HTTP: HTTPMessageEncoder HTTPMessageDecoder These two coders allow you to encode and decode your custom Codable types into an HTTP body, setting the appropriate content type headers. By default, HTTP provides conformance for JSONEncoder and JSONDecoder , but Vapor includes coders for many more types. Here is an example of encoding a Codable struct to an HTTP response. struct Greeting : Codable { var message : String } // Create an instance of Greeting let greeting = Greeting ( message : Hello, world! ) // Create a 200 OK response var httpRes = HTTPResponse ( status : . ok ) // Encode the greeting to the response try JSONEncoder (). encode ( greeting , to : httpRes , on : ...) API Docs Check out the API docs for more in-depth information about all of the methods.","title":"Message"},{"location":"http/message/#using-http-message","text":"There are two types of HTTP messages, HTTPRequest and HTTPResponse . For the most part they are very similar, but there are a couple of differences.","title":"Using HTTP Message"},{"location":"http/message/#request","text":"HTTP requests are sent by clients to a server and they should always receive exactly one HTTP response. HTTP requests contain two unique fields over a standard HTTP message: method url The method and URL define what content on the server is being requested. /// GET /hello let httpReq = HTTPRequest ( method : . GET , url : /hello ) You can define these when initializing an HTTP request, or set them later if the request is mutable. var httpReq : HTTPRequest = ... httpReq . method = . POST httpReq . url = URL (...) You can use Foundation's URLComponents to create URL s from their base components. HTTP request also has a property urlString that you can use to set a custom URL String manually, without going through URL . Here is what a serialized HTTP request looks like. This one is querying /hello . GET /hello HTTP / 1.1 Content-Length : 0","title":"Request"},{"location":"http/message/#response","text":"HTTP responses are generated by servers in response to an HTTP request. HTTP response only has one unique field over general HTTP messages: status The HTTP status is used to inform the client of any errors. The status consists of a status code and a reason. The code is always a three digit number and the reason is a short string explaining the code. You can see all of the status codes on httpstatuses.com . let httpRes = HTTPResponse ( status : . ok , body : hello ) All of the commonly used HTTP statuses will have pre-defined values you can use, like .ok for 200 OK . You can also define your own custom status codes. You can define the status when initializing an HTTP response, or set it later if the response is mutable. var httpRes : HTTPResponse = ... httpRes . status = . notFound Here is an example of a serialized HTTP response. HTTP / 1.1 200 OK Content-Length : 5 Content-Type : text/plain hello","title":"Response"},{"location":"http/message/#headers","text":"Every HTTP message has a collection of headers. Headers contain metadata about the message and help to explain what is in the message's body. Content-Length: 5 Content-Type: text/plain There must be at least a \"Content-Length\" or \"Transfer-Encoding\" header to define how long the message's body is. There is almost always a \"Content-Type\" header that explains what type of data the body contains. There are many other common headers such as \"Date\" which specifies when the message was created, and more. You can access an HTTP message's headers using the headers property. var message : HTTPMessage ... message . headers . firstValue ( for : . contentLength ) // 5 If you are interacting with common HTTP headers, you can use the convenience HTTP names instead of a raw String .","title":"Headers"},{"location":"http/message/#body","text":"HTTP messages can have an HTTPBody containing arbitrary data. This data can be either static or streaming and can be in whatever format you want. Use the contentType header to describe the type of data. var message : HTTPMessage = ... message . body = HTTPBody ( string : Hello, world! ) message . contentType = . plainText Tip Setting the body property will automatically update the \"Content-Length\" or \"Transfer-Encoding\" headers if required. var message : HTTPMessage = ... message . body = HTTPBody ( string : { message : Hello , world ! } ) message . contentType = . json","title":"Body"},{"location":"http/message/#codable","text":"Two protocols are defined for making it easy to use Codable with HTTP: HTTPMessageEncoder HTTPMessageDecoder These two coders allow you to encode and decode your custom Codable types into an HTTP body, setting the appropriate content type headers. By default, HTTP provides conformance for JSONEncoder and JSONDecoder , but Vapor includes coders for many more types. Here is an example of encoding a Codable struct to an HTTP response. struct Greeting : Codable { var message : String } // Create an instance of Greeting let greeting = Greeting ( message : Hello, world! ) // Create a 200 OK response var httpRes = HTTPResponse ( status : . ok ) // Encode the greeting to the response try JSONEncoder (). encode ( greeting , to : httpRes , on : ...)","title":"Codable"},{"location":"http/message/#api-docs","text":"Check out the API docs for more in-depth information about all of the methods.","title":"API Docs"},{"location":"http/server/","text":"Using HTTPServer HTTP servers respond to incoming HTTPRequests with HTTPResponses . The HTTPServer type is what powers Vapor's higher-level server. This short guide will show you how to set up your own HTTP server manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Getting Started for the more convenient APIs. Responder Creating an HTTP server is easy, and only takes a few lines of code. The first step is to create an HTTPServerResponder . This will be directly responsible for generating responses to incoming requests. Let's create a simple responder that will echo the request's content. /// Echoes the request as a response. struct EchoResponder : HTTPServerResponder { /// See `HTTPServerResponder`. func respond ( to req : HTTPRequest , on worker : Worker ) - Future HTTPResponse { // Create an HTTPResponse with the same body as the HTTPRequest let res = HTTPResponse ( body : req . body ) // We don t need to do any async work here, we can just // se the Worker s event-loop to create a succeeded future. return worker . eventLoop . newSucceededFuture ( result : res ) } } Start Now that we have a responder, we can create our HTTPServer . We just need to choose a hostname and port for the server to bind to. In this example, we will bind to http://localhost:8123 . // Create an EventLoopGroup with an appropriate number // of threads for the system we are running on. let group = MultiThreadedEventLoopGroup ( numThreads : System . coreCount ) // Make sure to shutdown the group when the application exits. defer { try ! group . syncShutdownGracefully () } // Start an HTTPServer using our EchoResponder // We are fine to use `wait()` here since we are on the main thread. let server = try HTTPServer . start ( hostname : localhost , port : 8123 , responder : EchoResponder (), on : group ). wait () // Wait for the server to close (indefinitely). try server . onClose . wait () The static start(...) method creates and returns a new HTTPServer asynchronously. The future will be completed when the server has finished booting succesfully, or it will contain an error if something went wrong. Once the start future is complete, our server is running. By waiting for the server's onClose future to complete, we can keep our application alive until the server closes. Normally the server will not close itself--it will just run indefinitely. However if server.close() is ever called, the application can exit gracefully. API Docs That's it! Congratulations on making your first HTTP server and responder. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"Server"},{"location":"http/server/#using-httpserver","text":"HTTP servers respond to incoming HTTPRequests with HTTPResponses . The HTTPServer type is what powers Vapor's higher-level server. This short guide will show you how to set up your own HTTP server manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Getting Started for the more convenient APIs.","title":"Using HTTPServer"},{"location":"http/server/#responder","text":"Creating an HTTP server is easy, and only takes a few lines of code. The first step is to create an HTTPServerResponder . This will be directly responsible for generating responses to incoming requests. Let's create a simple responder that will echo the request's content. /// Echoes the request as a response. struct EchoResponder : HTTPServerResponder { /// See `HTTPServerResponder`. func respond ( to req : HTTPRequest , on worker : Worker ) - Future HTTPResponse { // Create an HTTPResponse with the same body as the HTTPRequest let res = HTTPResponse ( body : req . body ) // We don t need to do any async work here, we can just // se the Worker s event-loop to create a succeeded future. return worker . eventLoop . newSucceededFuture ( result : res ) } }","title":"Responder"},{"location":"http/server/#start","text":"Now that we have a responder, we can create our HTTPServer . We just need to choose a hostname and port for the server to bind to. In this example, we will bind to http://localhost:8123 . // Create an EventLoopGroup with an appropriate number // of threads for the system we are running on. let group = MultiThreadedEventLoopGroup ( numThreads : System . coreCount ) // Make sure to shutdown the group when the application exits. defer { try ! group . syncShutdownGracefully () } // Start an HTTPServer using our EchoResponder // We are fine to use `wait()` here since we are on the main thread. let server = try HTTPServer . start ( hostname : localhost , port : 8123 , responder : EchoResponder (), on : group ). wait () // Wait for the server to close (indefinitely). try server . onClose . wait () The static start(...) method creates and returns a new HTTPServer asynchronously. The future will be completed when the server has finished booting succesfully, or it will contain an error if something went wrong. Once the start future is complete, our server is running. By waiting for the server's onClose future to complete, we can keep our application alive until the server closes. Normally the server will not close itself--it will just run indefinitely. However if server.close() is ever called, the application can exit gracefully.","title":"Start"},{"location":"http/server/#api-docs","text":"That's it! Congratulations on making your first HTTP server and responder. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"API Docs"},{"location":"install/macos/","text":"Install on macOS To use Vapor on macOS, you just need to have Xcode 9.3 or greater installed. Install Xcode Install Xcode 9.3 or greater from the Mac App Store. Warning After Xcode has been downloaded, you must open it to finish the installation. This may take a while. Verify Installation Double check the installation was successful by opening Terminal and running: swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater. Install Vapor Now that you have Swift 4.1, let's install the Vapor Toolbox . The toolbox includes all of Vapor's dependencies as well as a handy CLI tool for creating new projects. brew install vapor/tap/vapor Tip If you don't already have Homebrew installed, install it at brew.sh Verify Installation Double check the installation was successful by opening Terminal and running: vapor --help You should see a long list of available commands. Done Now that you have installed Vapor, create your first app in Getting Started Hello, world .","title":"macOS"},{"location":"install/macos/#install-on-macos","text":"To use Vapor on macOS, you just need to have Xcode 9.3 or greater installed.","title":"Install on macOS"},{"location":"install/macos/#install-xcode","text":"Install Xcode 9.3 or greater from the Mac App Store. Warning After Xcode has been downloaded, you must open it to finish the installation. This may take a while.","title":"Install Xcode"},{"location":"install/macos/#verify-installation","text":"Double check the installation was successful by opening Terminal and running: swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater.","title":"Verify Installation"},{"location":"install/macos/#install-vapor","text":"Now that you have Swift 4.1, let's install the Vapor Toolbox . The toolbox includes all of Vapor's dependencies as well as a handy CLI tool for creating new projects. brew install vapor/tap/vapor Tip If you don't already have Homebrew installed, install it at brew.sh","title":"Install Vapor"},{"location":"install/macos/#verify-installation_1","text":"Double check the installation was successful by opening Terminal and running: vapor --help You should see a long list of available commands.","title":"Verify Installation"},{"location":"install/macos/#done","text":"Now that you have installed Vapor, create your first app in Getting Started Hello, world .","title":"Done"},{"location":"install/ubuntu/","text":"Install on Ubuntu Installing Vapor on Ubuntu only takes a couple of minutes. Supported Vapor supports the same versions of Ubuntu that Swift supports. Version Codename 16.10 Yakkety Yak 16.04 Xenial Xerus 14.04 Trusty Tahr APT Repo Add Vapor's APT repo to get access to all of Vapor's Ubuntu packages. Quick Script Easily add Vapor's APT repo with this handy script. eval $( curl -sL https://apt.vapor.sh ) Tip This command requires curl which can be installed using sudo apt-get install curl Dockerfile When configuring Ubuntu from a Dockerfile, adding the APT repo can be done via this command: RUN /bin/bash -c $( wget -qO- https://apt.vapor.sh ) Manual Or add the repo manually. wget -q https://repo.vapor.codes/apt/keyring.gpg -O- | sudo apt-key add - echo deb https://repo.vapor.codes/apt $( lsb_release -sc ) main | sudo tee /etc/apt/sources.list.d/vapor.list sudo apt-get update Install Vapor Now that you have added Vapor's APT repo, you can install the required dependencies. sudo apt-get install swift vapor Verify Installation Double check everything worked with the following commands. Swift swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater. Vapor Toolbox vapor --help You should see a long list of available commands. Done Now that you have installed Vapor, create your first app in Getting Started Hello, world . Swift.org Check out Swift.org 's guide to using downloads if you need more detailed instructions for installing Swift 4.1.","title":"Ubuntu"},{"location":"install/ubuntu/#install-on-ubuntu","text":"Installing Vapor on Ubuntu only takes a couple of minutes.","title":"Install on Ubuntu"},{"location":"install/ubuntu/#supported","text":"Vapor supports the same versions of Ubuntu that Swift supports. Version Codename 16.10 Yakkety Yak 16.04 Xenial Xerus 14.04 Trusty Tahr","title":"Supported"},{"location":"install/ubuntu/#apt-repo","text":"Add Vapor's APT repo to get access to all of Vapor's Ubuntu packages.","title":"APT Repo"},{"location":"install/ubuntu/#quick-script","text":"Easily add Vapor's APT repo with this handy script. eval $( curl -sL https://apt.vapor.sh ) Tip This command requires curl which can be installed using sudo apt-get install curl","title":"Quick Script"},{"location":"install/ubuntu/#dockerfile","text":"When configuring Ubuntu from a Dockerfile, adding the APT repo can be done via this command: RUN /bin/bash -c $( wget -qO- https://apt.vapor.sh )","title":"Dockerfile"},{"location":"install/ubuntu/#manual","text":"Or add the repo manually. wget -q https://repo.vapor.codes/apt/keyring.gpg -O- | sudo apt-key add - echo deb https://repo.vapor.codes/apt $( lsb_release -sc ) main | sudo tee /etc/apt/sources.list.d/vapor.list sudo apt-get update","title":"Manual"},{"location":"install/ubuntu/#install-vapor","text":"Now that you have added Vapor's APT repo, you can install the required dependencies. sudo apt-get install swift vapor","title":"Install Vapor"},{"location":"install/ubuntu/#verify-installation","text":"Double check everything worked with the following commands.","title":"Verify Installation"},{"location":"install/ubuntu/#swift","text":"swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater.","title":"Swift"},{"location":"install/ubuntu/#vapor-toolbox","text":"vapor --help You should see a long list of available commands.","title":"Vapor Toolbox"},{"location":"install/ubuntu/#done","text":"Now that you have installed Vapor, create your first app in Getting Started Hello, world .","title":"Done"},{"location":"install/ubuntu/#swiftorg","text":"Check out Swift.org 's guide to using downloads if you need more detailed instructions for installing Swift 4.1.","title":"Swift.org"},{"location":"jwt/getting-started/","text":"Getting Started with JWT JWT ( vapor/jwt ) is a package for parsing and serializing J SON W eb T okens supporting both HMAC and RSA signing. JWTs are often used for implementing decentralized authentication and authorization. Since all of the authenticated user's information can be embedded within a JWT, there is no need to query a central authentication server with each request to your service. Unlike standard bearer tokens that must be looked up in a centralized database, JWTs contain cryptographic signatures that can be used to independently verify their authenticity. If implemented correctly, JWTs can be a powerful tool for making your application horizontally scalable . Learn more about JWT at jwt.io . Tip If your goal is not horizontal scalability, a standard bearer token will likely be a better solution. JWTs have some downsides worth considering such as the inability to revoke a token once it has been issued (until it expires normally). Let's take a look at how you can get started using JWT. Package The first step to using JWT is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd0f JSON Web Token signing and verification (HMAC, RSA). . package ( url : https://github.com/vapor/jwt.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ JWT , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) That's it for basic setup. The next section will give you an overview of the package's APIs. As always, feel free to visit the API Docs for more specific information.","title":"Getting Started"},{"location":"jwt/getting-started/#getting-started-with-jwt","text":"JWT ( vapor/jwt ) is a package for parsing and serializing J SON W eb T okens supporting both HMAC and RSA signing. JWTs are often used for implementing decentralized authentication and authorization. Since all of the authenticated user's information can be embedded within a JWT, there is no need to query a central authentication server with each request to your service. Unlike standard bearer tokens that must be looked up in a centralized database, JWTs contain cryptographic signatures that can be used to independently verify their authenticity. If implemented correctly, JWTs can be a powerful tool for making your application horizontally scalable . Learn more about JWT at jwt.io . Tip If your goal is not horizontal scalability, a standard bearer token will likely be a better solution. JWTs have some downsides worth considering such as the inability to revoke a token once it has been issued (until it expires normally). Let's take a look at how you can get started using JWT.","title":"Getting Started with JWT"},{"location":"jwt/getting-started/#package","text":"The first step to using JWT is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd0f JSON Web Token signing and verification (HMAC, RSA). . package ( url : https://github.com/vapor/jwt.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ JWT , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) That's it for basic setup. The next section will give you an overview of the package's APIs. As always, feel free to visit the API Docs for more specific information.","title":"Package"},{"location":"jwt/overview/","text":"Using JWT JSON Web Tokens are a great tool for implementing decentralized authentication and authorization. Once you are finished configuring your app to use the JWT package (see JWT Getting Started ), you are ready to begin using JWTs in your app. Structure Like other forms of token-based auth, JWTs are sent using the bearer authorization header. GET /hello HTTP / 1.1 Authorization : Bearer token ... In the example HTTP request above, token would be replaced by the serialized JWT. jwt.io hosts an online tool for parsing and serializing JWTs. We will use that tool to create a token for testing. Header The header is mainly used to specify which algorithm was used to generate the token's signature. This is used by the accepting app to verify the token's authenticity. Here is the raw JSON data for our header: { alg : HS256 , typ : JWT } This specifies the HMAC SHA-256 signing algorithm and that our token is indeed a JWT. Payload The payload is where you store information to identify the authenticated user. You can store any data you want here, but be careful not to store too much as some web browsers limit HTTP header sizes. The payload is also where you store claims . Claims are standardized key / value pairs that many JWT implementations can recognize and act on automatically. A commonly used claim is Expiration Time which stores the token's expiration date as a unix timestamp at key \"exp\" . See a full list of supported claims in RFC 7519 4.1 . To keep things simple, we will just include our user's identifier and name in the payload: { id : 42 , name : Vapor Developer } Secret Last but not least is the secret key used to sign and verify the JWT. For this example, we are using the HS256 algorithm (specified in the JWT header). HMAC algorithms use a single secret key for both signing and verifying. To keep things simple, we will use the following string as our key: secret Other algorithms, like RSA, use asymmetric (public and private) keys. With these types of algorithms, only the private key is able to create (sign) JWTs. Both the public and private keys can verify JWTs. This allows for an added layer of security as you can distribute the public key to services that should only be able to verify tokens, not create them. Serialized Finally, here is our fully serialized token. This will be sent via the bearer authorization header. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Each segment is separated by a . . The overall structure of the token is the following: header . payload . signature Note that the header and payload segments are simply base64-url encoded JSON. It is important to remember that all information your store in a normal JWT is publically readable. Parse Let's take a look at how to parse and verify incoming JWTs. Payload First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now. Route Now that our payload type is ready, we can parse and verify an incoming JWT. import JWT import Vapor router . get ( hello ) { req - String in // fetches the token from `Authorization: Bearer token ` header guard let bearer = req . http . headers . bearerAuthorization else { throw Abort (. unauthorized ) } // parse JWT from token string, using HS-256 signer let jwt = try JWT User ( from : bearer . token , verifiedUsing : . hs256 ( key : secret )) return Hello, \\( jwt . payload . name ) ! } This snippet creates a new route at GET /hello . The first part of the route handler fetches the token value from the bearer authorization header. The second part uses the JWT struct to parse the token using an HS256 signer. Once the JWT is parsed, we access the payload property which contains an instance of our User type. We then access the name property to say hello! Run the following request and check the output: GET /hello HTTP / 1.1 Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Content-Length : 0 You should see the following response: HTTP / 1.1 200 OK Content-Length : 23 Hello, Vapor Developer! Serialize Let's take a look at how to create and sign a JWT. Payload First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now. Route Now that our payload type is ready, we can generate a JWT. router . post ( login ) { req - String in // create payload let user = User ( id : 42 , name : Vapor Developer ) // create JWT and sign let data = try JWT ( payload : user ). sign ( using : . hs256 ( key : secret )) return String ( data : data , encoding : . utf8 ) ?? } This snippet creates a new route at POST /login . The first part of the route handler creates an instance of our User payload type. The second part creates an instance of JWT using our payload, and calls the sign(using:) method. This method returns Data , which we convert to a String . If you visit this route, you should get the following output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM If you plug that JWT into jwt.io and enter the secret ( secret ), you should see the encoded data and a message \"Signature Verified\".","title":"Overview"},{"location":"jwt/overview/#using-jwt","text":"JSON Web Tokens are a great tool for implementing decentralized authentication and authorization. Once you are finished configuring your app to use the JWT package (see JWT Getting Started ), you are ready to begin using JWTs in your app.","title":"Using JWT"},{"location":"jwt/overview/#structure","text":"Like other forms of token-based auth, JWTs are sent using the bearer authorization header. GET /hello HTTP / 1.1 Authorization : Bearer token ... In the example HTTP request above, token would be replaced by the serialized JWT. jwt.io hosts an online tool for parsing and serializing JWTs. We will use that tool to create a token for testing.","title":"Structure"},{"location":"jwt/overview/#header","text":"The header is mainly used to specify which algorithm was used to generate the token's signature. This is used by the accepting app to verify the token's authenticity. Here is the raw JSON data for our header: { alg : HS256 , typ : JWT } This specifies the HMAC SHA-256 signing algorithm and that our token is indeed a JWT.","title":"Header"},{"location":"jwt/overview/#payload","text":"The payload is where you store information to identify the authenticated user. You can store any data you want here, but be careful not to store too much as some web browsers limit HTTP header sizes. The payload is also where you store claims . Claims are standardized key / value pairs that many JWT implementations can recognize and act on automatically. A commonly used claim is Expiration Time which stores the token's expiration date as a unix timestamp at key \"exp\" . See a full list of supported claims in RFC 7519 4.1 . To keep things simple, we will just include our user's identifier and name in the payload: { id : 42 , name : Vapor Developer }","title":"Payload"},{"location":"jwt/overview/#secret","text":"Last but not least is the secret key used to sign and verify the JWT. For this example, we are using the HS256 algorithm (specified in the JWT header). HMAC algorithms use a single secret key for both signing and verifying. To keep things simple, we will use the following string as our key: secret Other algorithms, like RSA, use asymmetric (public and private) keys. With these types of algorithms, only the private key is able to create (sign) JWTs. Both the public and private keys can verify JWTs. This allows for an added layer of security as you can distribute the public key to services that should only be able to verify tokens, not create them.","title":"Secret"},{"location":"jwt/overview/#serialized","text":"Finally, here is our fully serialized token. This will be sent via the bearer authorization header. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Each segment is separated by a . . The overall structure of the token is the following: header . payload . signature Note that the header and payload segments are simply base64-url encoded JSON. It is important to remember that all information your store in a normal JWT is publically readable.","title":"Serialized"},{"location":"jwt/overview/#parse","text":"Let's take a look at how to parse and verify incoming JWTs.","title":"Parse"},{"location":"jwt/overview/#payload_1","text":"First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now.","title":"Payload"},{"location":"jwt/overview/#route","text":"Now that our payload type is ready, we can parse and verify an incoming JWT. import JWT import Vapor router . get ( hello ) { req - String in // fetches the token from `Authorization: Bearer token ` header guard let bearer = req . http . headers . bearerAuthorization else { throw Abort (. unauthorized ) } // parse JWT from token string, using HS-256 signer let jwt = try JWT User ( from : bearer . token , verifiedUsing : . hs256 ( key : secret )) return Hello, \\( jwt . payload . name ) ! } This snippet creates a new route at GET /hello . The first part of the route handler fetches the token value from the bearer authorization header. The second part uses the JWT struct to parse the token using an HS256 signer. Once the JWT is parsed, we access the payload property which contains an instance of our User type. We then access the name property to say hello! Run the following request and check the output: GET /hello HTTP / 1.1 Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Content-Length : 0 You should see the following response: HTTP / 1.1 200 OK Content-Length : 23 Hello, Vapor Developer!","title":"Route"},{"location":"jwt/overview/#serialize","text":"Let's take a look at how to create and sign a JWT.","title":"Serialize"},{"location":"jwt/overview/#payload_2","text":"First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now.","title":"Payload"},{"location":"jwt/overview/#route_1","text":"Now that our payload type is ready, we can generate a JWT. router . post ( login ) { req - String in // create payload let user = User ( id : 42 , name : Vapor Developer ) // create JWT and sign let data = try JWT ( payload : user ). sign ( using : . hs256 ( key : secret )) return String ( data : data , encoding : . utf8 ) ?? } This snippet creates a new route at POST /login . The first part of the route handler creates an instance of our User payload type. The second part creates an instance of JWT using our payload, and calls the sign(using:) method. This method returns Data , which we convert to a String . If you visit this route, you should get the following output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM If you plug that JWT into jwt.io and enter the secret ( secret ), you should see the encoded data and a message \"Signature Verified\".","title":"Route"},{"location":"leaf/custom-tags/","text":"Custom Tags You can create custom Leaf tags using the TagRenderer protocol. To demonstrate this, let's take a look at creating a custom tag #now that prints the current timestamp. The tag will also support a single, optional parameter for specifying the date format. Tag Renderer First create a class called NowTag and conform it to TagRenderer . final class NowTag : TagRenderer { init () { } func render ( tag : TagContext ) throws - EventLoopFuture TemplateData { ... } } Now let's implement the render(tag:) method. The TagContext context passed to this method has everything we should need. let formatter = DateFormatter () switch tag . parameters . count { case 0 : formatter . dateFormat = yyyy-MM-dd HH:mm:ss case 1 : guard let string = tag . parameters [ 0 ]. string else { throw ... } formatter . dateFormat = string default : throw ... } let string = formatter . string ( from : . init ()) return tag . container . future (. string ( string )) Configure Tag Now that we've implemented NowTag , we just need to configure it. You can configure any TagRenderer like this--even if they come from a separate package. services . register { container - LeafTagConfig in var config = LeafTagConfig . default () config . use ( NowTag (), as : now ) return config } And that's it! We can now use our custom tag in Leaf. The time is #now ( )","title":"Custom tags"},{"location":"leaf/custom-tags/#custom-tags","text":"You can create custom Leaf tags using the TagRenderer protocol. To demonstrate this, let's take a look at creating a custom tag #now that prints the current timestamp. The tag will also support a single, optional parameter for specifying the date format.","title":"Custom Tags"},{"location":"leaf/custom-tags/#tag-renderer","text":"First create a class called NowTag and conform it to TagRenderer . final class NowTag : TagRenderer { init () { } func render ( tag : TagContext ) throws - EventLoopFuture TemplateData { ... } } Now let's implement the render(tag:) method. The TagContext context passed to this method has everything we should need. let formatter = DateFormatter () switch tag . parameters . count { case 0 : formatter . dateFormat = yyyy-MM-dd HH:mm:ss case 1 : guard let string = tag . parameters [ 0 ]. string else { throw ... } formatter . dateFormat = string default : throw ... } let string = formatter . string ( from : . init ()) return tag . container . future (. string ( string ))","title":"Tag Renderer"},{"location":"leaf/custom-tags/#configure-tag","text":"Now that we've implemented NowTag , we just need to configure it. You can configure any TagRenderer like this--even if they come from a separate package. services . register { container - LeafTagConfig in var config = LeafTagConfig . default () config . use ( NowTag (), as : now ) return config } And that's it! We can now use our custom tag in Leaf. The time is #now ( )","title":"Configure Tag"},{"location":"leaf/getting-started/","text":"Leaf Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API. Package The first step to using Leaf is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/leaf.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Leaf , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Configure Once you have added the package to your project, you can configure Vapor to use it. This is usually done in configure.swift . import Leaf try services . register ( LeafProvider ()) If your application supports multiple view renderers, you may need to specify that you would like to use Leaf. config . prefer ( LeafRenderer . self , for : ViewRenderer . self ) Folder Structure Once you have configured Leaf, you will need to ensure you have a Views folder to store your .leaf files in. By default, Leaf expects the views folder to be a ./Resources/Views relative to your project's root. You will also likely want to enable Vapor's FileMiddleware to serve files from your /Public folder. VaporApp \u251c\u2500\u2500 Package.swift \u251c\u2500\u2500 Resources \u2502 \u251c\u2500\u2500 Views \u2502 \u2502 \u2514\u2500\u2500 hello.leaf \u251c\u2500\u2500 Public \u2502 \u251c\u2500\u2500 images (images resources) \u2502 \u251c\u2500\u2500 styles (css resources) \u2514\u2500\u2500 Sources \u2514\u2500\u2500 ... Syntax Highlighting You may also wish to install one of these third-party packages that provide support for syntax highlighting in Leaf templates. Sublime Install the package Leaf from package control. Atom language-leaf by ButkiewiczP Xcode It is not currently possible to implement Leaf Syntax Highlighting in Xcode, however, using Xcode's HTML Syntax Coloring can help a bit. Select one or more Leaf files and then choose Editor Syntax Coloring HTML. Your selected Leaf files will now use Xcode's HTML Syntax Coloring. Unfortunately the usefulness of this is limited because this association will be removed when vapor xcode is run. There appears to be a way to make Xcode file associations persist but that requires a bit more kung-fu. VS Code html-leaf by FranciscoAmado CLion AppCode Some preliminary work has been done to implement a Leaf Plugin for CLion AppCode but lack of skill and interest in Java has slowed progress! If you have IntelliJ SDK experience and want to help with this, message Tom Holland on Vapor Slack Rendering a View Now that Leaf is configured, let's render your first template. Inside of the Resources/Views folder, create a new file called hello.leaf with the following contents: Hello, # ( name) ! Then, register a route (usually done in routes.swift or a controller) to render the view. import Leaf router . get ( hello ) { req - Future View in return try req . view (). render ( hello , [ name : Leaf ]) } Open your browser and visit /hello . You should see Hello, Leaf! . Congratulations on rendering your first Leaf view!","title":"Getting Started"},{"location":"leaf/getting-started/#leaf","text":"Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API.","title":"Leaf"},{"location":"leaf/getting-started/#package","text":"The first step to using Leaf is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/leaf.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Leaf , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] )","title":"Package"},{"location":"leaf/getting-started/#configure","text":"Once you have added the package to your project, you can configure Vapor to use it. This is usually done in configure.swift . import Leaf try services . register ( LeafProvider ()) If your application supports multiple view renderers, you may need to specify that you would like to use Leaf. config . prefer ( LeafRenderer . self , for : ViewRenderer . self )","title":"Configure"},{"location":"leaf/getting-started/#folder-structure","text":"Once you have configured Leaf, you will need to ensure you have a Views folder to store your .leaf files in. By default, Leaf expects the views folder to be a ./Resources/Views relative to your project's root. You will also likely want to enable Vapor's FileMiddleware to serve files from your /Public folder. VaporApp \u251c\u2500\u2500 Package.swift \u251c\u2500\u2500 Resources \u2502 \u251c\u2500\u2500 Views \u2502 \u2502 \u2514\u2500\u2500 hello.leaf \u251c\u2500\u2500 Public \u2502 \u251c\u2500\u2500 images (images resources) \u2502 \u251c\u2500\u2500 styles (css resources) \u2514\u2500\u2500 Sources \u2514\u2500\u2500 ...","title":"Folder Structure"},{"location":"leaf/getting-started/#syntax-highlighting","text":"You may also wish to install one of these third-party packages that provide support for syntax highlighting in Leaf templates.","title":"Syntax Highlighting"},{"location":"leaf/getting-started/#sublime","text":"Install the package Leaf from package control.","title":"Sublime"},{"location":"leaf/getting-started/#atom","text":"language-leaf by ButkiewiczP","title":"Atom"},{"location":"leaf/getting-started/#xcode","text":"It is not currently possible to implement Leaf Syntax Highlighting in Xcode, however, using Xcode's HTML Syntax Coloring can help a bit. Select one or more Leaf files and then choose Editor Syntax Coloring HTML. Your selected Leaf files will now use Xcode's HTML Syntax Coloring. Unfortunately the usefulness of this is limited because this association will be removed when vapor xcode is run. There appears to be a way to make Xcode file associations persist but that requires a bit more kung-fu.","title":"Xcode"},{"location":"leaf/getting-started/#vs-code","text":"html-leaf by FranciscoAmado","title":"VS Code"},{"location":"leaf/getting-started/#clion-appcode","text":"Some preliminary work has been done to implement a Leaf Plugin for CLion AppCode but lack of skill and interest in Java has slowed progress! If you have IntelliJ SDK experience and want to help with this, message Tom Holland on Vapor Slack","title":"CLion & AppCode"},{"location":"leaf/getting-started/#rendering-a-view","text":"Now that Leaf is configured, let's render your first template. Inside of the Resources/Views folder, create a new file called hello.leaf with the following contents: Hello, # ( name) ! Then, register a route (usually done in routes.swift or a controller) to render the view. import Leaf router . get ( hello ) { req - Future View in return try req . view (). render ( hello , [ name : Leaf ]) } Open your browser and visit /hello . You should see Hello, Leaf! . Congratulations on rendering your first Leaf view!","title":"Rendering a View"},{"location":"leaf/overview/","text":"Leaf Overview Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API. This guide will give you an overview of Leaf's syntax and the available tags. Template syntax Here is an example of a basic Leaf tag usage. There are #count ( users) users. Leaf tags are made up of four elements: Token # : This signals the leaf parser to begin looking for a tag. Name count : that identifies the tag. Parameter List (users) : May accept zero or more arguments. Body: An optional body can be supplied to some tags. This is similar to Swift's trailing-closure syntax. There can be many different usages of these four elements depending on the tag's implementation. Let's look at a few examples of how Leaf's built-in tags might be used: # ( variable) #embed ( template ) #set ( title ) { Welcome to Vapor } #count ( friends) #for ( friend in friends) { li # ( friend . name) /li } Leaf also supports many expressions you are familiar with in Swift. + == || etc. #if ( 1 + 1 == 2 ) { Hello! } Context In the example from Getting Started , we used a [String: String] dictionary to pass data to Leaf. However, you can pass anything that conforms to Encodable . It's actually preferred to use Encodable structs since [String: Any] is not supported. struct WelcomeContext : Encodable { var title : String var number : Int } return try req . view (). make ( home , WelcomeContext ( title : Hello! , number : 42 )) That will expose title and message to our Leaf template, which can then be used inside tags. For example: h1 # ( title) /h1 p # ( number) /p Usage Here are some common Leaf usage examples. Conditions Leaf is able to evaluate a range of conditions using its #if tag. For example, if you provide a variable it will check that variable exists in its context: #if ( title) { The title is # ( title) } else { No title was provided. } You can also write comparisons, for example: #if ( title == Welcome ) { This is a friendly web page. } else { No strangers allowed! } If you want to use another tag as part of your condition, you should omit the # for the inner tag. For example: #if ( lowercase (title) == welcome ) { This is a friendly web page. } else { No strangers allowed! } Just like in Swift, you can also use else if statement.s #if ( title == Welcome ) { This is a friendly web page. } else if ( 1 == 2 ) { What? } else { No strangers allowed! } Loops If you provide an array of items, Leaf can loop over them and let you manipulate each item individually using its #for tag. For example, we could update our Swift code to provide a list of planets: struct SolarSystem : Codable { let planets = [ Venus , Earth , Mars ] } return try req . view (). render (..., SolarSystem ()) We could then loop over them in Leaf like this: Planets: ul #for ( planet in planets) { li # ( planet) /li } /ul This would render a view that looks like: Planets: - Venus - Earth - Mars Leaf provides some extra variables inside a #for loop to give you more information about the loop's progress: The isFirst variable is true when the current iteration is the first one. The isLast variable is true when it's the last iteration. The index variable will be set to the number of the current iteration, counting from 0. Here's how we could use a loop variable to print just the first name in our array: #for ( planet in planets) { #if ( isFirst) { # ( planet) is first! } } Embedding templates Leaf\u2019s #embed tag allows you to copy the contents of one template into another. When use this, you should always omit the template file's .leaf extension. Embedding is useful for copying in a standard piece of content, for example a page footer or advert code: #embed ( footer ) This tag is also useful for building one template on top of another. For example, you might have a master.leaf file that includes all the code required to lay out your website \u2013 HTML structure, CSS and JavaScript \u2013 with some gaps in place that represent where page content varies. Using this approach, you would construct a child template that fills in its unique content, then embeds the parent template that places the content appropriately. For example, you might create a child.leaf template like this: #set ( body ) { p Welcome to Vapor! /p } #embed ( master ) That configures one item of context, body , but doesn\u2019t display it directly. Instead, it embeds master.leaf, which can render body along with any other context variables passed in from Swift. For example, master.leaf might look like this: html head title # ( title) /title /head body #get ( body) /body /html When given the context [\"title\": \"Hi there!\"] , child.leaf will render as follows: html head title Hi there! / title / head body p Welcome to Vapor! / p / body / html Comments You can write single or multiline comments with Leaf. They will be discarded when rendering the view. #// Say hello to the user Hello, # ( name) ! Multi-line comments are opened with #/* and closed with */ . #/* Say hello to the user */ Hello, # ( name) ! Other tags #date The #date tag formats dates into a readable string. render (..., [ now : Date ()]) The time is #date ( now) You can pass a custom date formatter string as the second argument. See Swift's DateFormatter for more information. The date is #date ( now, yyyy-MM-dd ) #capitalize The #capitalize tag uppercases the first letter of any string. #capitalize ( name) #contains The #contains tag accepts an array and a value as its two parameters, and returns true if the array in parameter one contains the value in parameter two. #if ( contains (planets, Earth )) { Earth is here! } else { Earth is not in this array. } #count The #count tag returns the number of items in an array. For example: Your search matched #count ( matches) pages. #lowercase The #lowercase tag lowercases all letters in a string. #lowercase ( name) #uppercase The #uppercase tag uppercases all letters in a string. #uppercase ( name)","title":"Overview"},{"location":"leaf/overview/#leaf-overview","text":"Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API. This guide will give you an overview of Leaf's syntax and the available tags.","title":"Leaf Overview"},{"location":"leaf/overview/#template-syntax","text":"Here is an example of a basic Leaf tag usage. There are #count ( users) users. Leaf tags are made up of four elements: Token # : This signals the leaf parser to begin looking for a tag. Name count : that identifies the tag. Parameter List (users) : May accept zero or more arguments. Body: An optional body can be supplied to some tags. This is similar to Swift's trailing-closure syntax. There can be many different usages of these four elements depending on the tag's implementation. Let's look at a few examples of how Leaf's built-in tags might be used: # ( variable) #embed ( template ) #set ( title ) { Welcome to Vapor } #count ( friends) #for ( friend in friends) { li # ( friend . name) /li } Leaf also supports many expressions you are familiar with in Swift. + == || etc. #if ( 1 + 1 == 2 ) { Hello! }","title":"Template syntax"},{"location":"leaf/overview/#context","text":"In the example from Getting Started , we used a [String: String] dictionary to pass data to Leaf. However, you can pass anything that conforms to Encodable . It's actually preferred to use Encodable structs since [String: Any] is not supported. struct WelcomeContext : Encodable { var title : String var number : Int } return try req . view (). make ( home , WelcomeContext ( title : Hello! , number : 42 )) That will expose title and message to our Leaf template, which can then be used inside tags. For example: h1 # ( title) /h1 p # ( number) /p","title":"Context"},{"location":"leaf/overview/#usage","text":"Here are some common Leaf usage examples.","title":"Usage"},{"location":"leaf/overview/#conditions","text":"Leaf is able to evaluate a range of conditions using its #if tag. For example, if you provide a variable it will check that variable exists in its context: #if ( title) { The title is # ( title) } else { No title was provided. } You can also write comparisons, for example: #if ( title == Welcome ) { This is a friendly web page. } else { No strangers allowed! } If you want to use another tag as part of your condition, you should omit the # for the inner tag. For example: #if ( lowercase (title) == welcome ) { This is a friendly web page. } else { No strangers allowed! } Just like in Swift, you can also use else if statement.s #if ( title == Welcome ) { This is a friendly web page. } else if ( 1 == 2 ) { What? } else { No strangers allowed! }","title":"Conditions"},{"location":"leaf/overview/#loops","text":"If you provide an array of items, Leaf can loop over them and let you manipulate each item individually using its #for tag. For example, we could update our Swift code to provide a list of planets: struct SolarSystem : Codable { let planets = [ Venus , Earth , Mars ] } return try req . view (). render (..., SolarSystem ()) We could then loop over them in Leaf like this: Planets: ul #for ( planet in planets) { li # ( planet) /li } /ul This would render a view that looks like: Planets: - Venus - Earth - Mars Leaf provides some extra variables inside a #for loop to give you more information about the loop's progress: The isFirst variable is true when the current iteration is the first one. The isLast variable is true when it's the last iteration. The index variable will be set to the number of the current iteration, counting from 0. Here's how we could use a loop variable to print just the first name in our array: #for ( planet in planets) { #if ( isFirst) { # ( planet) is first! } }","title":"Loops"},{"location":"leaf/overview/#embedding-templates","text":"Leaf\u2019s #embed tag allows you to copy the contents of one template into another. When use this, you should always omit the template file's .leaf extension. Embedding is useful for copying in a standard piece of content, for example a page footer or advert code: #embed ( footer ) This tag is also useful for building one template on top of another. For example, you might have a master.leaf file that includes all the code required to lay out your website \u2013 HTML structure, CSS and JavaScript \u2013 with some gaps in place that represent where page content varies. Using this approach, you would construct a child template that fills in its unique content, then embeds the parent template that places the content appropriately. For example, you might create a child.leaf template like this: #set ( body ) { p Welcome to Vapor! /p } #embed ( master ) That configures one item of context, body , but doesn\u2019t display it directly. Instead, it embeds master.leaf, which can render body along with any other context variables passed in from Swift. For example, master.leaf might look like this: html head title # ( title) /title /head body #get ( body) /body /html When given the context [\"title\": \"Hi there!\"] , child.leaf will render as follows: html head title Hi there! / title / head body p Welcome to Vapor! / p / body / html","title":"Embedding templates"},{"location":"leaf/overview/#comments","text":"You can write single or multiline comments with Leaf. They will be discarded when rendering the view. #// Say hello to the user Hello, # ( name) ! Multi-line comments are opened with #/* and closed with */ . #/* Say hello to the user */ Hello, # ( name) !","title":"Comments"},{"location":"leaf/overview/#other-tags","text":"","title":"Other tags"},{"location":"leaf/overview/#date","text":"The #date tag formats dates into a readable string. render (..., [ now : Date ()]) The time is #date ( now) You can pass a custom date formatter string as the second argument. See Swift's DateFormatter for more information. The date is #date ( now, yyyy-MM-dd )","title":"#date"},{"location":"leaf/overview/#capitalize","text":"The #capitalize tag uppercases the first letter of any string. #capitalize ( name)","title":"#capitalize"},{"location":"leaf/overview/#contains","text":"The #contains tag accepts an array and a value as its two parameters, and returns true if the array in parameter one contains the value in parameter two. #if ( contains (planets, Earth )) { Earth is here! } else { Earth is not in this array. }","title":"#contains"},{"location":"leaf/overview/#count","text":"The #count tag returns the number of items in an array. For example: Your search matched #count ( matches) pages.","title":"#count"},{"location":"leaf/overview/#lowercase","text":"The #lowercase tag lowercases all letters in a string. #lowercase ( name)","title":"#lowercase"},{"location":"leaf/overview/#uppercase","text":"The #uppercase tag uppercases all letters in a string. #uppercase ( name)","title":"#uppercase"},{"location":"logging/getting-started/","text":"Getting Started with Logging The Logging module is provided as a part of Vapor's Console package ( vapor/console ). This module provides convenience APIs for creating log Tip For an in-depth look at all of Logging's APIs, check out the Logging API docs . Usage This package is included with Vapor and exported by default. You will have access to all Logging APIs when you import Vapor . import Vapor // implies import Logging Standalone The Logging module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Logging , ... ]) ] ) Use import Logging to access the APIs. Overview Continue to Logging \u2192 Overview for an overview of Logging's features.","title":"Getting Started"},{"location":"logging/getting-started/#getting-started-with-logging","text":"The Logging module is provided as a part of Vapor's Console package ( vapor/console ). This module provides convenience APIs for creating log Tip For an in-depth look at all of Logging's APIs, check out the Logging API docs .","title":"Getting Started with Logging"},{"location":"logging/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Logging APIs when you import Vapor . import Vapor // implies import Logging","title":"Usage"},{"location":"logging/getting-started/#standalone","text":"The Logging module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Logging , ... ]) ] ) Use import Logging to access the APIs.","title":"Standalone"},{"location":"logging/getting-started/#overview","text":"Continue to Logging \u2192 Overview for an overview of Logging's features.","title":"Overview"},{"location":"logging/overview/","text":"Logging Overview The logging package provides convenience APIs for logging information while your app is running. The Logger protocol declares a common interface for logging information. A default PrintLogger is available, but you can implement custom loggers to suit your specific needs. Log First, you will want to use a Container to create an instance of Logger . Then you can use the convenience methods to log information. let logger = try req . make ( Logger . self ) logger . info ( Logger created! ) See Logger in the API docs for a list of all available methods. Check out Service Services for more information on how to register a custom logger.","title":"Overview"},{"location":"logging/overview/#logging-overview","text":"The logging package provides convenience APIs for logging information while your app is running. The Logger protocol declares a common interface for logging information. A default PrintLogger is available, but you can implement custom loggers to suit your specific needs.","title":"Logging Overview"},{"location":"logging/overview/#log","text":"First, you will want to use a Container to create an instance of Logger . Then you can use the convenience methods to log information. let logger = try req . make ( Logger . self ) logger . info ( Logger created! ) See Logger in the API docs for a list of all available methods. Check out Service Services for more information on how to register a custom logger.","title":"Log"},{"location":"multipart/getting-started/","text":"Getting Started with Multipart Multipart ( vapor/multipart ) is a small package that helps you parse and serialize multipart encoded data. Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. The Multipart package makes it easy to use this encoding by integrating directly with Codable . Vapor This package is included with Vapor and exported by default. You will have access to all Multipart APIs when you import Vapor . import Vapor Standalone The Multipart package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with multipart-encoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/multipart.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Multipart , ... ]) ] ) Use import Multipart to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Multipart package in general. Visit the API Docs for Multipart-specific API info.","title":"Getting Started"},{"location":"multipart/getting-started/#getting-started-with-multipart","text":"Multipart ( vapor/multipart ) is a small package that helps you parse and serialize multipart encoded data. Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. The Multipart package makes it easy to use this encoding by integrating directly with Codable .","title":"Getting Started with Multipart"},{"location":"multipart/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Multipart APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"multipart/getting-started/#standalone","text":"The Multipart package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with multipart-encoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/multipart.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Multipart , ... ]) ] ) Use import Multipart to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Multipart package in general. Visit the API Docs for Multipart-specific API info.","title":"Standalone"},{"location":"multipart/overview/","text":"Using Multipart Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. It allows for arbitrary data to be encoded in each part thanks to a unique delimiter boundary that is defined separately. This boundary is guaranteed by the client to not appear anywhere in the data. Multipart is a powerful encoding, however it is rarely used in its base format. Most commonly, multipart/form-data is used. This encoding adds a \"name\" property to each part of the multipart data. This is required for serializing web forms. For the rest of this guide, assume we are talking about multipart/form-data unless otherwise specified. Tip Multipart integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a multipart/form-data -encoded request. Decode Most often, you will be decoding multipart/form-data -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like. Request Here is an example multipart/form-data -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : multipart/form-data; boundary=123 --123 Content-Disposition: form-data; name= name Vapor --123 Content-Disposition: form-data; name= age 3 --123 Content-Disposition: form-data; name= image ; filename= droplet.png contents of image --123-- You can see the multipart data uses a boundary (in this case it is \"123\" ) to separate the data. This will usually be a longer string. The client sending a multipart-encoded request must ensure that the boundary it supplies does not appear anywhere in the content it is sending you. That's what allows this encoding to be used to send things like files. Form There are many ways to create a multipart-encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users enctype = multipart/form-data input type = text name = name input type = text name = age input type = file name = image / form Take note of the enctype attribute on the form as well as the file type input. This is what allows us to send files via the web form. Content Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var image : Data } Tip You can use File instead of Data if you would also like to access the filename. Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . image ) // Raw image data return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work! Encode APIs encode multipart data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a multipart-encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , image : Data (...)) res . content . encode ( user , as : . formData ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure. Parsing Serializing The Multipart package also offers APIs for parsing and serializing multipart/form-data data without using Codable . Check out the API Docs for more information on using those APIs.","title":"Overview"},{"location":"multipart/overview/#using-multipart","text":"Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. It allows for arbitrary data to be encoded in each part thanks to a unique delimiter boundary that is defined separately. This boundary is guaranteed by the client to not appear anywhere in the data. Multipart is a powerful encoding, however it is rarely used in its base format. Most commonly, multipart/form-data is used. This encoding adds a \"name\" property to each part of the multipart data. This is required for serializing web forms. For the rest of this guide, assume we are talking about multipart/form-data unless otherwise specified. Tip Multipart integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a multipart/form-data -encoded request.","title":"Using Multipart"},{"location":"multipart/overview/#decode","text":"Most often, you will be decoding multipart/form-data -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like.","title":"Decode"},{"location":"multipart/overview/#request","text":"Here is an example multipart/form-data -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : multipart/form-data; boundary=123 --123 Content-Disposition: form-data; name= name Vapor --123 Content-Disposition: form-data; name= age 3 --123 Content-Disposition: form-data; name= image ; filename= droplet.png contents of image --123-- You can see the multipart data uses a boundary (in this case it is \"123\" ) to separate the data. This will usually be a longer string. The client sending a multipart-encoded request must ensure that the boundary it supplies does not appear anywhere in the content it is sending you. That's what allows this encoding to be used to send things like files.","title":"Request"},{"location":"multipart/overview/#form","text":"There are many ways to create a multipart-encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users enctype = multipart/form-data input type = text name = name input type = text name = age input type = file name = image / form Take note of the enctype attribute on the form as well as the file type input. This is what allows us to send files via the web form.","title":"Form"},{"location":"multipart/overview/#content","text":"Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var image : Data } Tip You can use File instead of Data if you would also like to access the filename. Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . image ) // Raw image data return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work!","title":"Content"},{"location":"multipart/overview/#encode","text":"APIs encode multipart data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a multipart-encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , image : Data (...)) res . content . encode ( user , as : . formData ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure.","title":"Encode"},{"location":"multipart/overview/#parsing-serializing","text":"The Multipart package also offers APIs for parsing and serializing multipart/form-data data without using Codable . Check out the API Docs for more information on using those APIs.","title":"Parsing & Serializing"},{"location":"mysql/getting-started/","text":"MySQL MySQL ( vapor/mysql ) is a pure Swift MySQL (and MariaDB) client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the MySQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. MySQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent MySQL , all of the features of MySQL core will be available to you. Getting Started Let's take a look at how you can get started using MySQL core. Package The first step to using MySQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc2c Pure Swift MySQL client built on non-blocking, event-driven sockets. . package ( url : https://github.com/vapor/mysql.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ MySQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Config The next step is to configure the database in configure.swift . import MySQL /// Register providers first try services . register ( MySQLProvider ()) Registering the provider will add all of the services required for MySQL to work properly. It also includes a default database config struct that uses standard credentials. Customizing Config You can of course override the default configuration provided by MySQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a MySQL database let mysql = try MySQLDatabase ( config : MySQLDatabaseConfig (...)) /// Register the configured MySQL database to the database config. var databases = DatabasesConfig () databases . add ( database : mysql , as : . mysql ) services . register ( databases ) See MySQLDatabase and MySQLDatabaseConfig for more information. MySQL's default database identifier is .mysql . You can create a custom identifier if you want by extending DatabaseIdentifier . Query Now that the database is configured, you can make your first query. struct MySQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . mysql ) { conn in return conn . raw ( SELECT @@version as version ) . all ( decoding : MySQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your MySQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit MySQL's API docs for detailed information about all available types and methods.","title":"Getting Started"},{"location":"mysql/getting-started/#mysql","text":"MySQL ( vapor/mysql ) is a pure Swift MySQL (and MariaDB) client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the MySQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. MySQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent MySQL , all of the features of MySQL core will be available to you.","title":"MySQL"},{"location":"mysql/getting-started/#getting-started","text":"Let's take a look at how you can get started using MySQL core.","title":"Getting Started"},{"location":"mysql/getting-started/#package","text":"The first step to using MySQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc2c Pure Swift MySQL client built on non-blocking, event-driven sockets. . package ( url : https://github.com/vapor/mysql.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ MySQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"mysql/getting-started/#config","text":"The next step is to configure the database in configure.swift . import MySQL /// Register providers first try services . register ( MySQLProvider ()) Registering the provider will add all of the services required for MySQL to work properly. It also includes a default database config struct that uses standard credentials.","title":"Config"},{"location":"mysql/getting-started/#customizing-config","text":"You can of course override the default configuration provided by MySQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a MySQL database let mysql = try MySQLDatabase ( config : MySQLDatabaseConfig (...)) /// Register the configured MySQL database to the database config. var databases = DatabasesConfig () databases . add ( database : mysql , as : . mysql ) services . register ( databases ) See MySQLDatabase and MySQLDatabaseConfig for more information. MySQL's default database identifier is .mysql . You can create a custom identifier if you want by extending DatabaseIdentifier .","title":"Customizing Config"},{"location":"mysql/getting-started/#query","text":"Now that the database is configured, you can make your first query. struct MySQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . mysql ) { conn in return conn . raw ( SELECT @@version as version ) . all ( decoding : MySQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your MySQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit MySQL's API docs for detailed information about all available types and methods.","title":"Query"},{"location":"postgresql/getting-started/","text":"PostgreSQL PostgreSQL ( vapor/postgresql ) is a pure Swift PostgreSQL client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the PostgreSQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. PostgreSQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent PostgreSQL , all of the features of PostgreSQL core will be available to you. Getting Started Let's take a look at how you can get started using PostgreSQL core. Package The first step to using PostgreSQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc18 Non-blocking, event-driven Swift client for PostgreSQL. . package ( url : https://github.com/vapor/postgresql.git , from : 1.0.0 ), ], targets : [ . target ( name : App , dependencies : [ PostgreSQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Config The next step is to configure the database in configure.swift . import PostgreSQL /// Register providers first try services . register ( PostgreSQLProvider ()) Registering the provider will add all of the services required for PostgreSQL to work properly. It also includes a default database config struct that uses standard credentials. Customizing Config You can of course override the default configuration provided by PostgreSQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a PostgreSQL database let postgresql = try PostgreSQLDatabase ( config : PostgreSQLDatabaseConfig (...)) /// Register the configured PostgreSQL database to the database config. var databases = DatabasesConfig () databases . add ( database : postgresql , as : . psql ) services . register ( databases ) See PostgreSQLDatabase and PostgreSQLDatabaseConfig for more information. PostgreSQL's default database identifier is .psql . You can create a custom identifier if you want by extending DatabaseIdentifier . Query Now that the database is configured, you can make your first query. struct PostgreSQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . psql ) { conn in return conn . raw ( SELECT version() ) . all ( decoding : PostgreSQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your PostgreSQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit PostgreSQL's API docs for detailed information about all available types and methods.","title":"Getting Started"},{"location":"postgresql/getting-started/#postgresql","text":"PostgreSQL ( vapor/postgresql ) is a pure Swift PostgreSQL client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the PostgreSQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. PostgreSQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent PostgreSQL , all of the features of PostgreSQL core will be available to you.","title":"PostgreSQL"},{"location":"postgresql/getting-started/#getting-started","text":"Let's take a look at how you can get started using PostgreSQL core.","title":"Getting Started"},{"location":"postgresql/getting-started/#package","text":"The first step to using PostgreSQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc18 Non-blocking, event-driven Swift client for PostgreSQL. . package ( url : https://github.com/vapor/postgresql.git , from : 1.0.0 ), ], targets : [ . target ( name : App , dependencies : [ PostgreSQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"postgresql/getting-started/#config","text":"The next step is to configure the database in configure.swift . import PostgreSQL /// Register providers first try services . register ( PostgreSQLProvider ()) Registering the provider will add all of the services required for PostgreSQL to work properly. It also includes a default database config struct that uses standard credentials.","title":"Config"},{"location":"postgresql/getting-started/#customizing-config","text":"You can of course override the default configuration provided by PostgreSQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a PostgreSQL database let postgresql = try PostgreSQLDatabase ( config : PostgreSQLDatabaseConfig (...)) /// Register the configured PostgreSQL database to the database config. var databases = DatabasesConfig () databases . add ( database : postgresql , as : . psql ) services . register ( databases ) See PostgreSQLDatabase and PostgreSQLDatabaseConfig for more information. PostgreSQL's default database identifier is .psql . You can create a custom identifier if you want by extending DatabaseIdentifier .","title":"Customizing Config"},{"location":"postgresql/getting-started/#query","text":"Now that the database is configured, you can make your first query. struct PostgreSQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . psql ) { conn in return conn . raw ( SELECT version() ) . all ( decoding : PostgreSQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your PostgreSQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit PostgreSQL's API docs for detailed information about all available types and methods.","title":"Query"},{"location":"redis/getting-started/","text":"Getting Started with Redis Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface. Let's take a look at how you can get started using Redis. Package The first step to using Redis is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \u26a1\ufe0fNon-blocking, event-driven Redis client. . package ( url : https://github.com/vapor/redis.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Redis , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Provider Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Redis // register Redis provider try services . register ( RedisProvider ()) That's it for basic setup. The next step is to create a Redis connection and send a command. Command First, create a new connection to your Redis database. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. See DatabaseKit Overview for more information. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } Once you have a connection, you can use it to send a command. Let's send the \"INFO\" command which should return information about our Redis server. // send INFO command to redis return redis . command ( INFO ) // map the resulting RedisData to a String . map { $0 . string ?? } Run your app and query GET /redis . You should see information about your Redis server printed as output. Congratulations!","title":"Getting Started"},{"location":"redis/getting-started/#getting-started-with-redis","text":"Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface. Let's take a look at how you can get started using Redis.","title":"Getting Started with Redis"},{"location":"redis/getting-started/#package","text":"The first step to using Redis is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \u26a1\ufe0fNon-blocking, event-driven Redis client. . package ( url : https://github.com/vapor/redis.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Redis , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] )","title":"Package"},{"location":"redis/getting-started/#provider","text":"Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Redis // register Redis provider try services . register ( RedisProvider ()) That's it for basic setup. The next step is to create a Redis connection and send a command.","title":"Provider"},{"location":"redis/getting-started/#command","text":"First, create a new connection to your Redis database. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. See DatabaseKit Overview for more information. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } Once you have a connection, you can use it to send a command. Let's send the \"INFO\" command which should return information about our Redis server. // send INFO command to redis return redis . command ( INFO ) // map the resulting RedisData to a String . map { $0 . string ?? } Run your app and query GET /redis . You should see information about your Redis server printed as output. Congratulations!","title":"Command"},{"location":"redis/overview/","text":"Using Redis Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface. Redis Commands Let's take a look at how to send and recieve data using Redis commands. Connection The first thing you will need to send a Redis command is a connection. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. For this example, we will use the withNewConnection(to:) method to create a new connection to Redis. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } See DatabaseKit Overview for more information. Available Commands See RedisClient for a list of all available commands. Here we'll take a look at some common commands. Get / Set Redis's GET and SET commands allow you to store and later retrieve data from the server. You can pass any Codable type as the value to this command. router . get ( set ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // save a new key/value pair to the cache return redis . set ( hello , to : world ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } router . get ( get ) { req - Future String in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . get ( hello , as : String . self ) // handle nil case . map { $0 ?? } } } Delete Redis's DELETE command allows you to clear a previously stored key/value pair. router . get ( del ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . delete ( hello ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } See RedisClient for a list of all available commands. Keyed Cache You can also use Redis as the backend to Vapor's KeyedCache protocol. router . get ( set ) { req - Future HTTPStatus in let string = try req . query . get ( String . self , at : string ) return try req . keyedCache ( for : . redis ). set ( string , to : string ) . transform ( to : . ok ) } router . get ( get ) { req - Future String in return try req . keyedCache ( for : . redis ). get ( string , as : String . self ) . unwrap ( or : Abort (. badRequest , reason : No string set yet. )) } See DatabaseKit Overview for more information.","title":"Overview"},{"location":"redis/overview/#using-redis","text":"Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface.","title":"Using Redis"},{"location":"redis/overview/#redis-commands","text":"Let's take a look at how to send and recieve data using Redis commands.","title":"Redis Commands"},{"location":"redis/overview/#connection","text":"The first thing you will need to send a Redis command is a connection. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. For this example, we will use the withNewConnection(to:) method to create a new connection to Redis. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } See DatabaseKit Overview for more information.","title":"Connection"},{"location":"redis/overview/#available-commands","text":"See RedisClient for a list of all available commands. Here we'll take a look at some common commands.","title":"Available Commands"},{"location":"redis/overview/#get-set","text":"Redis's GET and SET commands allow you to store and later retrieve data from the server. You can pass any Codable type as the value to this command. router . get ( set ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // save a new key/value pair to the cache return redis . set ( hello , to : world ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } router . get ( get ) { req - Future String in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . get ( hello , as : String . self ) // handle nil case . map { $0 ?? } } }","title":"Get / Set"},{"location":"redis/overview/#delete","text":"Redis's DELETE command allows you to clear a previously stored key/value pair. router . get ( del ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . delete ( hello ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } See RedisClient for a list of all available commands.","title":"Delete"},{"location":"redis/overview/#keyed-cache","text":"You can also use Redis as the backend to Vapor's KeyedCache protocol. router . get ( set ) { req - Future HTTPStatus in let string = try req . query . get ( String . self , at : string ) return try req . keyedCache ( for : . redis ). set ( string , to : string ) . transform ( to : . ok ) } router . get ( get ) { req - Future String in return try req . keyedCache ( for : . redis ). get ( string , as : String . self ) . unwrap ( or : Abort (. badRequest , reason : No string set yet. )) } See DatabaseKit Overview for more information.","title":"Keyed Cache"},{"location":"routing/getting-started/","text":"Routing Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. For example, the routing package can help you route a request like the following and collect the values of the dynamic components. /users/:user_id/comments/:comment_id Vapor This package is included with Vapor and exported by default. You will have access to all Routing APIs when you import Vapor . Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See Getting Started Routing for more information. import Vapor Standalone The Routing package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a routing framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/routing.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Routing , ... ]) ] ) Use import Routing to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Routing package in general. Visit the API Docs for Routing-specific API info.","title":"Getting Started"},{"location":"routing/getting-started/#routing","text":"Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. For example, the routing package can help you route a request like the following and collect the values of the dynamic components. /users/:user_id/comments/:comment_id","title":"Routing"},{"location":"routing/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Routing APIs when you import Vapor . Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See Getting Started Routing for more information. import Vapor","title":"Vapor"},{"location":"routing/getting-started/#standalone","text":"The Routing package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a routing framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/routing.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Routing , ... ]) ] ) Use import Routing to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Routing package in general. Visit the API Docs for Routing-specific API info.","title":"Standalone"},{"location":"routing/overview/","text":"Routing Overview Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See [Vapor \u2192 Routing] for more information. This guide will show you how to register a static route and a dynamic route and how to use Parameter s. Register The first step to routing is to register some routes. Let's take a look at how to do that with a simple router a TrieRouter Double which holds numbers. Usually you would store something like HTTP responders, but we'll keep things simple for this example. // Create a router that stores Doubles let router = TrieRouter ( Double . self ) // Register some routes and values to the router router . register ( route : Route ( path : [ funny , meaning_of_universe ], output : 42 )) router . register ( route : Route ( path : [ funny , leet ], output : 1337 )) router . register ( route : Route ( path : [ math , pi ], output : 3.14 )) // Create empty Parameters to hold dynamic params (none yet) var params = Parameters () // Test fetching some routes print ( router . route ( path : [ fun , meaning_of_universe ], parameters : params )) // 42 print ( router . route ( path : [ foo ], parameters : params )) // nil Here we are using register(...) to register routes to our router, then later route(...) to fetch them. The TrieRouter uses a trie (digital tree) internally to make finding value in the router fast. Parameter Let's take a look at registering some dynamic path components. These are parts of the path that are variable and whose value should be collected for later use. You will often see this used for situations like show a webpage for a user: /users/:user_id Here is how you would implement that with TrieRouter . For this example, we will ignore the route output. // Create a route for /users/:user_id let user = Route ( path : [. constant ( users ), . parameter ( user_id )], output : ...) // Create a router and register our route let router = TrieRouter (...) router . register ( route : user ) // Create empty Parameters to hold dynamic values var params = Parameters () // Route the path /users/42 _ = router . route ( path : [ users , 42 ], parameters : params ) // The params contains our dynamic value! print ( params ) // [ user_id : 42 ] Note that the String used for .parameter(...) will be the key to fetch the value from Parameters . API Docs Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"Overview"},{"location":"routing/overview/#routing-overview","text":"Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See [Vapor \u2192 Routing] for more information. This guide will show you how to register a static route and a dynamic route and how to use Parameter s.","title":"Routing Overview"},{"location":"routing/overview/#register","text":"The first step to routing is to register some routes. Let's take a look at how to do that with a simple router a TrieRouter Double which holds numbers. Usually you would store something like HTTP responders, but we'll keep things simple for this example. // Create a router that stores Doubles let router = TrieRouter ( Double . self ) // Register some routes and values to the router router . register ( route : Route ( path : [ funny , meaning_of_universe ], output : 42 )) router . register ( route : Route ( path : [ funny , leet ], output : 1337 )) router . register ( route : Route ( path : [ math , pi ], output : 3.14 )) // Create empty Parameters to hold dynamic params (none yet) var params = Parameters () // Test fetching some routes print ( router . route ( path : [ fun , meaning_of_universe ], parameters : params )) // 42 print ( router . route ( path : [ foo ], parameters : params )) // nil Here we are using register(...) to register routes to our router, then later route(...) to fetch them. The TrieRouter uses a trie (digital tree) internally to make finding value in the router fast.","title":"Register"},{"location":"routing/overview/#parameter","text":"Let's take a look at registering some dynamic path components. These are parts of the path that are variable and whose value should be collected for later use. You will often see this used for situations like show a webpage for a user: /users/:user_id Here is how you would implement that with TrieRouter . For this example, we will ignore the route output. // Create a route for /users/:user_id let user = Route ( path : [. constant ( users ), . parameter ( user_id )], output : ...) // Create a router and register our route let router = TrieRouter (...) router . register ( route : user ) // Create empty Parameters to hold dynamic values var params = Parameters () // Route the path /users/42 _ = router . route ( path : [ users , 42 ], parameters : params ) // The params contains our dynamic value! print ( params ) // [ user_id : 42 ] Note that the String used for .parameter(...) will be the key to fetch the value from Parameters .","title":"Parameter"},{"location":"routing/overview/#api-docs","text":"Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"API Docs"},{"location":"service/getting-started/","text":"Getting Started with Service Service ( vapor/service ) is a dependency injection (inversion of control) framework. It allows you to register, configure, and create your application's dependencies in a maintainable way. /// register a service during boot services . register ( PrintLogger . self , as : Logger . self ) /// you can then create that service later let logger = try someContainer . make ( Logger . self ) print ( logger is PrintLogger ) // true You can read more about dependency injection on Wikipedia. Also be sure to check out the Getting Started Services guide. Vapor This package is included with Vapor and exported by default. You will have access to all Service APIs when you import Vapor . import Vapor Standalone The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a dependency injection framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/service.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Service , ... ]) ] ) Use import Service to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Services package in general. Visit the API Docs for Service-specific API info.","title":"Getting Started"},{"location":"service/getting-started/#getting-started-with-service","text":"Service ( vapor/service ) is a dependency injection (inversion of control) framework. It allows you to register, configure, and create your application's dependencies in a maintainable way. /// register a service during boot services . register ( PrintLogger . self , as : Logger . self ) /// you can then create that service later let logger = try someContainer . make ( Logger . self ) print ( logger is PrintLogger ) // true You can read more about dependency injection on Wikipedia. Also be sure to check out the Getting Started Services guide.","title":"Getting Started with Service"},{"location":"service/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Service APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"service/getting-started/#standalone","text":"The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a dependency injection framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/service.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Service , ... ]) ] ) Use import Service to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Services package in general. Visit the API Docs for Service-specific API info.","title":"Standalone"},{"location":"service/provider/","text":"Using Providers The Provider protocol make it easy to integrate external services into your application. All of Vapor's official packages, like Fluent , use the provider system to expose their services. Providers can: Register services to your Services struct. Hook into your Container 's lifecycle. Register Once you have added a Service-exposing SPM dependency to your project, adding the provider is easy. import Foo try services . register ( FooProvider ()) This is usually done in configure.swift . Note You can search GitHub for the vapor-service tag for a list of packages that expose services using this method. Create Creating a custom provider can be a great way to organize your code. You will also want to create a provider if you are working on a third-party package for Vapor. Here is what a simple provider would look like for the Logger examples from the Services section. public final class LoggerProvider : Provider { /// See `Provider`. public func register ( _ services : inout Services ) throws { services . register ( PrintLogger . self ) services . register ( FileLogger . self ) } /// See `Provider`. public func didBoot ( _ container : Container ) throws - Future Void { let logger = try container . make ( Logger . self ) logger . log ( Hello from LoggerProvider! ) return . done ( on : container ) } } Now when someone registers the LoggerProvider to their Services struct, it will automatically register the print and file loggers. When the container boots, the success message will be printed to verify the provider was added. See the Provider protocol's API docs for more information.","title":"Provider"},{"location":"service/provider/#using-providers","text":"The Provider protocol make it easy to integrate external services into your application. All of Vapor's official packages, like Fluent , use the provider system to expose their services. Providers can: Register services to your Services struct. Hook into your Container 's lifecycle.","title":"Using Providers"},{"location":"service/provider/#register","text":"Once you have added a Service-exposing SPM dependency to your project, adding the provider is easy. import Foo try services . register ( FooProvider ()) This is usually done in configure.swift . Note You can search GitHub for the vapor-service tag for a list of packages that expose services using this method.","title":"Register"},{"location":"service/provider/#create","text":"Creating a custom provider can be a great way to organize your code. You will also want to create a provider if you are working on a third-party package for Vapor. Here is what a simple provider would look like for the Logger examples from the Services section. public final class LoggerProvider : Provider { /// See `Provider`. public func register ( _ services : inout Services ) throws { services . register ( PrintLogger . self ) services . register ( FileLogger . self ) } /// See `Provider`. public func didBoot ( _ container : Container ) throws - Future Void { let logger = try container . make ( Logger . self ) logger . log ( Hello from LoggerProvider! ) return . done ( on : container ) } } Now when someone registers the LoggerProvider to their Services struct, it will automatically register the print and file loggers. When the container boots, the success message will be printed to verify the provider was added. See the Provider protocol's API docs for more information.","title":"Create"},{"location":"service/services/","text":"Using Services This guide will show you how to register, configure, and create your own service. In this example we will be assuming two different Logger implementations. PrintLogger : Prints logs. FileLogger : Saves logs to a file. Already conforms to ServiceType . Register Let's take a look at how we can register our PrintLogger . First you must conform your type to Service . The easiest way to do this is simply adding the conformance in an extension. extension PrintLogger : Service { } It's an empty protocol so there should be no missing requirements. Factory Now the service can be registered to the Services struct. This is usually done in configure.swift . services . register ( Logger . self ) { container in return PrintLogger () } By registering the PrintLogger using a factory (closure) method, we allow the Container to dynamically create the service once it is needed. Any SubContainer s created later can call this method again to create their own PrintLogger s. Service Type To make registering a service easier, you can conform it to ServiceType . extension PrintLogger : ServiceType { /// See `ServiceType`. static var serviceSupports : [ Any . Type ] { return [ Logger . self ] } /// See `ServiceType`. static func makeService ( for worker : Container ) throws - PrintLogger { return PrintLogger () } } Services conforming to ServiceType can be registered using just the type name. This will automatically conform to Service as well. services . register ( PrintLogger . self ) Instance You can also register pre-initialized instances to Services . services . register ( PrintLogger (), as : Logger . self ) Warning If using reference types ( class ) this method will share the same object between all Container s and SubContainer s. Be careful to protect against race conditions. Configure If more than one service is registered for a given interface, we will need to choose which service is used. services . register ( PrintLogger . self ) services . register ( FileLogger . self ) Assuming the above services are registered, we can use service Config to pick which one we want. switch env { case . production : config . prefer ( FileLogger . self , for : Logger . self ) default : config . prefer ( PrintLogger . self , for : Logger . self ) } Here we are using the Environment to dynamically prefer a service. This is usually done in configure.swift . Note You can also dynamically register services based on environment instead of using service config. However, service config is required for choosing services that come from the framework or a provider. Create After you have registered your services, you can use a Container to create them. let logger = try someContainer . make ( Logger . self ) logger . log ( Hello, world! ) // PrintLogger or FileLogger depending on the container s environment print ( type ( of : logger )) Tip Usually the framework will create any required containers for you. You can use BasicContainer if you want to create one for testing.","title":"Services"},{"location":"service/services/#using-services","text":"This guide will show you how to register, configure, and create your own service. In this example we will be assuming two different Logger implementations. PrintLogger : Prints logs. FileLogger : Saves logs to a file. Already conforms to ServiceType .","title":"Using Services"},{"location":"service/services/#register","text":"Let's take a look at how we can register our PrintLogger . First you must conform your type to Service . The easiest way to do this is simply adding the conformance in an extension. extension PrintLogger : Service { } It's an empty protocol so there should be no missing requirements.","title":"Register"},{"location":"service/services/#factory","text":"Now the service can be registered to the Services struct. This is usually done in configure.swift . services . register ( Logger . self ) { container in return PrintLogger () } By registering the PrintLogger using a factory (closure) method, we allow the Container to dynamically create the service once it is needed. Any SubContainer s created later can call this method again to create their own PrintLogger s.","title":"Factory"},{"location":"service/services/#service-type","text":"To make registering a service easier, you can conform it to ServiceType . extension PrintLogger : ServiceType { /// See `ServiceType`. static var serviceSupports : [ Any . Type ] { return [ Logger . self ] } /// See `ServiceType`. static func makeService ( for worker : Container ) throws - PrintLogger { return PrintLogger () } } Services conforming to ServiceType can be registered using just the type name. This will automatically conform to Service as well. services . register ( PrintLogger . self )","title":"Service Type"},{"location":"service/services/#instance","text":"You can also register pre-initialized instances to Services . services . register ( PrintLogger (), as : Logger . self ) Warning If using reference types ( class ) this method will share the same object between all Container s and SubContainer s. Be careful to protect against race conditions.","title":"Instance"},{"location":"service/services/#configure","text":"If more than one service is registered for a given interface, we will need to choose which service is used. services . register ( PrintLogger . self ) services . register ( FileLogger . self ) Assuming the above services are registered, we can use service Config to pick which one we want. switch env { case . production : config . prefer ( FileLogger . self , for : Logger . self ) default : config . prefer ( PrintLogger . self , for : Logger . self ) } Here we are using the Environment to dynamically prefer a service. This is usually done in configure.swift . Note You can also dynamically register services based on environment instead of using service config. However, service config is required for choosing services that come from the framework or a provider.","title":"Configure"},{"location":"service/services/#create","text":"After you have registered your services, you can use a Container to create them. let logger = try someContainer . make ( Logger . self ) logger . log ( Hello, world! ) // PrintLogger or FileLogger depending on the container s environment print ( type ( of : logger )) Tip Usually the framework will create any required containers for you. You can use BasicContainer if you want to create one for testing.","title":"Create"},{"location":"sql/getting-started/","text":"Getting Started with SQL SQL ( vapor/sql ) is a library for building and serializing SQL queries in Swift. It has an extensible, protocol-based design and supports DQL, DML, and DDL. Tip If you use Fluent, you will usually not need to build SQL queries manually. Choosing a Driver Vapor's SQL database packages are built on top of this library. database repo version dbid notes PostgreSQL postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. Once you have selected a driver and added it to your Package.swift file, you can continue following this guide.","title":"Getting Started"},{"location":"sql/getting-started/#getting-started-with-sql","text":"SQL ( vapor/sql ) is a library for building and serializing SQL queries in Swift. It has an extensible, protocol-based design and supports DQL, DML, and DDL. Tip If you use Fluent, you will usually not need to build SQL queries manually.","title":"Getting Started with SQL"},{"location":"sql/getting-started/#choosing-a-driver","text":"Vapor's SQL database packages are built on top of this library. database repo version dbid notes PostgreSQL postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. Once you have selected a driver and added it to your Package.swift file, you can continue following this guide.","title":"Choosing a Driver"},{"location":"sql/overview/","text":"Using SQL The SQL library helps you build and serialize SQL queries in Swift. It has an extensible, protocol-based design that supports many standard SQL queries like: SELECT , INSERT , UPDATE , DELETE CREATE TABLE , ALTER TABLE , DROP TABLE CREATE INDEX , DROP INDEX This package also integrates deeply with Codable and parameter binding to make working with your database fast and secure. This guide assumes you have already chosen and configured a driver in SQL Getting Started . In some cases, these SQL dialects will have different syntaxes or supported features. Be sure to check their API docs for additional functionality. Connection The first step to building a SQL query is getting access to a connection. Most often, you will use withPooledConnection(to:) followed by your database's dbid . Note Refer to the table in SQL Getting Started for your database's default dbid . The dbid allows you to use multiple databases per application. router . get ( sql ) { req in return req . withPooledConnection ( to : . # dbid # ) { conn in return // use conn to perform a query } } Check out Database Kit Overview Connections for more information. The rest of this guide will assume you have access to a SQL database connection. Select Use the select() method on a connection to create a SQLSelectBuilder . This builder helps you create SELECT statements and supports: * , columns, and expressions like functions FROM JOIN GROUP BY ORDER BY The select builder conforms to SQLPredicateBuilder for building WHERE predicates. It also conforms to SQLQueryFetcher for decoding Codable models from the result set. Let's take a look at an example SELECT query. Replace the Xcode placeholder with the name of the database you are using, i.e., SQLite . struct User : SQLTable , Codable { static let sqlTableIdentifierString = users let id : Int ? let name : String } let users = conn . select () . all (). from ( User . self ) . where ( \\ User . name == Vapor ) . all ( decoding : User . self ) print ( users ) // Future [User] The resulting SQL will look something like this: SELECT * FROM users WHERE users . name = ? As you can see, the Swift code reads similarly to actual SQL. Be sure to visit the API docs for the various builder protocols to see all available methods. API Docs Check out the API docs for more in-depth information about SQL's APIs.","title":"Overview"},{"location":"sql/overview/#using-sql","text":"The SQL library helps you build and serialize SQL queries in Swift. It has an extensible, protocol-based design that supports many standard SQL queries like: SELECT , INSERT , UPDATE , DELETE CREATE TABLE , ALTER TABLE , DROP TABLE CREATE INDEX , DROP INDEX This package also integrates deeply with Codable and parameter binding to make working with your database fast and secure. This guide assumes you have already chosen and configured a driver in SQL Getting Started . In some cases, these SQL dialects will have different syntaxes or supported features. Be sure to check their API docs for additional functionality.","title":"Using SQL"},{"location":"sql/overview/#connection","text":"The first step to building a SQL query is getting access to a connection. Most often, you will use withPooledConnection(to:) followed by your database's dbid . Note Refer to the table in SQL Getting Started for your database's default dbid . The dbid allows you to use multiple databases per application. router . get ( sql ) { req in return req . withPooledConnection ( to : . # dbid # ) { conn in return // use conn to perform a query } } Check out Database Kit Overview Connections for more information. The rest of this guide will assume you have access to a SQL database connection.","title":"Connection"},{"location":"sql/overview/#select","text":"Use the select() method on a connection to create a SQLSelectBuilder . This builder helps you create SELECT statements and supports: * , columns, and expressions like functions FROM JOIN GROUP BY ORDER BY The select builder conforms to SQLPredicateBuilder for building WHERE predicates. It also conforms to SQLQueryFetcher for decoding Codable models from the result set. Let's take a look at an example SELECT query. Replace the Xcode placeholder with the name of the database you are using, i.e., SQLite . struct User : SQLTable , Codable { static let sqlTableIdentifierString = users let id : Int ? let name : String } let users = conn . select () . all (). from ( User . self ) . where ( \\ User . name == Vapor ) . all ( decoding : User . self ) print ( users ) // Future [User] The resulting SQL will look something like this: SELECT * FROM users WHERE users . name = ? As you can see, the Swift code reads similarly to actual SQL. Be sure to visit the API docs for the various builder protocols to see all available methods.","title":"Select"},{"location":"sql/overview/#api-docs","text":"Check out the API docs for more in-depth information about SQL's APIs.","title":"API Docs"},{"location":"sqlite/getting-started/","text":"SQLite SQLite ( vapor/sqlite ) is a wrapper around the libsqlite C-library. The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the SQLite package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. SQLite core is built on top of DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent SQLite , all of the features of SQLite core will be available to you. Getting Started Let's take a look at how you can get started using SQLite core. Package The first step to using SQLite core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd35 SQLite 3 wrapper for Swift. . package ( url : https://github.com/vapor/sqlite.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ SQLite , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Config The next step is to configure the database in configure.swift . import SQLite /// Register providers first try services . register ( SQLiteProvider ()) Registering the provider will add all of the services required for SQLite to work properly. It also includes a default database config struct that uses an in-memory DB. Customizing Config You can of course override the default configuration provided by SQLiteProvider if you'd like. SQLite supports in-memory and file-based persistance. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a SQLite database let sqlite = try SQLiteDatabase ( storage : . file ( path : db.sqlite )) /// Register the configured SQLite database to the database config. var databases = DatabasesConfig () databases . add ( database : sqlite , as : . sqlite ) services . register ( databases ) See SQLiteDatabase and SQLiteStorage for more information. SQLite's default database identifier is .sqlite . You can create a custom identifier if you want by extending DatabaseIdentifier . Query Now that the database is configured, you can make your first query. struct SQLiteVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . sqlite ) { conn in return conn . select () . column ( function : sqlite_version , as : version ) . all ( decoding : SQLiteVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your SQLite version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Once we have a connection, we can use select() to create a SELECT query builder. Learn more about building queries in SQL Getting Started . Visit SQLite's API docs for detailed information about all available types and methods.","title":"Getting Started"},{"location":"sqlite/getting-started/#sqlite","text":"SQLite ( vapor/sqlite ) is a wrapper around the libsqlite C-library. The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the SQLite package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. SQLite core is built on top of DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent SQLite , all of the features of SQLite core will be available to you.","title":"SQLite"},{"location":"sqlite/getting-started/#getting-started","text":"Let's take a look at how you can get started using SQLite core.","title":"Getting Started"},{"location":"sqlite/getting-started/#package","text":"The first step to using SQLite core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd35 SQLite 3 wrapper for Swift. . package ( url : https://github.com/vapor/sqlite.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ SQLite , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"sqlite/getting-started/#config","text":"The next step is to configure the database in configure.swift . import SQLite /// Register providers first try services . register ( SQLiteProvider ()) Registering the provider will add all of the services required for SQLite to work properly. It also includes a default database config struct that uses an in-memory DB.","title":"Config"},{"location":"sqlite/getting-started/#customizing-config","text":"You can of course override the default configuration provided by SQLiteProvider if you'd like. SQLite supports in-memory and file-based persistance. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a SQLite database let sqlite = try SQLiteDatabase ( storage : . file ( path : db.sqlite )) /// Register the configured SQLite database to the database config. var databases = DatabasesConfig () databases . add ( database : sqlite , as : . sqlite ) services . register ( databases ) See SQLiteDatabase and SQLiteStorage for more information. SQLite's default database identifier is .sqlite . You can create a custom identifier if you want by extending DatabaseIdentifier .","title":"Customizing Config"},{"location":"sqlite/getting-started/#query","text":"Now that the database is configured, you can make your first query. struct SQLiteVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . sqlite ) { conn in return conn . select () . column ( function : sqlite_version , as : version ) . all ( decoding : SQLiteVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your SQLite version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Once we have a connection, we can use select() to create a SELECT query builder. Learn more about building queries in SQL Getting Started . Visit SQLite's API docs for detailed information about all available types and methods.","title":"Query"},{"location":"template-kit/getting-started/","text":"Getting Started with Template Kit Template Kit ( vapor/template-kit ) is a framework for implementing templating languages in Swift. It is currently used to power Leaf ( vapor/leaf ) and hopefully more languages in the future. Template Kit is designed to make implementing a templating language easy by defining a common template structure and handling the entire serialization step. Warning These docs are for developers interested in implementing a templating language using Template Kit. See Leaf Getting Started for information about using Leaf. Vapor This package is included with Vapor and exported by default. You will have access to all TemplateKit APIs when you import Vapor . import Vapor Standalone The Template Kit package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a templating framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/template-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ TemplateKit , ... ]) ] ) Use import TemplateKit to access the APIs. Overview Let's take a look at how Leaf uses Template Kit to render views. Assume we have a template greeting.leaf with the following contents: Hello, #capitalize ( name) ! This first step in rendering this view is to parse the syntax into an abstract syntax tree (AST). This is the part of view rendering that Leaf is responsible for, since Leaf has a unique syntax. Leaf does this by creating a LeafParser that conforms to TemplateParser . greeting.leaf - LeafParser - AST In code, this looks like: func parse ( scanner : TemplateByteScanner ) throws - [ TemplateSyntax ] The AST for our example greeting.leaf file would look something like this: [ . raw ( data : Hello. ), . tag ( name : capitalize , parameters : [. identifier ( name )] ), . raw ( data : ! ), ] Now that Leaf has created an AST, it's job is done! Template Kit will handle converting this AST into a rendered view. All it needs is a TemplateData to use for filling in any variables. let data = TemplateData . dictionary ([ name : vapor ]) The above data will be combined with the AST and used by the TemplateSerializer to create a rendered view. AST + Data - TemplateSerializer - View Our rendered view will look something like: Hello, Vapor! All of these steps are handled by LeafRenderer which conforms to TemplateRenderer . A template renderer is simply an object that contains both a parser and a serializer. When you implement one, you will get several helpful extensions from Template Kit for free that help load files and cache parsed ASTs. It's what the end user will use to render views. The entire pipeline looks like this: LeafRenderer | |----------------------------------------------------------------| greeting.leaf - LeafParser - AST - TemplateSerializer - View ^ / TemplateData In code, the method looks like this: public func render ( _ path : String , _ context : TemplateData ) - Future View Check out Template Kit's API docs for detailed information about all of the protocols, structs, and classes Template Kit offers.","title":"Getting Started"},{"location":"template-kit/getting-started/#getting-started-with-template-kit","text":"Template Kit ( vapor/template-kit ) is a framework for implementing templating languages in Swift. It is currently used to power Leaf ( vapor/leaf ) and hopefully more languages in the future. Template Kit is designed to make implementing a templating language easy by defining a common template structure and handling the entire serialization step. Warning These docs are for developers interested in implementing a templating language using Template Kit. See Leaf Getting Started for information about using Leaf.","title":"Getting Started with Template Kit"},{"location":"template-kit/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all TemplateKit APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"template-kit/getting-started/#standalone","text":"The Template Kit package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a templating framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/template-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ TemplateKit , ... ]) ] ) Use import TemplateKit to access the APIs.","title":"Standalone"},{"location":"template-kit/getting-started/#overview","text":"Let's take a look at how Leaf uses Template Kit to render views. Assume we have a template greeting.leaf with the following contents: Hello, #capitalize ( name) ! This first step in rendering this view is to parse the syntax into an abstract syntax tree (AST). This is the part of view rendering that Leaf is responsible for, since Leaf has a unique syntax. Leaf does this by creating a LeafParser that conforms to TemplateParser . greeting.leaf - LeafParser - AST In code, this looks like: func parse ( scanner : TemplateByteScanner ) throws - [ TemplateSyntax ] The AST for our example greeting.leaf file would look something like this: [ . raw ( data : Hello. ), . tag ( name : capitalize , parameters : [. identifier ( name )] ), . raw ( data : ! ), ] Now that Leaf has created an AST, it's job is done! Template Kit will handle converting this AST into a rendered view. All it needs is a TemplateData to use for filling in any variables. let data = TemplateData . dictionary ([ name : vapor ]) The above data will be combined with the AST and used by the TemplateSerializer to create a rendered view. AST + Data - TemplateSerializer - View Our rendered view will look something like: Hello, Vapor! All of these steps are handled by LeafRenderer which conforms to TemplateRenderer . A template renderer is simply an object that contains both a parser and a serializer. When you implement one, you will get several helpful extensions from Template Kit for free that help load files and cache parsed ASTs. It's what the end user will use to render views. The entire pipeline looks like this: LeafRenderer | |----------------------------------------------------------------| greeting.leaf - LeafParser - AST - TemplateSerializer - View ^ / TemplateData In code, the method looks like this: public func render ( _ path : String , _ context : TemplateData ) - Future View Check out Template Kit's API docs for detailed information about all of the protocols, structs, and classes Template Kit offers.","title":"Overview"},{"location":"testing/getting-started/","text":"Getting Started with Testing Coming soon.","title":"Getting Started"},{"location":"testing/getting-started/#getting-started-with-testing","text":"Coming soon.","title":"Getting Started with Testing"},{"location":"url-encoded-form/getting-started/","text":"Getting Started with URL-Encoded Form URL-Encoded Form ( vapor/url-encoded-form ) is a small package that helps you parse and serialize application/x-www-form-urlencoded data. URL-encoded forms are a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. The URL-Encoded Form package makes it easy to use this encoding by integrating directly with Codable . Vapor This package is included with Vapor and exported by default. You will have access to all URLEncodedForm APIs when you import Vapor . import Vapor Standalone The URL-Encoded Form package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with form-urlencoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/url-encoded-form.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ URLEncodedForm , ... ]) ] ) Use import URLEncodedForm to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the URL-Encoded Form package in general. Visit the API Docs for specific API info.","title":"Getting Started"},{"location":"url-encoded-form/getting-started/#getting-started-with-url-encoded-form","text":"URL-Encoded Form ( vapor/url-encoded-form ) is a small package that helps you parse and serialize application/x-www-form-urlencoded data. URL-encoded forms are a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. The URL-Encoded Form package makes it easy to use this encoding by integrating directly with Codable .","title":"Getting Started with URL-Encoded Form"},{"location":"url-encoded-form/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all URLEncodedForm APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"url-encoded-form/getting-started/#standalone","text":"The URL-Encoded Form package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with form-urlencoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/url-encoded-form.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ URLEncodedForm , ... ]) ] ) Use import URLEncodedForm to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the URL-Encoded Form package in general. Visit the API Docs for specific API info.","title":"Standalone"},{"location":"url-encoded-form/overview/","text":"Using URL-Encoded Form URL-Encoded Form is a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. This encoding is also used to send structured data in URL query strings. It is a relatively efficient encoding for sending small amounts of data. However, all data must be percent-encoded making this encoding suboptimal for large amounts of data. See the Multipart encoding if you need to upload things like files. Tip URL-Encoded Form integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a application/x-www-form-urlencoded request. Decode Body Most often, you will be decoding form-urlencoded -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like. Request Here is an example form-urlencoded -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : application/x-www-form-urlencoded name=Vapor age=3 luckyNumbers[]=5 luckyNumbers[]=7 You can see the [] notation is used to encode arrays. Your web form will need to use this notation as well. Form There are many ways to create a form-urlencoded -encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users input type = text name = name input type = text name = age input type = text name = luckyNumbers[] input type = text name = luckyNumbers[] / form Since we are not specifying a special enctype attribute on the form , the browser will URL-encode the form by default. We are also providing two fields with the same name, luckyNumbers[] . This will let us send an array of values. Content Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var luckyNumbers : [ Int ] } Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . luckyNumbers ) // [5, 7] return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work! Encode Body APIs encode form-urlencoded data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a form-urlencoded -encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , luckyNumbers : [ 5 , 7 ]) res . content . encode ( user , as : . urlEncodedForm ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure. URL Query URL-Encoded Forms are also useful for sending structured data in the URL query string. This is widely used for sending data via GET requests where HTTP bodies are not allowed. Let's take a look at how we can decode some search parameters from the query string. GET /users?name=Vapor age=3 HTTP / 1.1 The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct UsersFilters : Content { var name : String ? var age : Int ? } Here we are making both name and age optional since the route can be called without any flags to return all users. Now that we have a Codable struct, we can decode the URL query string. The process is almost identical to decoding content, expect we use req.query instead of req.content . router . get ( users ) { req - Future [ User ] in let filters = try req . query . decode ( UsersFilters . self ) print ( filters . name ) // Vapor print ( filters . age ) // 3 return // fetch users with filters } Tip Decoding the URL query string is not asynchronous because, unlike HTTP bodies, Vapor can be sure it is available when calling the route closure.","title":"Overview"},{"location":"url-encoded-form/overview/#using-url-encoded-form","text":"URL-Encoded Form is a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. This encoding is also used to send structured data in URL query strings. It is a relatively efficient encoding for sending small amounts of data. However, all data must be percent-encoded making this encoding suboptimal for large amounts of data. See the Multipart encoding if you need to upload things like files. Tip URL-Encoded Form integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a application/x-www-form-urlencoded request.","title":"Using URL-Encoded Form"},{"location":"url-encoded-form/overview/#decode-body","text":"Most often, you will be decoding form-urlencoded -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like.","title":"Decode Body"},{"location":"url-encoded-form/overview/#request","text":"Here is an example form-urlencoded -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : application/x-www-form-urlencoded name=Vapor age=3 luckyNumbers[]=5 luckyNumbers[]=7 You can see the [] notation is used to encode arrays. Your web form will need to use this notation as well.","title":"Request"},{"location":"url-encoded-form/overview/#form","text":"There are many ways to create a form-urlencoded -encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users input type = text name = name input type = text name = age input type = text name = luckyNumbers[] input type = text name = luckyNumbers[] / form Since we are not specifying a special enctype attribute on the form , the browser will URL-encode the form by default. We are also providing two fields with the same name, luckyNumbers[] . This will let us send an array of values.","title":"Form"},{"location":"url-encoded-form/overview/#content","text":"Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var luckyNumbers : [ Int ] } Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . luckyNumbers ) // [5, 7] return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work!","title":"Content"},{"location":"url-encoded-form/overview/#encode-body","text":"APIs encode form-urlencoded data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a form-urlencoded -encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , luckyNumbers : [ 5 , 7 ]) res . content . encode ( user , as : . urlEncodedForm ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure.","title":"Encode Body"},{"location":"url-encoded-form/overview/#url-query","text":"URL-Encoded Forms are also useful for sending structured data in the URL query string. This is widely used for sending data via GET requests where HTTP bodies are not allowed. Let's take a look at how we can decode some search parameters from the query string. GET /users?name=Vapor age=3 HTTP / 1.1 The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct UsersFilters : Content { var name : String ? var age : Int ? } Here we are making both name and age optional since the route can be called without any flags to return all users. Now that we have a Codable struct, we can decode the URL query string. The process is almost identical to decoding content, expect we use req.query instead of req.content . router . get ( users ) { req - Future [ User ] in let filters = try req . query . decode ( UsersFilters . self ) print ( filters . name ) // Vapor print ( filters . age ) // 3 return // fetch users with filters } Tip Decoding the URL query string is not asynchronous because, unlike HTTP bodies, Vapor can be sure it is available when calling the route closure.","title":"URL Query"},{"location":"validation/getting-started/","text":"Getting Started with Validation Validation ( vapor/validation ) is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators. The rest of this guide will show you how to add and import the Validation module. For more information on using this package, check out Validation Overview . Vapor This package is included with Vapor and exported by default. You will have access to all Validation APIs when you import Vapor . import Vapor Standalone The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a validation framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/validation.git , from : 2.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Validation , ... ]) ] ) Use import Validation to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Validation package in general. Visit the API Docs for Validation-specific API info.","title":"Getting Started"},{"location":"validation/getting-started/#getting-started-with-validation","text":"Validation ( vapor/validation ) is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators. The rest of this guide will show you how to add and import the Validation module. For more information on using this package, check out Validation Overview .","title":"Getting Started with Validation"},{"location":"validation/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Validation APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"validation/getting-started/#standalone","text":"The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a validation framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/validation.git , from : 2.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Validation , ... ]) ] ) Use import Validation to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Validation package in general. Visit the API Docs for Validation-specific API info.","title":"Standalone"},{"location":"validation/overview/","text":"Validation Overview Validation is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators. Swift Codable Swift's strong type system and Codable take care of most of the basic validation that web apps need to do. struct User : Codable { var id : UUID ? var name : String var age : Int var email : String ? var profilePictureURL : String ? } For example, when you decode the above User model, Swift will automatically ensure the following: id is a valid UUID or is nil . name is a valid String and is not nil . age is a valid Int and is not nil . email is a valid String or is nil . profilePictureURL is a valid String or is nil . This is a great first step, but there is still room for improvement here. Here are some examples of things Swift and Codable would not mind, but are not ideal: name is empty string \"\" name contains non-alphanumeric characters age is a negative number -42 email is not correctly formatted test@@vapor.codes profilePictureURL is not a URL without a scheme Luckily the Validation package can help. Validatable Let's take a look at how the Validation package can help you validate incoming data. We'll start by conforming our User model from the previous section to the Validatable protocol. Note This assumes User already conforms to Reflectable (added by default when using one of Fluent's Model protocols). If not, you will need to add conformance to Reflectable manually. extension User : Validatable { /// See `Validatable`. static func validations () - Validations User { // define validations } } let user = User (...) // since User conforms to Validatable, we get a new method validate() // that throws an error if any validations fail try user . validate () This is the basic structure of Validatable conformance. Let's take a look at how we can implement the static validations() method. Validations First let's start by verifying that the name is at least 3 characters long. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . count ( 3. ..)) return validations } } The count(...) validation accepts Swift Range notation and will validate that a collection's count is within that range. By only placing a value on the left side of ... , we only set a minimum range. Take a look at all of the available validators here . Operators Validating that the name is three or more characters is great, but we also want to make sure that the name is alphanumeric characters only. We can do this by combining multiple validators using . try validations . add ( \\ . name , . count ( 3. ..) . alphanumeric ) Now our name will only be considered valid if it is three or more characters and alphanumeric. Take a look at all of the available operators here . Nil You may want to run validations on optionals only if a value is present. The and || operators have special overloads that help you do this. try validations . add ( \\ . email , . email || . nil ) The nil validator checks if a T? optional value is nil . The email validator checks if a String is a valid email address. However, the property on our User is a String? . This means the email validator cannot be used directly with the property. We can combine these two operators using || to express the validation we want: validate the email is correctly formatted if it is not nil. Validate Let's finish up the rest of our validations using our new knowledge. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . alphanumeric . count ( 3. ..)) try validations . add ( \\ . age , . range ( 18. ..)) try validations . add ( \\ . email , . email || . nil ) try validations . add ( \\ . profilePictureURL , . url || . nil ) return validations } } Now let's try out validating our model. router . post ( User . self , at : users ) { req , user - User in try user . validate () return user } When you query that route, you should see that errors are thrown if the data does not meet your validations. If the data is correct, your user model is returned successfully. Congratulations on setting up your first Validatable model! Check out the API docs for more information and code samples.","title":"Overview"},{"location":"validation/overview/#validation-overview","text":"Validation is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators.","title":"Validation Overview"},{"location":"validation/overview/#swift-codable","text":"Swift's strong type system and Codable take care of most of the basic validation that web apps need to do. struct User : Codable { var id : UUID ? var name : String var age : Int var email : String ? var profilePictureURL : String ? } For example, when you decode the above User model, Swift will automatically ensure the following: id is a valid UUID or is nil . name is a valid String and is not nil . age is a valid Int and is not nil . email is a valid String or is nil . profilePictureURL is a valid String or is nil . This is a great first step, but there is still room for improvement here. Here are some examples of things Swift and Codable would not mind, but are not ideal: name is empty string \"\" name contains non-alphanumeric characters age is a negative number -42 email is not correctly formatted test@@vapor.codes profilePictureURL is not a URL without a scheme Luckily the Validation package can help.","title":"Swift & Codable"},{"location":"validation/overview/#validatable","text":"Let's take a look at how the Validation package can help you validate incoming data. We'll start by conforming our User model from the previous section to the Validatable protocol. Note This assumes User already conforms to Reflectable (added by default when using one of Fluent's Model protocols). If not, you will need to add conformance to Reflectable manually. extension User : Validatable { /// See `Validatable`. static func validations () - Validations User { // define validations } } let user = User (...) // since User conforms to Validatable, we get a new method validate() // that throws an error if any validations fail try user . validate () This is the basic structure of Validatable conformance. Let's take a look at how we can implement the static validations() method.","title":"Validatable"},{"location":"validation/overview/#validations","text":"First let's start by verifying that the name is at least 3 characters long. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . count ( 3. ..)) return validations } } The count(...) validation accepts Swift Range notation and will validate that a collection's count is within that range. By only placing a value on the left side of ... , we only set a minimum range. Take a look at all of the available validators here .","title":"Validations"},{"location":"validation/overview/#operators","text":"Validating that the name is three or more characters is great, but we also want to make sure that the name is alphanumeric characters only. We can do this by combining multiple validators using . try validations . add ( \\ . name , . count ( 3. ..) . alphanumeric ) Now our name will only be considered valid if it is three or more characters and alphanumeric. Take a look at all of the available operators here .","title":"Operators"},{"location":"validation/overview/#nil","text":"You may want to run validations on optionals only if a value is present. The and || operators have special overloads that help you do this. try validations . add ( \\ . email , . email || . nil ) The nil validator checks if a T? optional value is nil . The email validator checks if a String is a valid email address. However, the property on our User is a String? . This means the email validator cannot be used directly with the property. We can combine these two operators using || to express the validation we want: validate the email is correctly formatted if it is not nil.","title":"Nil"},{"location":"validation/overview/#validate","text":"Let's finish up the rest of our validations using our new knowledge. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . alphanumeric . count ( 3. ..)) try validations . add ( \\ . age , . range ( 18. ..)) try validations . add ( \\ . email , . email || . nil ) try validations . add ( \\ . profilePictureURL , . url || . nil ) return validations } } Now let's try out validating our model. router . post ( User . self , at : users ) { req , user - User in try user . validate () return user } When you query that route, you should see that errors are thrown if the data does not meet your validations. If the data is correct, your user model is returned successfully. Congratulations on setting up your first Validatable model! Check out the API docs for more information and code samples.","title":"Validate"},{"location":"vapor/client/","text":"Using Client Client is a convenience wrapper around the lower level HTTP Client . It automatically parses things like hostname and port from URIs and helps you encode and decode Content . let res = try req . client (). get ( http://vapor.codes ) print ( res ) // Future Response Container The first thing you will need is a service Container to create your client. If you are making this external API request as the result of an incoming request to your server, you should use the Request container to create a client. This is most often the case. If you need a client during boot, use the Application or if you are in a Command use the command context's container. Once you have a Container , use the client() method to create a Client . // Creates a generic Client let client = try container . client () Send Once you have a Client , you can use the send(...) method to send a Request . Note that the request URI must include a scheme and hostname. let req : Request ... let res = try client . send ( req ) print ( res ) // Future Response You can also use the convenience methods like get(...) , post(...) , etc. let user : User ... let res = try client . post ( http://api.vapor.codes/users ) { post in try post . content . encode ( user ) } print ( res ) // Future Response See Content for more information on encoding and decoding content to messages.","title":"Client"},{"location":"vapor/client/#using-client","text":"Client is a convenience wrapper around the lower level HTTP Client . It automatically parses things like hostname and port from URIs and helps you encode and decode Content . let res = try req . client (). get ( http://vapor.codes ) print ( res ) // Future Response","title":"Using Client"},{"location":"vapor/client/#container","text":"The first thing you will need is a service Container to create your client. If you are making this external API request as the result of an incoming request to your server, you should use the Request container to create a client. This is most often the case. If you need a client during boot, use the Application or if you are in a Command use the command context's container. Once you have a Container , use the client() method to create a Client . // Creates a generic Client let client = try container . client ()","title":"Container"},{"location":"vapor/client/#send","text":"Once you have a Client , you can use the send(...) method to send a Request . Note that the request URI must include a scheme and hostname. let req : Request ... let res = try client . send ( req ) print ( res ) // Future Response You can also use the convenience methods like get(...) , post(...) , etc. let user : User ... let res = try client . post ( http://api.vapor.codes/users ) { post in try post . content . encode ( user ) } print ( res ) // Future Response See Content for more information on encoding and decoding content to messages.","title":"Send"},{"location":"vapor/content/","text":"Using Content In Vapor 3, all content types (JSON, protobuf, URLEncodedForm , Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use mostly JSON as an example. But keep in mind the API is the same for any supported content type. Server This first section will go over decoding and encoding messages sent between your server and connected clients. See the client section for encoding and decoding content in messages sent to external APIs. Request Let's take a look at how you would parse the following HTTP request sent to your server. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Notice the key names exactly match the keys in the request data. The expected data types also match. Next conform this struct or class to Content . Decode Now we are ready to decode that HTTP request. Every Request has a ContentContainer that we can use to decode content from the message's body. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok } } We use .map(to:) here since decode(...) returns a future . Note Decoding content from requests is asynchronous because HTTP allows bodies to be split into multiple parts using chunked transfer encoding. Router To help make decoding content from incoming requests easier, Vapor offers a few extensions on Router to do this automatically. router . post ( LoginRequest . self , at : login ) { req , loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok } Detect Type Since the HTTP request in this example declared JSON as its content type, Vapor knows to use a JSON decoder automatically. This same method would work just as well for the following request. POST /login HTTP / 1.1 Content-Type : application/x-www-form-urlencoded email=user@vapor.codes don t+look! All HTTP requests must include a content type to be valid. Because of this, Vapor will automatically choose an appropriate decoder or error if it encounters an unknown media type. Tip You can configure the default encoders and decoders Vapor uses. Custom You can always override Vapor's default decoder and pass in a custom one if you want. let user = try req . content . decode ( User . self , using : JSONDecoder ()) print ( user ) // Future User Response Let's take a look at how you would create the following HTTP response from your server. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content . Encode Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } This will create a default Response with 200 OK status code and minimal headers. You can customize the response using a convenience encode(...) method. router . get ( user ) { req - Future Response in return User ( name : Vapor User , email : user@vapor.codes ) . encode ( status : . created ) } Override Type Content will automatically encode as JSON by default. You can always override which content type is used using the as: parameter. try res . content . encode ( user , as : . urlEncodedForm ) You can also change the default media type for any class or struct. struct User : Content { /// See `Content`. static let defaultContentType : MediaType = . urlEncodedForm ... } Client Encoding content to HTTP requests sent by Client s is similar to encoding HTTP responses returned by your server. Request Let's take a look at how we can encode the following request. POST /login HTTP / 1.1 Host : api.vapor.codes Content-Type : application/json { email : user@vapor.codes , password : don t look! } Encode First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Now we are ready to make our request. Let's assume we are making this request inside of a route closure, so we will use the incoming request as our container. let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) let res = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // encode the loginRequest before sending try loginReq . content . encode ( loginRequest ) } print ( res ) // Future Response Response Continuing from our example in the encode section, let's see how we would decode content from the client's response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } First of course we must create a struct or class to represent the data. import Vapor struct User : Content { var name : String var email : String } Decode Now we are ready to decode the client response. let res : Future Response // from the Client let user = res . flatMap { try $0 . content . decode ( User . self ) } print ( user ) // Future User Example Let's now take a look at our complete Client request that both encodes and decodes content. // Create the LoginRequest data let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) // POST /login let user = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // Encode Content before Request is sent return try loginReq . content . encode ( loginRequest ) }. flatMap { loginRes in // Decode Content after Response is received return try loginRes . content . decode ( User . self ) } print ( user ) // Future User Query String URL-Encoded Form data can be encoded and decoded from an HTTP request's URI query string just like content. All you need is a class or struct that conforms to Content . In these examples, we will be using the following struct. struct Flags : Content { var search : String ? var isAdmin : Bool ? } Decode All Request s have a QueryContainer that you can use to decode the query string. let flags = try req . query . decode ( Flags . self ) print ( flags ) // Flags Encode You can also encode content. This is useful for encoding query strings when using Client . let flags : Flags ... try req . query . encode ( flags ) Dynamic Properties One of the most frequently asked questions regarding Content is: How do I add a property to just this response? The way Vapor 3 handles Content is based entirely on Codable . At no point (that is publically accessible) is your data in an arbitrary data structure like [String: Any] that you can mutate at will. Because of this, all data structures that your app accepts and returns must be statically defined. Let's take a look at a common scenario to better understand this. Very often when you are creating a user, there are a couple different data formats required: create: password should be supplied twice to check values match internal: you should store a hash not the plaintext password public: when listing users, the password hash should not be included To do this, you should create three types. // Data required to create a user struct UserCreate : Content { var email : String var password : String var passwordCheck : String } // Our internal User representation struct User : Model { var id : Int ? var email : String var passwordHash : Data } // Public user representation struct PublicUser : Content { var id : Int var email : String } // Create a router for POST /users router . post ( UserCreate . self , at : users ) { req , userCreate - PublicUser in guard userCreate . password == passwordCheck else { /* some error */ } let hasher = try req . make ( /* some hasher */ ) let user = try User ( email : userCreate . email , passwordHash : hasher . hash ( userCreate . password ) ) // save user return try PublicUser ( id : user . requireID (), email : user . email ) } For other methods such as PATCH and PUT , you may want to create additional types to supports the unique semantics. Benefits This method may seem a bit verbose at first when compared to dynamic solutions, but it has a number of key advantages: Statically Typed : Very little validation is needed on top of what Swift and Codable do automatically. Readability : No need for Strings and optional chaining when working with Swift types. Maintainable : Large projects will appreciate having this information separated and clearly stated. Shareable : Types defining what content your routes accept and return can be used to conform to specifications like OpenAPI or even be shared directly with clients written in Swift. Performance : Working with native Swift types is much more performant than mutating [String: Any] dictionaries. JSON JSON is a very popular encoding format for APIs and the way in which dates, data, floats, etc are encoded is non-standard. Because of this, Vapor makes it easy to use custom JSONDecoder s when you interact with other APIs. // Conforms to Encodable let user : User ... // Encode JSON using custom date encoding strategy try req . content . encode ( json : user , using : . custom ( dates : . millisecondsSince1970 )) You can also use this method for decoding. // Decode JSON using custom date encoding strategy let user = try req . content . decode ( json : User . self , using : . custom ( dates : . millisecondsSince1970 )) If you would like to set a custom JSON encoder or decoder globally, you can do so using configuration . Configure Use ContentConfig to register custom encoder/decoders for your application. These custom coders will be used anywhere you do content.encode / content.decode . /// Create default content config var contentConfig = ContentConfig . default () /// Create custom JSON encoder var jsonEncoder = JSONEncoder () jsonEncoder . dateEncodingStrategy = . millisecondsSince1970 /// Register JSON encoder and content config contentConfig . use ( encoder : jsonEncoder , for : . json ) services . register ( contentConfig )","title":"Content"},{"location":"vapor/content/#using-content","text":"In Vapor 3, all content types (JSON, protobuf, URLEncodedForm , Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use mostly JSON as an example. But keep in mind the API is the same for any supported content type.","title":"Using Content"},{"location":"vapor/content/#server","text":"This first section will go over decoding and encoding messages sent between your server and connected clients. See the client section for encoding and decoding content in messages sent to external APIs.","title":"Server"},{"location":"vapor/content/#request","text":"Let's take a look at how you would parse the following HTTP request sent to your server. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Notice the key names exactly match the keys in the request data. The expected data types also match. Next conform this struct or class to Content .","title":"Request"},{"location":"vapor/content/#decode","text":"Now we are ready to decode that HTTP request. Every Request has a ContentContainer that we can use to decode content from the message's body. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok } } We use .map(to:) here since decode(...) returns a future . Note Decoding content from requests is asynchronous because HTTP allows bodies to be split into multiple parts using chunked transfer encoding.","title":"Decode"},{"location":"vapor/content/#router","text":"To help make decoding content from incoming requests easier, Vapor offers a few extensions on Router to do this automatically. router . post ( LoginRequest . self , at : login ) { req , loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok }","title":"Router"},{"location":"vapor/content/#detect-type","text":"Since the HTTP request in this example declared JSON as its content type, Vapor knows to use a JSON decoder automatically. This same method would work just as well for the following request. POST /login HTTP / 1.1 Content-Type : application/x-www-form-urlencoded email=user@vapor.codes don t+look! All HTTP requests must include a content type to be valid. Because of this, Vapor will automatically choose an appropriate decoder or error if it encounters an unknown media type. Tip You can configure the default encoders and decoders Vapor uses.","title":"Detect Type"},{"location":"vapor/content/#custom","text":"You can always override Vapor's default decoder and pass in a custom one if you want. let user = try req . content . decode ( User . self , using : JSONDecoder ()) print ( user ) // Future User","title":"Custom"},{"location":"vapor/content/#response","text":"Let's take a look at how you would create the following HTTP response from your server. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content .","title":"Response"},{"location":"vapor/content/#encode","text":"Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } This will create a default Response with 200 OK status code and minimal headers. You can customize the response using a convenience encode(...) method. router . get ( user ) { req - Future Response in return User ( name : Vapor User , email : user@vapor.codes ) . encode ( status : . created ) }","title":"Encode"},{"location":"vapor/content/#override-type","text":"Content will automatically encode as JSON by default. You can always override which content type is used using the as: parameter. try res . content . encode ( user , as : . urlEncodedForm ) You can also change the default media type for any class or struct. struct User : Content { /// See `Content`. static let defaultContentType : MediaType = . urlEncodedForm ... }","title":"Override Type"},{"location":"vapor/content/#client","text":"Encoding content to HTTP requests sent by Client s is similar to encoding HTTP responses returned by your server.","title":"Client"},{"location":"vapor/content/#request_1","text":"Let's take a look at how we can encode the following request. POST /login HTTP / 1.1 Host : api.vapor.codes Content-Type : application/json { email : user@vapor.codes , password : don t look! }","title":"Request"},{"location":"vapor/content/#encode_1","text":"First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Now we are ready to make our request. Let's assume we are making this request inside of a route closure, so we will use the incoming request as our container. let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) let res = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // encode the loginRequest before sending try loginReq . content . encode ( loginRequest ) } print ( res ) // Future Response","title":"Encode"},{"location":"vapor/content/#response_1","text":"Continuing from our example in the encode section, let's see how we would decode content from the client's response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } First of course we must create a struct or class to represent the data. import Vapor struct User : Content { var name : String var email : String }","title":"Response"},{"location":"vapor/content/#decode_1","text":"Now we are ready to decode the client response. let res : Future Response // from the Client let user = res . flatMap { try $0 . content . decode ( User . self ) } print ( user ) // Future User","title":"Decode"},{"location":"vapor/content/#example","text":"Let's now take a look at our complete Client request that both encodes and decodes content. // Create the LoginRequest data let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) // POST /login let user = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // Encode Content before Request is sent return try loginReq . content . encode ( loginRequest ) }. flatMap { loginRes in // Decode Content after Response is received return try loginRes . content . decode ( User . self ) } print ( user ) // Future User","title":"Example"},{"location":"vapor/content/#query-string","text":"URL-Encoded Form data can be encoded and decoded from an HTTP request's URI query string just like content. All you need is a class or struct that conforms to Content . In these examples, we will be using the following struct. struct Flags : Content { var search : String ? var isAdmin : Bool ? }","title":"Query String"},{"location":"vapor/content/#decode_2","text":"All Request s have a QueryContainer that you can use to decode the query string. let flags = try req . query . decode ( Flags . self ) print ( flags ) // Flags","title":"Decode"},{"location":"vapor/content/#encode_2","text":"You can also encode content. This is useful for encoding query strings when using Client . let flags : Flags ... try req . query . encode ( flags )","title":"Encode"},{"location":"vapor/content/#dynamic-properties","text":"One of the most frequently asked questions regarding Content is: How do I add a property to just this response? The way Vapor 3 handles Content is based entirely on Codable . At no point (that is publically accessible) is your data in an arbitrary data structure like [String: Any] that you can mutate at will. Because of this, all data structures that your app accepts and returns must be statically defined. Let's take a look at a common scenario to better understand this. Very often when you are creating a user, there are a couple different data formats required: create: password should be supplied twice to check values match internal: you should store a hash not the plaintext password public: when listing users, the password hash should not be included To do this, you should create three types. // Data required to create a user struct UserCreate : Content { var email : String var password : String var passwordCheck : String } // Our internal User representation struct User : Model { var id : Int ? var email : String var passwordHash : Data } // Public user representation struct PublicUser : Content { var id : Int var email : String } // Create a router for POST /users router . post ( UserCreate . self , at : users ) { req , userCreate - PublicUser in guard userCreate . password == passwordCheck else { /* some error */ } let hasher = try req . make ( /* some hasher */ ) let user = try User ( email : userCreate . email , passwordHash : hasher . hash ( userCreate . password ) ) // save user return try PublicUser ( id : user . requireID (), email : user . email ) } For other methods such as PATCH and PUT , you may want to create additional types to supports the unique semantics.","title":"Dynamic Properties"},{"location":"vapor/content/#benefits","text":"This method may seem a bit verbose at first when compared to dynamic solutions, but it has a number of key advantages: Statically Typed : Very little validation is needed on top of what Swift and Codable do automatically. Readability : No need for Strings and optional chaining when working with Swift types. Maintainable : Large projects will appreciate having this information separated and clearly stated. Shareable : Types defining what content your routes accept and return can be used to conform to specifications like OpenAPI or even be shared directly with clients written in Swift. Performance : Working with native Swift types is much more performant than mutating [String: Any] dictionaries.","title":"Benefits"},{"location":"vapor/content/#json","text":"JSON is a very popular encoding format for APIs and the way in which dates, data, floats, etc are encoded is non-standard. Because of this, Vapor makes it easy to use custom JSONDecoder s when you interact with other APIs. // Conforms to Encodable let user : User ... // Encode JSON using custom date encoding strategy try req . content . encode ( json : user , using : . custom ( dates : . millisecondsSince1970 )) You can also use this method for decoding. // Decode JSON using custom date encoding strategy let user = try req . content . decode ( json : User . self , using : . custom ( dates : . millisecondsSince1970 )) If you would like to set a custom JSON encoder or decoder globally, you can do so using configuration .","title":"JSON"},{"location":"vapor/content/#configure","text":"Use ContentConfig to register custom encoder/decoders for your application. These custom coders will be used anywhere you do content.encode / content.decode . /// Create default content config var contentConfig = ContentConfig . default () /// Create custom JSON encoder var jsonEncoder = JSONEncoder () jsonEncoder . dateEncodingStrategy = . millisecondsSince1970 /// Register JSON encoder and content config contentConfig . use ( encoder : jsonEncoder , for : . json ) services . register ( contentConfig )","title":"Configure"},{"location":"vapor/getting-started/","text":"Getting Started with Vapor Check out the main Getting Started guide which covers Vapor specifically. This page is here mostly for consistency with the rest of the packages. More in-depth information on the APIs included in Vapor, see the sub-sections to the left. Package If you don't want to use one of Vapor's templates to get started, you can always include the framework manually. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Vapor , ... ]) ] ) Use import Vapor to access the APIs. API Docs The rest of this guide will give you an overview of what is available in the Vapor package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"vapor/getting-started/#getting-started-with-vapor","text":"Check out the main Getting Started guide which covers Vapor specifically. This page is here mostly for consistency with the rest of the packages. More in-depth information on the APIs included in Vapor, see the sub-sections to the left.","title":"Getting Started with Vapor"},{"location":"vapor/getting-started/#package","text":"If you don't want to use one of Vapor's templates to get started, you can always include the framework manually. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Vapor , ... ]) ] ) Use import Vapor to access the APIs.","title":"Package"},{"location":"vapor/getting-started/#api-docs","text":"The rest of this guide will give you an overview of what is available in the Vapor package. As always, feel free to visit the API docs for more in-depth information.","title":"API Docs"},{"location":"vapor/middleware/","text":"Middleware Coming soon.","title":"Middleware"},{"location":"vapor/middleware/#middleware","text":"Coming soon.","title":"Middleware"},{"location":"vapor/sessions/","text":"Using Sessions This guide will show you how to use sessions in Vapor to maintain state for a connected client. Sessions work by creating unique identifiers for each new client and asking the client to supply this identifier with each request. When the next request is received, Vapor uses this unique identifier to restore the session data. This identifier could be transmitted in any format, but it is almost always done with cookies and that is how Vapor's sessions work. When a new client connects and session data is set, Vapor will return a Set-Cookie header. The client is then expected to re-supply the value with each request in a Cookie header. All browsers do this automatically. If your ever decide to invalidate the session, Vapor will delete any related data and notify the client that their cookie is no longer valid. Middleware The first step to using sessions is enabling SessionsMiddleware . This can be done globally for the entire application or on a per-route basis. Globally To globally enable sessions, add the middleware to your MiddlewareConfig . var middlewares = MiddlewareConfig . default () middlewares . use ( SessionsMiddleware . self ) services . register ( middlewares ) This is usually done in configure.swift . Per Route To enable sessions for a group of routes, use the grouped(...) methods on Router . // create a grouped router at /sessions w/ sessions enabled let sessions = router . grouped ( sessions ). grouped ( SessionsMiddleware . self ) // create a route at GET /sessions/foo sessions . get ( foo ) { req in // use sessions } Sessions When SessionsMiddleware boots it will attempt to make a Sessions and a SessionsConfig . Vapor will use an in-memory session by default. You can override both of these services by registering them in configure.swift . You can use Fluent databases (like MySQL, PostgreSQL, etc) or caches like Redis to store your sessions. See the respective guides for more information. Session Once you have SessionsMiddleware enabled, you can use req.session() to access the session. Here is a simple example that does simple CRUD operations on a \"name\" value in the session. // create a route at GET /sessions/get sessions . get ( get ) { req - String in // access name from session or return n/a return try req . session ()[ name ] ?? n/a } // create a route at GET /sessions/set/:name sessions . get ( set , String . parameter ) { req - String in // get router param let name = try req . parameters . next ( String . self ) // set name to session at key name try req . session ()[ name ] = name // return the newly set name return name } // create a route at GET /sessions/del sessions . get ( del ) { req - String in // destroy the session try req . destroySession () // signal success return done } That's it, congratulations on getting sessions working!","title":"Sessions"},{"location":"vapor/sessions/#using-sessions","text":"This guide will show you how to use sessions in Vapor to maintain state for a connected client. Sessions work by creating unique identifiers for each new client and asking the client to supply this identifier with each request. When the next request is received, Vapor uses this unique identifier to restore the session data. This identifier could be transmitted in any format, but it is almost always done with cookies and that is how Vapor's sessions work. When a new client connects and session data is set, Vapor will return a Set-Cookie header. The client is then expected to re-supply the value with each request in a Cookie header. All browsers do this automatically. If your ever decide to invalidate the session, Vapor will delete any related data and notify the client that their cookie is no longer valid.","title":"Using Sessions"},{"location":"vapor/sessions/#middleware","text":"The first step to using sessions is enabling SessionsMiddleware . This can be done globally for the entire application or on a per-route basis.","title":"Middleware"},{"location":"vapor/sessions/#globally","text":"To globally enable sessions, add the middleware to your MiddlewareConfig . var middlewares = MiddlewareConfig . default () middlewares . use ( SessionsMiddleware . self ) services . register ( middlewares ) This is usually done in configure.swift .","title":"Globally"},{"location":"vapor/sessions/#per-route","text":"To enable sessions for a group of routes, use the grouped(...) methods on Router . // create a grouped router at /sessions w/ sessions enabled let sessions = router . grouped ( sessions ). grouped ( SessionsMiddleware . self ) // create a route at GET /sessions/foo sessions . get ( foo ) { req in // use sessions }","title":"Per Route"},{"location":"vapor/sessions/#sessions","text":"When SessionsMiddleware boots it will attempt to make a Sessions and a SessionsConfig . Vapor will use an in-memory session by default. You can override both of these services by registering them in configure.swift . You can use Fluent databases (like MySQL, PostgreSQL, etc) or caches like Redis to store your sessions. See the respective guides for more information.","title":"Sessions"},{"location":"vapor/sessions/#session","text":"Once you have SessionsMiddleware enabled, you can use req.session() to access the session. Here is a simple example that does simple CRUD operations on a \"name\" value in the session. // create a route at GET /sessions/get sessions . get ( get ) { req - String in // access name from session or return n/a return try req . session ()[ name ] ?? n/a } // create a route at GET /sessions/set/:name sessions . get ( set , String . parameter ) { req - String in // get router param let name = try req . parameters . next ( String . self ) // set name to session at key name try req . session ()[ name ] = name // return the newly set name return name } // create a route at GET /sessions/del sessions . get ( del ) { req - String in // destroy the session try req . destroySession () // signal success return done } That's it, congratulations on getting sessions working!","title":"Session"},{"location":"vapor/websocket/","text":"Using WebSockets Vapor includes convenience methods for working with the lower level WebSocket client and server . Server Vapor's WebSocket server includes the ability to route incoming requests just like its HTTP server. When Vapor's main HTTP Server boots it will attempt to create a WebSocketServer . If one is registered, it will be added as an HTTP upgrade handler to the server. So to create a WebSocket server, all you need to do is register one in configure.swift . // Create a new NIO websocket server let wss = NIOWebSocketServer . default () // Add WebSocket upgrade support to GET /echo wss . get ( echo ) { ws , req in // Add a new on text callback ws . onText { ws , text in // Simply echo any received text ws . send ( text ) } } // Register our server services . register ( wss , as : WebSocketServer . self ) That's it. Next time you boot your server, you will be able to perform a WebSocket upgrade at GET /echo . You can test this using a simple command line tool called wsta available for macOS and Linux. $ wsta ws://localhost:8080/echo Connected to ws://localhost:8080/echo hello, world! hello, world! Parameters Like Vapor's HTTP router, you can also use routing parameters with your WebSocket server. // Add WebSocket upgrade support to GET /chat/:name wss . get ( chat , String . parameter ) { ws , req in let name = try req . parameters . next ( String . self ) ws . send ( Welcome, \\( name ) ! ) // ... } Now let's test this new route: $ wsta ws://localhost:8080/chat/Vapor Connected to ws://localhost:8080/chat/Vapor Welcome, Vapor! Client Vapor also supports connecting to WebSocket servers as a client. The easiest way to connect to a WebSocket server is through the webSocket(...) method on Client . For this example, we will assume our application connects to a WebSocket server in boot.swift // connect to echo.websocket.org let done = try app . client (). webSocket ( ws://echo.websocket.org ). flatMap { ws - Future Void in // setup an on text callback that will print the echo ws . onText { ws , text in print ( rec: \\( text ) ) // close the websocket connection after we recv the echo ws . close () } // when the websocket first connects, send message ws . send ( hello, world! ) // return a future that will complete when the websocket closes return ws . onClose } print ( done ) // Future Void // wait for the websocket to close try done . wait ()","title":"WebSocket"},{"location":"vapor/websocket/#using-websockets","text":"Vapor includes convenience methods for working with the lower level WebSocket client and server .","title":"Using WebSockets"},{"location":"vapor/websocket/#server","text":"Vapor's WebSocket server includes the ability to route incoming requests just like its HTTP server. When Vapor's main HTTP Server boots it will attempt to create a WebSocketServer . If one is registered, it will be added as an HTTP upgrade handler to the server. So to create a WebSocket server, all you need to do is register one in configure.swift . // Create a new NIO websocket server let wss = NIOWebSocketServer . default () // Add WebSocket upgrade support to GET /echo wss . get ( echo ) { ws , req in // Add a new on text callback ws . onText { ws , text in // Simply echo any received text ws . send ( text ) } } // Register our server services . register ( wss , as : WebSocketServer . self ) That's it. Next time you boot your server, you will be able to perform a WebSocket upgrade at GET /echo . You can test this using a simple command line tool called wsta available for macOS and Linux. $ wsta ws://localhost:8080/echo Connected to ws://localhost:8080/echo hello, world! hello, world!","title":"Server"},{"location":"vapor/websocket/#parameters","text":"Like Vapor's HTTP router, you can also use routing parameters with your WebSocket server. // Add WebSocket upgrade support to GET /chat/:name wss . get ( chat , String . parameter ) { ws , req in let name = try req . parameters . next ( String . self ) ws . send ( Welcome, \\( name ) ! ) // ... } Now let's test this new route: $ wsta ws://localhost:8080/chat/Vapor Connected to ws://localhost:8080/chat/Vapor Welcome, Vapor!","title":"Parameters"},{"location":"vapor/websocket/#client","text":"Vapor also supports connecting to WebSocket servers as a client. The easiest way to connect to a WebSocket server is through the webSocket(...) method on Client . For this example, we will assume our application connects to a WebSocket server in boot.swift // connect to echo.websocket.org let done = try app . client (). webSocket ( ws://echo.websocket.org ). flatMap { ws - Future Void in // setup an on text callback that will print the echo ws . onText { ws , text in print ( rec: \\( text ) ) // close the websocket connection after we recv the echo ws . close () } // when the websocket first connects, send message ws . send ( hello, world! ) // return a future that will complete when the websocket closes return ws . onClose } print ( done ) // Future Void // wait for the websocket to close try done . wait ()","title":"Client"},{"location":"version/1_5/","text":"Redirecting...","title":"1.5"},{"location":"version/1_5/#redirecting","text":"","title":"Redirecting..."},{"location":"version/2_0/","text":"Redirecting...","title":"2.0"},{"location":"version/2_0/#redirecting","text":"","title":"Redirecting..."},{"location":"version/3_0/","text":"Redirecting...","title":"3.0"},{"location":"version/3_0/#redirecting","text":"","title":"Redirecting..."},{"location":"version/support/","text":"Version Support Vapor 3.0 is currently active. Vapor 2.4 is being maintained until November 2018. Vapor 1.5 is no longer maintained (ended November 2017). Core All packages in the Vapor GitHub are maintained according to the following rules. Active While a version is active, reported security issues and bugs are fixed. Additionally, new features and optimizations may be added. If new API is added, the minor version number will be incremented. At no point can existing API be removed or broken during an active version. Semver is strictly followed and tested. Maintenance When a new version of Vapor is released, the previous version will enter a maintenance phase which lasts for six months. During this phase, critical security issues and bugs will be fixed. No new features will be added. Note Only the latest minor version will be maintained. Unstable The master branch is the latest development version of Vapor and is constantly changing. Before a new version of Vapor is released, there may be unstable alpha and beta phases in which you are welcome to test and provide feedback on the changes. Community All packages in the Vapor Community GitHub are maintained in strict accordance of semver. Violations of semver should be reported as issues to the offending package's GitHub page.","title":"Support"},{"location":"version/support/#version-support","text":"Vapor 3.0 is currently active. Vapor 2.4 is being maintained until November 2018. Vapor 1.5 is no longer maintained (ended November 2017).","title":"Version Support"},{"location":"version/support/#core","text":"All packages in the Vapor GitHub are maintained according to the following rules.","title":"Core"},{"location":"version/support/#active","text":"While a version is active, reported security issues and bugs are fixed. Additionally, new features and optimizations may be added. If new API is added, the minor version number will be incremented. At no point can existing API be removed or broken during an active version. Semver is strictly followed and tested.","title":"Active"},{"location":"version/support/#maintenance","text":"When a new version of Vapor is released, the previous version will enter a maintenance phase which lasts for six months. During this phase, critical security issues and bugs will be fixed. No new features will be added. Note Only the latest minor version will be maintained.","title":"Maintenance"},{"location":"version/support/#unstable","text":"The master branch is the latest development version of Vapor and is constantly changing. Before a new version of Vapor is released, there may be unstable alpha and beta phases in which you are welcome to test and provide feedback on the changes.","title":"Unstable"},{"location":"version/support/#community","text":"All packages in the Vapor Community GitHub are maintained in strict accordance of semver. Violations of semver should be reported as issues to the offending package's GitHub page.","title":"Community"},{"location":"version/upgrading/","text":"Upgrading Versions This document provides information about changes between version and tips for migrating your projects. 2.4 to 3.0 Vapor 3 has been rewritten from the ground up to be async and event-driven. This release contains the most changes of any previous release (and most likely any future release). Because of this, it is recommended that to migrate your projects you start by creating a new, empty template and migrate by copy / pasting code over to the new project. We recommend reading the Getting Started Hello, world! section for Vapor 3 to familiarize yourself with the new APIs. Async The biggest change in Vapor 3 is that the framework is now completely asynchronous. When you call methods that need to perform slow work like network requests or disk access instead of blocking they will now return a Future T . Futures are values that may not exist yet, so you cannot interact with them directly. Instead, you must use map / flatMap to access the values. // vapor 2 let res = try drop . client . get ( http://vapor.codes ) print ( res . status ) // HTTPStatus return res . status // vapor 3 let f = try req . client (). get ( http://vapor.codes ). map { res in print ( res . http . status ) // HTTPStatus return res . http . status } print ( f ) // Future HTTPStatus See Async Getting Started to learn more. Application Services Droplet has been renamed to Application and is now a service-container. In Vapor 2, the Droplet had stored properties for things you would need during development (like views, hashers, etc). In Vapor 3, this is all done via services. While the Application is a service-container, you should not use it from your route closures. This is to prevent race conditions since Vapor runs on multiple threads (event loops). Instead, use the Request that is supplied to your route closure. This has a copy of all of the application's services for you to use. // vapor 2 return try drop . view . make ( myView ) // vapor 3 return try req . make ( ViewRenderer . self ). render ( myView ) // shorthand return try req . view (). render ( myView ) See Service Getting Started to learn more. Database Connections In Vapor 3, database connections are no longer statically accessible. This makes doing things like transactions and connection pooling much more predictable and performant. In order to create a QueryBuilder in Fluent 3, you will need access to something DatabaseConnectable . Most often you can just use the incoming Request , but you can also create connections manually if you need. // vapor 2 User . makeQuery (). all () // vapor 3 User . query ( on : req ). all () See DatabaseKit Getting Started to learn more. Migrating SQL Database When migrating from Fluent 2 to 3 you may need to update your fluent table to support the new format. In Fluent 3, the migration log table has the following changes: id is now a UUID . createdAt and updatedAt must now be camelCase . Depending on how your Fluent database was configured, your tables may already be in the correct format. If not, you can run the following queries to transfer the table data. Use this query if your column names were already set to camelCase . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , createdAt , updatedAt from fluent_old ); Use this query if your column names were snake_case . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , created_at as createdAt , updated_at as updatedAt from fluent_old ); After you have verified the table was transferred properly, you can drop the old fluent table. DROP TABLE fluent_old ; Work in progress This migration guide is a work in progress. Please feel free to add any migration tips here by submitting a PR. Join the #upgrading-to-3 in Vapor's team chat to ask questions and get help in real time. Also check out Getting started with Vapor 3 , an in-depth article about the differences between Vapor 2 and 3. This article was written by two developers from an app development company using Vapor.","title":"Upgrading"},{"location":"version/upgrading/#upgrading-versions","text":"This document provides information about changes between version and tips for migrating your projects.","title":"Upgrading Versions"},{"location":"version/upgrading/#24-to-30","text":"Vapor 3 has been rewritten from the ground up to be async and event-driven. This release contains the most changes of any previous release (and most likely any future release). Because of this, it is recommended that to migrate your projects you start by creating a new, empty template and migrate by copy / pasting code over to the new project. We recommend reading the Getting Started Hello, world! section for Vapor 3 to familiarize yourself with the new APIs.","title":"2.4 to 3.0"},{"location":"version/upgrading/#async","text":"The biggest change in Vapor 3 is that the framework is now completely asynchronous. When you call methods that need to perform slow work like network requests or disk access instead of blocking they will now return a Future T . Futures are values that may not exist yet, so you cannot interact with them directly. Instead, you must use map / flatMap to access the values. // vapor 2 let res = try drop . client . get ( http://vapor.codes ) print ( res . status ) // HTTPStatus return res . status // vapor 3 let f = try req . client (). get ( http://vapor.codes ). map { res in print ( res . http . status ) // HTTPStatus return res . http . status } print ( f ) // Future HTTPStatus See Async Getting Started to learn more.","title":"Async"},{"location":"version/upgrading/#application-services","text":"Droplet has been renamed to Application and is now a service-container. In Vapor 2, the Droplet had stored properties for things you would need during development (like views, hashers, etc). In Vapor 3, this is all done via services. While the Application is a service-container, you should not use it from your route closures. This is to prevent race conditions since Vapor runs on multiple threads (event loops). Instead, use the Request that is supplied to your route closure. This has a copy of all of the application's services for you to use. // vapor 2 return try drop . view . make ( myView ) // vapor 3 return try req . make ( ViewRenderer . self ). render ( myView ) // shorthand return try req . view (). render ( myView ) See Service Getting Started to learn more.","title":"Application & Services"},{"location":"version/upgrading/#database-connections","text":"In Vapor 3, database connections are no longer statically accessible. This makes doing things like transactions and connection pooling much more predictable and performant. In order to create a QueryBuilder in Fluent 3, you will need access to something DatabaseConnectable . Most often you can just use the incoming Request , but you can also create connections manually if you need. // vapor 2 User . makeQuery (). all () // vapor 3 User . query ( on : req ). all () See DatabaseKit Getting Started to learn more.","title":"Database Connections"},{"location":"version/upgrading/#migrating-sql-database","text":"When migrating from Fluent 2 to 3 you may need to update your fluent table to support the new format. In Fluent 3, the migration log table has the following changes: id is now a UUID . createdAt and updatedAt must now be camelCase . Depending on how your Fluent database was configured, your tables may already be in the correct format. If not, you can run the following queries to transfer the table data. Use this query if your column names were already set to camelCase . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , createdAt , updatedAt from fluent_old ); Use this query if your column names were snake_case . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , created_at as createdAt , updated_at as updatedAt from fluent_old ); After you have verified the table was transferred properly, you can drop the old fluent table. DROP TABLE fluent_old ;","title":"Migrating SQL Database"},{"location":"version/upgrading/#work-in-progress","text":"This migration guide is a work in progress. Please feel free to add any migration tips here by submitting a PR. Join the #upgrading-to-3 in Vapor's team chat to ask questions and get help in real time. Also check out Getting started with Vapor 3 , an in-depth article about the differences between Vapor 2 and 3. This article was written by two developers from an app development company using Vapor.","title":"Work in progress"},{"location":"websocket/getting-started/","text":"Getting Started with WebSocket WebSocket ( vapor/websocket ) is a non-blocking, event-driven WebSocket library built on SwiftNIO. It makes working with SwiftNIO's WebSocket handlers easy and provides integration with HTTP clients and servers. Creating a WebSocket echo server takes just a few lines of code. Tip If you use Vapor, most of WebSocket's APIs will be wrapped by more convenient methods. Vapor This package is included with Vapor and exported by default. You will have access to all WebSocket APIs when you import Vapor . import Vapor Standalone The WebSocket package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as a WebSocket framework any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/websocket.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ WebSocket , ... ]) ] ) Use import WebSocket to access the APIs. The rest of this guide will give you an overview of what is available in the WebSocket package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"websocket/getting-started/#getting-started-with-websocket","text":"WebSocket ( vapor/websocket ) is a non-blocking, event-driven WebSocket library built on SwiftNIO. It makes working with SwiftNIO's WebSocket handlers easy and provides integration with HTTP clients and servers. Creating a WebSocket echo server takes just a few lines of code. Tip If you use Vapor, most of WebSocket's APIs will be wrapped by more convenient methods.","title":"Getting Started with WebSocket"},{"location":"websocket/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all WebSocket APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"websocket/getting-started/#standalone","text":"The WebSocket package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as a WebSocket framework any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/websocket.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ WebSocket , ... ]) ] ) Use import WebSocket to access the APIs. The rest of this guide will give you an overview of what is available in the WebSocket package. As always, feel free to visit the API docs for more in-depth information.","title":"Standalone"},{"location":"websocket/overview/","text":"Using WebSockets Unlike HTTP, WebSockets allow you to communicate between client and server in an open, interactive way. You can send messages (called frames) in either text or binary format. Both the client and the server can send as many messages as they want at a time, without having to wait for responses. Although WebSocket is its own protocol, it still uses HTTP to get setup. Every WebSocket connection will start with an HTTP request with special headers followed by an HTTP response with status 101 Switching Protocols . After this initial handshake, the connection is a WebSocket connection. WebSocket The WebSocket class represents a connected WebSocket client. You can use this to set callbacks for receiving data and to send data. let ws : WebSocket = ... // Send an initial message to this WebSocket ws . send ( Hello! ) // Set a new callback for receiving text formatted data ws . onText { ws , string in // Echo the text back, reversed. ws . send ( string . reversed ()) } Tip All callbacks will receive a reference to the WebSocket . Use these if you need to send data to avoid creating a reference cycle. The WebSocket has an onClose future that will be completed when the connection closes. You can use close() to close the connection yourself. Server WebSocket servers connect to one or more WebSocket clients at a time. As mentioned previously, WebSocket connections must start via an HTTP request and response handshake. Because of this, WebSocket servers are built on top of HTTP servers using the HTTP upgrade mechanism. // First, create an HTTPProtocolUpgrader let ws = HTTPServer . webSocketUpgrader ( shouldUpgrade : { req in // Returning nil in this closure will reject upgrade if req . url . path == /deny { return nil } // Return any additional headers you like, or just empty return [:] }, onUpgrade : { ws , req in // This closure will be called with each new WebSocket client ws . send ( Connected ) ws . onText { ws , string in ws . send ( string . reversed ()) } }) // Next, create your server, adding the WebSocket upgrader let server = try HTTPServer . start ( ... upgraders : [ ws ], ... ). wait () // Run the server. try server . onClose . wait () Seealso Visit HTTP \u2192 Server for more information on setting up an HTTP server. The WebSocket protocol upgrader consists of two callbacks. The first callback shouldUpgrade receives the incoming HTTP request that is requesting upgrade. This callback decides whether or not to complete the upgrade based on the contents of the request. If nil is returned in this closure, the upgrade will be rejected. The second callback onUpgrade is called each time a new WebSocket client connects. This is where you configure your callbacks and send any initial data. Warning The upgrade closures may be called on any event loop. Be careful to avoid race conditions if you must access external variables. Client You can also use the WebSocket package to connect to a WebSocket server. Just like the WebSocket server used an HTTP server, the WebSocket client uses HTTP client. // Create a new WebSocket connected to echo.websocket.org let ws = try HTTPClient . webSocket ( hostname : echo.websocket.org , on : ...). wait () // Set a new callback for receiving text formatted data. ws . onText { ws , text in print ( Server echo: \\( text ) ) } // Send a message. ws . send ( Hello, world! ) // Wait for the Websocket to closre. try ws . onClose . wait () Seealso Visit HTTP \u2192 Client for more information on setting up an HTTP client. API Docs Check out the API docs for more in-depth information about all of the methods.","title":"Overview"},{"location":"websocket/overview/#using-websockets","text":"Unlike HTTP, WebSockets allow you to communicate between client and server in an open, interactive way. You can send messages (called frames) in either text or binary format. Both the client and the server can send as many messages as they want at a time, without having to wait for responses. Although WebSocket is its own protocol, it still uses HTTP to get setup. Every WebSocket connection will start with an HTTP request with special headers followed by an HTTP response with status 101 Switching Protocols . After this initial handshake, the connection is a WebSocket connection.","title":"Using WebSockets"},{"location":"websocket/overview/#websocket","text":"The WebSocket class represents a connected WebSocket client. You can use this to set callbacks for receiving data and to send data. let ws : WebSocket = ... // Send an initial message to this WebSocket ws . send ( Hello! ) // Set a new callback for receiving text formatted data ws . onText { ws , string in // Echo the text back, reversed. ws . send ( string . reversed ()) } Tip All callbacks will receive a reference to the WebSocket . Use these if you need to send data to avoid creating a reference cycle. The WebSocket has an onClose future that will be completed when the connection closes. You can use close() to close the connection yourself.","title":"WebSocket"},{"location":"websocket/overview/#server","text":"WebSocket servers connect to one or more WebSocket clients at a time. As mentioned previously, WebSocket connections must start via an HTTP request and response handshake. Because of this, WebSocket servers are built on top of HTTP servers using the HTTP upgrade mechanism. // First, create an HTTPProtocolUpgrader let ws = HTTPServer . webSocketUpgrader ( shouldUpgrade : { req in // Returning nil in this closure will reject upgrade if req . url . path == /deny { return nil } // Return any additional headers you like, or just empty return [:] }, onUpgrade : { ws , req in // This closure will be called with each new WebSocket client ws . send ( Connected ) ws . onText { ws , string in ws . send ( string . reversed ()) } }) // Next, create your server, adding the WebSocket upgrader let server = try HTTPServer . start ( ... upgraders : [ ws ], ... ). wait () // Run the server. try server . onClose . wait () Seealso Visit HTTP \u2192 Server for more information on setting up an HTTP server. The WebSocket protocol upgrader consists of two callbacks. The first callback shouldUpgrade receives the incoming HTTP request that is requesting upgrade. This callback decides whether or not to complete the upgrade based on the contents of the request. If nil is returned in this closure, the upgrade will be rejected. The second callback onUpgrade is called each time a new WebSocket client connects. This is where you configure your callbacks and send any initial data. Warning The upgrade closures may be called on any event loop. Be careful to avoid race conditions if you must access external variables.","title":"Server"},{"location":"websocket/overview/#client","text":"You can also use the WebSocket package to connect to a WebSocket server. Just like the WebSocket server used an HTTP server, the WebSocket client uses HTTP client. // Create a new WebSocket connected to echo.websocket.org let ws = try HTTPClient . webSocket ( hostname : echo.websocket.org , on : ...). wait () // Set a new callback for receiving text formatted data. ws . onText { ws , text in print ( Server echo: \\( text ) ) } // Send a message. ws . send ( Hello, world! ) // Wait for the Websocket to closre. try ws . onClose . wait () Seealso Visit HTTP \u2192 Client for more information on setting up an HTTP client.","title":"Client"},{"location":"websocket/overview/#api-docs","text":"Check out the API docs for more in-depth information about all of the methods.","title":"API Docs"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Vapor Documentation This is the documentation for Vapor, a Web Framework for Swift that works on macOS and Ubuntu, and all of the packages that Vapor offers. Vapor is the most used web framework for Swift. It provides a beautifully expressive and easy to use foundation for your next website or API. Getting Started If this is your first time using Vapor, head to the Install macOS section to install Swift and Vapor. Once you have Vapor installed, check out Getting Started Hello, world to create your first Vapor app! Like Vapor? Our small team works hard to make Vapor awesome (and free). Support the framework by starring Vapor on GitHub or donating $1 monthly it helps us a lot. Thanks! Other Sources Here are some other great places to find information about Vapor. name description link Vapor Discord Chat with thousands of Vapor developers. visit API docs Auto-generated documentation from code comments. visit Stack Overflow Ask and answer questions with the vapor tag. visit Swift Forums Post in Vapor's section of the Swift.org forums. visit Source Code Learn how Vapor works under the hood. visit GitHub Issues Report bugs or request features on GitHub. visit Service Providers Vapor providers are a convenient way to add functionality to your Vapor projects. For a full list of providers, check out the vapor-service tag on GitHub. Authors Tanner Nelson , Logan Wright , and the hundreds of members of Vapor.","title":"Overview"},{"location":"#vapor-documentation","text":"This is the documentation for Vapor, a Web Framework for Swift that works on macOS and Ubuntu, and all of the packages that Vapor offers. Vapor is the most used web framework for Swift. It provides a beautifully expressive and easy to use foundation for your next website or API.","title":"Vapor Documentation"},{"location":"#getting-started","text":"If this is your first time using Vapor, head to the Install macOS section to install Swift and Vapor. Once you have Vapor installed, check out Getting Started Hello, world to create your first Vapor app!","title":"Getting Started"},{"location":"#like-vapor","text":"Our small team works hard to make Vapor awesome (and free). Support the framework by starring Vapor on GitHub or donating $1 monthly it helps us a lot. Thanks!","title":"Like Vapor?"},{"location":"#other-sources","text":"Here are some other great places to find information about Vapor. name description link Vapor Discord Chat with thousands of Vapor developers. visit API docs Auto-generated documentation from code comments. visit Stack Overflow Ask and answer questions with the vapor tag. visit Swift Forums Post in Vapor's section of the Swift.org forums. visit Source Code Learn how Vapor works under the hood. visit GitHub Issues Report bugs or request features on GitHub. visit","title":"Other Sources"},{"location":"#service-providers","text":"Vapor providers are a convenient way to add functionality to your Vapor projects. For a full list of providers, check out the vapor-service tag on GitHub.","title":"Service Providers"},{"location":"#authors","text":"Tanner Nelson , Logan Wright , and the hundreds of members of Vapor.","title":"Authors"},{"location":"async/getting-started/","text":"Getting Started with Async The Async module is provided as a part of Vapor Core ( vapor/core ). It is a collection of convenience APIs (mostly extensions) built on top of SwiftNIO . Tip You can read more about SwiftNIO's async types ( Future , Promise , EventLoop , and more) in its GitHub README or its API Docs . Usage This package is included with Vapor and exported by default. You will have access to all Async APIs when you import Vapor . import Vapor // implies `import Async` Standalone The Async module, part of the larger Vapor Core package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/core.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Async , ... ]) ] ) Use import Async to access the APIs. Overview Continue to Async Overview for an overview of Async's features.","title":"Getting Started"},{"location":"async/getting-started/#getting-started-with-async","text":"The Async module is provided as a part of Vapor Core ( vapor/core ). It is a collection of convenience APIs (mostly extensions) built on top of SwiftNIO . Tip You can read more about SwiftNIO's async types ( Future , Promise , EventLoop , and more) in its GitHub README or its API Docs .","title":"Getting Started with Async"},{"location":"async/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Async APIs when you import Vapor . import Vapor // implies `import Async`","title":"Usage"},{"location":"async/getting-started/#standalone","text":"The Async module, part of the larger Vapor Core package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/core.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Async , ... ]) ] ) Use import Async to access the APIs.","title":"Standalone"},{"location":"async/getting-started/#overview","text":"Continue to Async Overview for an overview of Async's features.","title":"Overview"},{"location":"async/overview/","text":"Async Overview You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. Promises and futures are related, but distinct, types. Promises are used to create futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises. type description mutability methods Future Reference to an object that may not be available yet. read-only .map(to:_:) .flatMap(to:_:) do(_:) catch(_:) Promise A promise to provide some object asynchronously. read/write succeed(_:) fail(_:) Futures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful. Transforming Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures. method signature description map to: U.Type, _: (T) - U Maps a future value to a different value. flatMap to: U.Type, _: (T) - Future U Maps a future value to different future value. transform to: U Maps a future to an already available value. If you look at the method signatures for map and flatMap on Optional T and Array T , you will see that they are very similar to the methods available on Future T . Map The .map(to:_:) method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int Flat Map The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your generic futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes! Transform The .transform(_:) method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of Future Void where the actual value of the future is not important. Tip Future Void , sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation. /// Assume we get a void future back from some API let userDidSave : Future Void = ... /// Transform the void future to an HTTP status let futureStatus = userDidSave . transform ( to : HTTPStatus . ok ) print ( futureStatus ) // Future HTTPStatus Even though we have supplied an already-available value to transform , this is still a transformation . The future will not complete until all previous futures have completed (or failed). Chaining The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown. Future Let's take a look at some other, less commonly used methods on Future T . Do / Catch Similar to Swift's do / catch syntax, futures have a do and catch method for awaiting the future's result. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . do { string in print ( string ) // The actual String }. catch { error in print ( error ) // A Swift Error } Info .do and .catch work together. If you forget .catch , the compiler will warn you about an unused result. Don't forget to handle the error case! Always You can use always to add a callback that will be executed whether the future succeeds or fails. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . always { print ( The future is complete! ) } Note You can add as many callbacks to a future as you want. Wait You can use .wait() to synchronously wait for the future to be completed. Since a future may fail, this call is throwing. /// Assume we get a future string back from some API let futureString : Future String = ... /// Block until the string is ready let string = try futureString . wait () print ( string ) /// String Warning Do not use this method in route closures or controllers. Read the section about Blocking for more information. Promise Most of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own. To create a promise, you will need access to an EventLoop . All containers in Vapor have an eventLoop property that you can use. Most commonly, this will be the current Request . /// Create a new promise for some string let promiseString = req . eventLoop . newPromise ( String . self ) print ( promiseString ) // Promise String print ( promiseString . futureResult ) // Future String /// Completes the associated future promiseString . succeed ( result : Hello ) /// Fails the associated future promiseString . fail ( error : ...) Info A promise can only be completed once. Any subsequent completions will be ignored. Thread Safety Promises can be completed ( succeed(result:) / fail(error:) ) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution. Event Loop When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading. Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed. Worker Things that have access to an event loop are called Workers . Every container in Vapor is a worker. The most common containers you will interact with in Vapor are: Application Request Response You can use the .eventLoop property on these containers to gain access to the event loop. print ( app . eventLoop ) // EventLoop There are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like on: Worker . If you are in a route closure or a controller, pass the current Request or Response . If you need a worker while booting your app, use the Application . Blocking An absolutely critical rule is the following: Danger Never make blocking calls directly on an event loop. An example of a blocking call would be something like libc.sleep(_:) . router . get ( hello ) { req in /// Puts the event loop s thread to sleep. sleep ( 5 ) /// Returns a simple string once the thread re-awakens. return Hello, world! } sleep(_:) is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do sleep(5) on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds. Make sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way. router . get ( hello ) { req in /// Create a new void promise let promise = req . eventLoop . newPromise ( Void . self ) /// Dispatch some work to happen on a background thread DispatchQueue . global () { /// Puts the background thread to sleep /// This will not affect any of the event loops sleep ( 5 ) /// When the blocking work has completed, /// complete the promise and its associated future. promise . succeed () } /// Wait for the future to be completed, /// then transform the result to a simple String return promise . futureResult . transform ( to : Hello, world! ) } Not all blocking calls will be as obvious as sleep(_:) . If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking. Info If doing blocking work is a central part of your application, you should consider using a BlockingIOThreadPool to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.","title":"Overview"},{"location":"async/overview/#async-overview","text":"You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. Promises and futures are related, but distinct, types. Promises are used to create futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises. type description mutability methods Future Reference to an object that may not be available yet. read-only .map(to:_:) .flatMap(to:_:) do(_:) catch(_:) Promise A promise to provide some object asynchronously. read/write succeed(_:) fail(_:) Futures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful.","title":"Async Overview"},{"location":"async/overview/#transforming","text":"Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures. method signature description map to: U.Type, _: (T) - U Maps a future value to a different value. flatMap to: U.Type, _: (T) - Future U Maps a future value to different future value. transform to: U Maps a future to an already available value. If you look at the method signatures for map and flatMap on Optional T and Array T , you will see that they are very similar to the methods available on Future T .","title":"Transforming"},{"location":"async/overview/#map","text":"The .map(to:_:) method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int","title":"Map"},{"location":"async/overview/#flat-map","text":"The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your generic futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes!","title":"Flat Map"},{"location":"async/overview/#transform","text":"The .transform(_:) method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of Future Void where the actual value of the future is not important. Tip Future Void , sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation. /// Assume we get a void future back from some API let userDidSave : Future Void = ... /// Transform the void future to an HTTP status let futureStatus = userDidSave . transform ( to : HTTPStatus . ok ) print ( futureStatus ) // Future HTTPStatus Even though we have supplied an already-available value to transform , this is still a transformation . The future will not complete until all previous futures have completed (or failed).","title":"Transform"},{"location":"async/overview/#chaining","text":"The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown.","title":"Chaining"},{"location":"async/overview/#future","text":"Let's take a look at some other, less commonly used methods on Future T .","title":"Future"},{"location":"async/overview/#do-catch","text":"Similar to Swift's do / catch syntax, futures have a do and catch method for awaiting the future's result. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . do { string in print ( string ) // The actual String }. catch { error in print ( error ) // A Swift Error } Info .do and .catch work together. If you forget .catch , the compiler will warn you about an unused result. Don't forget to handle the error case!","title":"Do / Catch"},{"location":"async/overview/#always","text":"You can use always to add a callback that will be executed whether the future succeeds or fails. /// Assume we get a future string back from some API let futureString : Future String = ... futureString . always { print ( The future is complete! ) } Note You can add as many callbacks to a future as you want.","title":"Always"},{"location":"async/overview/#wait","text":"You can use .wait() to synchronously wait for the future to be completed. Since a future may fail, this call is throwing. /// Assume we get a future string back from some API let futureString : Future String = ... /// Block until the string is ready let string = try futureString . wait () print ( string ) /// String Warning Do not use this method in route closures or controllers. Read the section about Blocking for more information.","title":"Wait"},{"location":"async/overview/#promise","text":"Most of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own. To create a promise, you will need access to an EventLoop . All containers in Vapor have an eventLoop property that you can use. Most commonly, this will be the current Request . /// Create a new promise for some string let promiseString = req . eventLoop . newPromise ( String . self ) print ( promiseString ) // Promise String print ( promiseString . futureResult ) // Future String /// Completes the associated future promiseString . succeed ( result : Hello ) /// Fails the associated future promiseString . fail ( error : ...) Info A promise can only be completed once. Any subsequent completions will be ignored.","title":"Promise"},{"location":"async/overview/#thread-safety","text":"Promises can be completed ( succeed(result:) / fail(error:) ) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution.","title":"Thread Safety"},{"location":"async/overview/#event-loop","text":"When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading. Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed.","title":"Event Loop"},{"location":"async/overview/#worker","text":"Things that have access to an event loop are called Workers . Every container in Vapor is a worker. The most common containers you will interact with in Vapor are: Application Request Response You can use the .eventLoop property on these containers to gain access to the event loop. print ( app . eventLoop ) // EventLoop There are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like on: Worker . If you are in a route closure or a controller, pass the current Request or Response . If you need a worker while booting your app, use the Application .","title":"Worker"},{"location":"async/overview/#blocking","text":"An absolutely critical rule is the following: Danger Never make blocking calls directly on an event loop. An example of a blocking call would be something like libc.sleep(_:) . router . get ( hello ) { req in /// Puts the event loop s thread to sleep. sleep ( 5 ) /// Returns a simple string once the thread re-awakens. return Hello, world! } sleep(_:) is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do sleep(5) on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds. Make sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way. router . get ( hello ) { req in /// Create a new void promise let promise = req . eventLoop . newPromise ( Void . self ) /// Dispatch some work to happen on a background thread DispatchQueue . global () { /// Puts the background thread to sleep /// This will not affect any of the event loops sleep ( 5 ) /// When the blocking work has completed, /// complete the promise and its associated future. promise . succeed () } /// Wait for the future to be completed, /// then transform the result to a simple String return promise . futureResult . transform ( to : Hello, world! ) } Not all blocking calls will be as obvious as sleep(_:) . If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking. Info If doing blocking work is a central part of your application, you should consider using a BlockingIOThreadPool to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.","title":"Blocking"},{"location":"auth/api/","text":"API Authentication This guide will introduce you to stateless authentication a method of authentication commonly used for protecting API endpoints. Concept In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource This package allows you to implement stateless authorization using the following tools: \"Authorization\" header : Used to send credentials in an HTTP request. Middleware : Detects credentials in request and fetches authenticated user. Model : Represents an authenticated user and its identifying information. Authorization Header This packages makes use of two common authorization header formats: basic and bearer. Basic Basic authorization contains a username and password. They are joined together by a : and then base64 encoded. A basic authorization header containing the username Alladin and password OpenSesame would look like this: Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l Although basic authorization can be used to authenticate each request to your server, most web applications usually create an ephemeral token for this purpose instead. Bearer Bearer authorization simply contains a token. A bearer authorization header containing the token cn389ncoiwuencr would look like this: Authorization: Bearer cn389ncoiwuencr The bearer authorization header is very common in APIs since it can be sent easily with each request and contain an ephemeral token. Middleware The usage of Middleware is critical to this package. If you are not familiar with how Middleware works in Vapor, feel free to brush up by reading Vapor Middleware . Authentication middleware is responsible for reading the credentials from the request and fetching the identifier user. This usually means checking the \"Authorization\" header, parsing the credentials, and doing a database lookup. For each model / authentication method you use, you will add one middleware to your application. All of this package's middlewares are composable, meaning you can add multiple middlewares to one route and they will work together. If one middleware fails to authorize a user, it will simply forward the request for the next middleware to try. If you would like to ensure that a certain model's authentication has succeeded before running your route, you must add an instance of GuardAuthenticationMiddleware . Model Fluent models are what the middlewares authenticate. Learn more about models by reading Fluent Models . If authentication is succesful, the middleware will have fetched your model from the database and stored it on the request. This means you can access an authenticated model synchronously in your route. In your route closure, you use the following methods to check for authentication: authenticated(_:) : Returns type if authenticated, nil if not. isAuthenticated(_:) : Returns true if supplied type is authenticated. requireAuthenticated(_:) : Returns type if authenticated, throws if not. Typical usage looks like the following: // use middleware to protect a group let protectedGroup = router . group (...) // add a protected route protectedGroup . get ( test ) { req in // require that a User has been authed by middleware or throw let user = try req . requireAuthenticated ( User . self ) // say hello to the user return Hello, \\( user . name ) . } Methods This package supports two basic types of stateless authentication. Token : Uses the bearer authorization header. Password : Uses the basic authorization header. For each authentication type, there is a separate middleware and model protocol. Password Authentication Password authentication uses the basic authorization header (username and password) to verify a user. With this method, the username and password must be sent with each request to a protected endpoint. To use password authentication, you will first need to conform your Fluent model to PasswordAuthenticatable . extension User : PasswordAuthenticatable { /// See `PasswordAuthenticatable`. static var usernameKey : WritableKeyPath User , String { return \\ . email } /// See `PasswordAuthenticatable`. static var passwordKey : WritableKeyPath User , String { return \\ . passwordHash } } Note that the passwordKey should point to the hashed password. Never store passwords in plaintext. Once you have created an authenticatable model, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let password = User . basicAuthMiddleware ( using : BCryptDigest ()) // Create a route closure wrapped by this middleware router . grouped ( password ). get ( hello ) { req in /// } Here we are using BCryptDigest as the PasswordVerifier since we are assuming the user's password is stored as a BCrypt hash. Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required. Token Authentication Token authentication uses the bearer authorization header (token) to lookup a token and its related user. With this method, the token must be sent with each request to a protected endpoint. Unlike password authentication, token authentication relies on two Fluent models. One for the token and one for the user. The token model should be a child of the user model. Here is an example of a very basic User and associated UserToken . struct User : Model { var id : Int ? var name : String var email : String var passwordHash : String var tokens : Children User , UserToken { return children ( \\ . userID ) } } struct UserToken : Model { var id : Int ? var string : String var userID : User . ID var user : Parent UserToken , User { return parent ( \\ . userID ) } } The first step to using token authentication is to conform your user and token models to their respective Authenticatable protocols. extension UserToken : Token { /// See `Token`. typealias UserType = User /// See `Token`. static var tokenKey : WritableKeyPath UserToken , String { return \\ . string } /// See `Token`. static var userIDKey : WritableKeyPath UserToken , User . ID { return \\ . userID } } Once the token is conformed to Token , setting up the user model is easy. extension User : TokenAuthenticatable { /// See `TokenAuthenticatable`. typealias TokenType = UserToken } Once you have conformed your models, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let token = User . tokenAuthMiddleware () // Create a route closure wrapped by this middleware router . grouped ( token ). get ( hello ) { // } Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required.","title":"Stateless (API)"},{"location":"auth/api/#api-authentication","text":"This guide will introduce you to stateless authentication a method of authentication commonly used for protecting API endpoints.","title":"API Authentication"},{"location":"auth/api/#concept","text":"In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource This package allows you to implement stateless authorization using the following tools: \"Authorization\" header : Used to send credentials in an HTTP request. Middleware : Detects credentials in request and fetches authenticated user. Model : Represents an authenticated user and its identifying information.","title":"Concept"},{"location":"auth/api/#authorization-header","text":"This packages makes use of two common authorization header formats: basic and bearer.","title":"Authorization Header"},{"location":"auth/api/#basic","text":"Basic authorization contains a username and password. They are joined together by a : and then base64 encoded. A basic authorization header containing the username Alladin and password OpenSesame would look like this: Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l Although basic authorization can be used to authenticate each request to your server, most web applications usually create an ephemeral token for this purpose instead.","title":"Basic"},{"location":"auth/api/#bearer","text":"Bearer authorization simply contains a token. A bearer authorization header containing the token cn389ncoiwuencr would look like this: Authorization: Bearer cn389ncoiwuencr The bearer authorization header is very common in APIs since it can be sent easily with each request and contain an ephemeral token.","title":"Bearer"},{"location":"auth/api/#middleware","text":"The usage of Middleware is critical to this package. If you are not familiar with how Middleware works in Vapor, feel free to brush up by reading Vapor Middleware . Authentication middleware is responsible for reading the credentials from the request and fetching the identifier user. This usually means checking the \"Authorization\" header, parsing the credentials, and doing a database lookup. For each model / authentication method you use, you will add one middleware to your application. All of this package's middlewares are composable, meaning you can add multiple middlewares to one route and they will work together. If one middleware fails to authorize a user, it will simply forward the request for the next middleware to try. If you would like to ensure that a certain model's authentication has succeeded before running your route, you must add an instance of GuardAuthenticationMiddleware .","title":"Middleware"},{"location":"auth/api/#model","text":"Fluent models are what the middlewares authenticate. Learn more about models by reading Fluent Models . If authentication is succesful, the middleware will have fetched your model from the database and stored it on the request. This means you can access an authenticated model synchronously in your route. In your route closure, you use the following methods to check for authentication: authenticated(_:) : Returns type if authenticated, nil if not. isAuthenticated(_:) : Returns true if supplied type is authenticated. requireAuthenticated(_:) : Returns type if authenticated, throws if not. Typical usage looks like the following: // use middleware to protect a group let protectedGroup = router . group (...) // add a protected route protectedGroup . get ( test ) { req in // require that a User has been authed by middleware or throw let user = try req . requireAuthenticated ( User . self ) // say hello to the user return Hello, \\( user . name ) . }","title":"Model"},{"location":"auth/api/#methods","text":"This package supports two basic types of stateless authentication. Token : Uses the bearer authorization header. Password : Uses the basic authorization header. For each authentication type, there is a separate middleware and model protocol.","title":"Methods"},{"location":"auth/api/#password-authentication","text":"Password authentication uses the basic authorization header (username and password) to verify a user. With this method, the username and password must be sent with each request to a protected endpoint. To use password authentication, you will first need to conform your Fluent model to PasswordAuthenticatable . extension User : PasswordAuthenticatable { /// See `PasswordAuthenticatable`. static var usernameKey : WritableKeyPath User , String { return \\ . email } /// See `PasswordAuthenticatable`. static var passwordKey : WritableKeyPath User , String { return \\ . passwordHash } } Note that the passwordKey should point to the hashed password. Never store passwords in plaintext. Once you have created an authenticatable model, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let password = User . basicAuthMiddleware ( using : BCryptDigest ()) // Create a route closure wrapped by this middleware router . grouped ( password ). get ( hello ) { req in /// } Here we are using BCryptDigest as the PasswordVerifier since we are assuming the user's password is stored as a BCrypt hash. Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required.","title":"Password Authentication"},{"location":"auth/api/#token-authentication","text":"Token authentication uses the bearer authorization header (token) to lookup a token and its related user. With this method, the token must be sent with each request to a protected endpoint. Unlike password authentication, token authentication relies on two Fluent models. One for the token and one for the user. The token model should be a child of the user model. Here is an example of a very basic User and associated UserToken . struct User : Model { var id : Int ? var name : String var email : String var passwordHash : String var tokens : Children User , UserToken { return children ( \\ . userID ) } } struct UserToken : Model { var id : Int ? var string : String var userID : User . ID var user : Parent UserToken , User { return parent ( \\ . userID ) } } The first step to using token authentication is to conform your user and token models to their respective Authenticatable protocols. extension UserToken : Token { /// See `Token`. typealias UserType = User /// See `Token`. static var tokenKey : WritableKeyPath UserToken , String { return \\ . string } /// See `Token`. static var userIDKey : WritableKeyPath UserToken , User . ID { return \\ . userID } } Once the token is conformed to Token , setting up the user model is easy. extension User : TokenAuthenticatable { /// See `TokenAuthenticatable`. typealias TokenType = UserToken } Once you have conformed your models, the next step is to add middleware to your protected route. // Use user model to create an authentication middleware let token = User . tokenAuthMiddleware () // Create a route closure wrapped by this middleware router . grouped ( token ). get ( hello ) { // } Now, to fetch the authenticated user in the route closure, you can use requireAuthenticated(_:) . let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) . The requireAuthenticated method will automatically throw an appropriate unauthorized error if the valid credentials were not supplied. Because of this, using GuardAuthenticationMiddleware to protect the route from unauthenticated access is not required.","title":"Token Authentication"},{"location":"auth/getting-started/","text":"Getting Started with Auth Auth ( vapor/auth ) is a framework for adding authentication to your application. It builds on top of Fluent by using models as the basis of authentication. Tip There is a Vapor API template with Auth pre-configured available. See Getting Started Toolbox Templates . Let's take a look at how you can get started using Auth. Package The first step to using Auth is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc64 Authentication and Authorization framework for Fluent. . package ( url : https://github.com/vapor/auth.git , from : 2.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Authentication , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Auth currently provides one module Authentication . In the future, there will be a separate module named Authorization for performing more advanced auth. Provider Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Authentication // register Authentication provider try services . register ( AuthenticationProvider ()) That's it for basic setup. The next step is to create an authenticatable model.","title":"Getting Started"},{"location":"auth/getting-started/#getting-started-with-auth","text":"Auth ( vapor/auth ) is a framework for adding authentication to your application. It builds on top of Fluent by using models as the basis of authentication. Tip There is a Vapor API template with Auth pre-configured available. See Getting Started Toolbox Templates . Let's take a look at how you can get started using Auth.","title":"Getting Started with Auth"},{"location":"auth/getting-started/#package","text":"The first step to using Auth is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc64 Authentication and Authorization framework for Fluent. . package ( url : https://github.com/vapor/auth.git , from : 2.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Authentication , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Auth currently provides one module Authentication . In the future, there will be a separate module named Authorization for performing more advanced auth.","title":"Package"},{"location":"auth/getting-started/#provider","text":"Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Authentication // register Authentication provider try services . register ( AuthenticationProvider ()) That's it for basic setup. The next step is to create an authenticatable model.","title":"Provider"},{"location":"auth/web/","text":"Web Authentication This guide will introduce you to session-based authentication a method of authentication commonly used for protecting web (front-end) pages. Concept In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource Session-based authentication uses cookies to re-authenticate users with each request to your website. It performs this logic via a middleware that you add to your application or specific routes. You are responsible for initially authenticating the user to your application (either manually or by using methods from the Stateless (API) section). Once you have authenticated the user once, the middleware will use cookies to re-authenticate the user on subsequent requests automatically. Example Let's take a look at a simple session-based authentication example. Pre-requisites In order to do session-based authentication, you must have a way to initially authenticate your user. In other words, you need a method for logging them in. The Stateless (API) section covers some of these methods, but it's entirely up to you. You will also need to have sessions configured for your application. You can learn more about this in Vapor Sessions . Usually this will require adding the SessionsMiddleware and choosing a KeyedCache . config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) var middlewares = MiddlewareConfig () middlewares . use ( SessionsMiddleware . self ) // ... services . register ( middlewares ) Model Once you are ready to enable session-based authentication, the first step is to conform your user model to SessionAuthenticatable . extension User : SessionAuthenticatable { } The conformance is empty since all of the required methods have default implementations. Middleware Once your model is conformed, you can use it to create an AuthenticationSessionsMiddleware . // create auth sessions middleware for user let session = User . authSessionsMiddleware () // create a route group wrapped by this middleware let auth = router . grouped ( session ) // create new route in this route group auth . get ( hello ) { req - String in // } Create a route group wrapped by this middleware using the route grouping methods. Any routes you want to support session-based authentication should use this route group. You can also apply this middleware globally to your application if you'd like. Route Inside of any route closure wrapped by the session auth middleware, we can access our authenticated model using the authenticated(_:) methods. let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) ! Here we are using the method prefixed with require to throw an error if the user was not succesfully authenticated. If you visit this route now, you should see a message saying no user has been authenticated. Let's resolve this by creating a way for our user to login! Note Use GuardAuthenticationMiddleware to protect routes that do not call requireAuthenticated(_:) or otherwise require authentication. Login For the sake of this example, we will just log in a pre-defined user with a fixed ID. auth . get ( login ) { req - Future String in return User . find ( 1 , on : req ). map { user in guard let user = user else { throw Abort (. badRequest ) } try req . authenticate ( user ) return Logged in } } Remember that this login route must go through the AuthenticationSessionsMiddleware . The middleware is what will detect that we have authenticated a user and later restore the authentication automatically. Upon visiting /hello , you should recieve an error message stating that you are not logged in. If you then visit /login first, followed by /hello you should see that you are now successfully logged in! If you open the inspector, you should notice a new cookie named \"vapor-session\" has been added to your browser.","title":"Sessions (Web)"},{"location":"auth/web/#web-authentication","text":"This guide will introduce you to session-based authentication a method of authentication commonly used for protecting web (front-end) pages.","title":"Web Authentication"},{"location":"auth/web/#concept","text":"In Computer Science (especially web frameworks), the concept of Authentication means verifying the identity of a user. This is not to be confused with Authorization which verifies privileges to a given resource Session-based authentication uses cookies to re-authenticate users with each request to your website. It performs this logic via a middleware that you add to your application or specific routes. You are responsible for initially authenticating the user to your application (either manually or by using methods from the Stateless (API) section). Once you have authenticated the user once, the middleware will use cookies to re-authenticate the user on subsequent requests automatically.","title":"Concept"},{"location":"auth/web/#example","text":"Let's take a look at a simple session-based authentication example.","title":"Example"},{"location":"auth/web/#pre-requisites","text":"In order to do session-based authentication, you must have a way to initially authenticate your user. In other words, you need a method for logging them in. The Stateless (API) section covers some of these methods, but it's entirely up to you. You will also need to have sessions configured for your application. You can learn more about this in Vapor Sessions . Usually this will require adding the SessionsMiddleware and choosing a KeyedCache . config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) var middlewares = MiddlewareConfig () middlewares . use ( SessionsMiddleware . self ) // ... services . register ( middlewares )","title":"Pre-requisites"},{"location":"auth/web/#model","text":"Once you are ready to enable session-based authentication, the first step is to conform your user model to SessionAuthenticatable . extension User : SessionAuthenticatable { } The conformance is empty since all of the required methods have default implementations.","title":"Model"},{"location":"auth/web/#middleware","text":"Once your model is conformed, you can use it to create an AuthenticationSessionsMiddleware . // create auth sessions middleware for user let session = User . authSessionsMiddleware () // create a route group wrapped by this middleware let auth = router . grouped ( session ) // create new route in this route group auth . get ( hello ) { req - String in // } Create a route group wrapped by this middleware using the route grouping methods. Any routes you want to support session-based authentication should use this route group. You can also apply this middleware globally to your application if you'd like.","title":"Middleware"},{"location":"auth/web/#route","text":"Inside of any route closure wrapped by the session auth middleware, we can access our authenticated model using the authenticated(_:) methods. let user = try req . requireAuthenticated ( User . self ) return Hello, \\( user . name ) ! Here we are using the method prefixed with require to throw an error if the user was not succesfully authenticated. If you visit this route now, you should see a message saying no user has been authenticated. Let's resolve this by creating a way for our user to login! Note Use GuardAuthenticationMiddleware to protect routes that do not call requireAuthenticated(_:) or otherwise require authentication.","title":"Route"},{"location":"auth/web/#login","text":"For the sake of this example, we will just log in a pre-defined user with a fixed ID. auth . get ( login ) { req - Future String in return User . find ( 1 , on : req ). map { user in guard let user = user else { throw Abort (. badRequest ) } try req . authenticate ( user ) return Logged in } } Remember that this login route must go through the AuthenticationSessionsMiddleware . The middleware is what will detect that we have authenticated a user and later restore the authentication automatically. Upon visiting /hello , you should recieve an error message stating that you are not logged in. If you then visit /login first, followed by /hello you should see that you are now successfully logged in! If you open the inspector, you should notice a new cookie named \"vapor-session\" has been added to your browser.","title":"Login"},{"location":"command/getting-started/","text":"Getting Started with Command The Command module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for creating command-line interfaces (CLIs). It's what powers the Vapor Toolbox . Tip For an in-depth look at all of Command's APIs, check out the Command API docs . Usage This package is included with Vapor and exported by default. You will have access to all Command APIs when you import Vapor . import Vapor // implies import Command Standalone The Command module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Command , ... ]) ] ) Use import Command to access the APIs. Overview Continue to Command \u2192 Overview for an overview of Command's features.","title":"Getting Started"},{"location":"command/getting-started/#getting-started-with-command","text":"The Command module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for creating command-line interfaces (CLIs). It's what powers the Vapor Toolbox . Tip For an in-depth look at all of Command's APIs, check out the Command API docs .","title":"Getting Started with Command"},{"location":"command/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Command APIs when you import Vapor . import Vapor // implies import Command","title":"Usage"},{"location":"command/getting-started/#standalone","text":"The Command module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Command , ... ]) ] ) Use import Command to access the APIs.","title":"Standalone"},{"location":"command/getting-started/#overview","text":"Continue to Command \u2192 Overview for an overview of Command's features.","title":"Overview"},{"location":"command/overview/","text":"Command Overview This guide will introduce you to the Command module by showing you how to create your own CLI. For this example, we will implement cowsay , a command that prints an ASCII picture of a cow with a message. Tip You can install the real cowsay program using brew install cowsay . $ cowsay Hello ----- Hello ----- \\ ^__^ \\ ( oo \\_ ______ ( __ ) \\ ) \\/\\ || ----w | || || Command The first step is to create a type that conforms to Command . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... } Now let's implement the required methods. Arguments Commands can have zero or more CommandArgument s. These arguments will be required for the command to run. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { /// See `Command` var arguments : [ CommandArgument ] { return [. argument ( name : message )] } ... } Here we are defining one argument, the message that the cow will say. This is required to run the cowsay command. Options Commands can have zero or more CommandOption s. These options are not required for the command to run and can be passed using -- or - syntax. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var options : [ CommandOption ] { return [ . value ( name : eyes , short : e , default : oo , help : [ Change cow s eyes ]), . value ( name : tongue , short : t , default : , help : [ Change cow s tongue ]), ] } ... } Here we are defining two options, eyes and tongue . These will let the user optionally change how the cow looks. Help Next we can define an optional help message to display when the user passes --help . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var help : [ String ] { return [ Generates ASCII picture of a cow with a message. ] } ... } Let's take a look at how this will look once our command is complete: Usage: executable cowsay message [ --eyes,-e ] [ --tongue,-t ] Generates ASCII picture of a cow with a message. Arguments: message n/a Options: eyes Change cow s eyes tongue Change cow s tongue Run Finally, we need to write our implementation: /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command`. func run ( using context : CommandContext ) throws - Future Void { let message = try context . argument ( message ) /// We can use requireOption here since both options have default values let eyes = try context . requireOption ( eyes ) let tongue = try context . requireOption ( tongue ) let padding = String ( repeating : - , count : message . count ) let text : String = \\( padding ) \\( message ) \\( padding ) \\\\ ^__^ \\\\ ( \\( eyes ) \\\\ _______ (__) \\\\ ) \\\\ / \\\\ \\( tongue ) ||----w | || || context . console . print ( text ) return . done ( on : context . container ) } } The CommandContext gives you access to everything you will need, including a Container . Now that we have a complete Command , the next step is to configure it. Config Use the CommandConfig struct to register commands to your container. This is usually done in configure.swift /// Create a `CommandConfig` with default commands. var commandConfig = CommandConfig . default () /// Add the `CowsayCommand`. commandConfig . use ( CowsayCommand (), as : cowsay ) /// Register this `CommandConfig` to services. services . register ( commandConfig ) Check that your command was properly configured using --help . swift run Run cowsay -- help That's it! $ swift run Run cowsay Good job ! - e ^^ - t U --------- Good job ! --------- \\ ^ __ ^ \\ ( ^^ \\ _______ ( __ ) \\ ) \\ / \\ U ||---- w | || ||","title":"Overview"},{"location":"command/overview/#command-overview","text":"This guide will introduce you to the Command module by showing you how to create your own CLI. For this example, we will implement cowsay , a command that prints an ASCII picture of a cow with a message. Tip You can install the real cowsay program using brew install cowsay . $ cowsay Hello ----- Hello ----- \\ ^__^ \\ ( oo \\_ ______ ( __ ) \\ ) \\/\\ || ----w | || ||","title":"Command Overview"},{"location":"command/overview/#command","text":"The first step is to create a type that conforms to Command . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... } Now let's implement the required methods.","title":"Command"},{"location":"command/overview/#arguments","text":"Commands can have zero or more CommandArgument s. These arguments will be required for the command to run. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { /// See `Command` var arguments : [ CommandArgument ] { return [. argument ( name : message )] } ... } Here we are defining one argument, the message that the cow will say. This is required to run the cowsay command.","title":"Arguments"},{"location":"command/overview/#options","text":"Commands can have zero or more CommandOption s. These options are not required for the command to run and can be passed using -- or - syntax. /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var options : [ CommandOption ] { return [ . value ( name : eyes , short : e , default : oo , help : [ Change cow s eyes ]), . value ( name : tongue , short : t , default : , help : [ Change cow s tongue ]), ] } ... } Here we are defining two options, eyes and tongue . These will let the user optionally change how the cow looks.","title":"Options"},{"location":"command/overview/#help","text":"Next we can define an optional help message to display when the user passes --help . /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command` var help : [ String ] { return [ Generates ASCII picture of a cow with a message. ] } ... } Let's take a look at how this will look once our command is complete: Usage: executable cowsay message [ --eyes,-e ] [ --tongue,-t ] Generates ASCII picture of a cow with a message. Arguments: message n/a Options: eyes Change cow s eyes tongue Change cow s tongue","title":"Help"},{"location":"command/overview/#run","text":"Finally, we need to write our implementation: /// Generates ASCII picture of a cow with a message. struct CowsayCommand : Command { ... /// See `Command`. func run ( using context : CommandContext ) throws - Future Void { let message = try context . argument ( message ) /// We can use requireOption here since both options have default values let eyes = try context . requireOption ( eyes ) let tongue = try context . requireOption ( tongue ) let padding = String ( repeating : - , count : message . count ) let text : String = \\( padding ) \\( message ) \\( padding ) \\\\ ^__^ \\\\ ( \\( eyes ) \\\\ _______ (__) \\\\ ) \\\\ / \\\\ \\( tongue ) ||----w | || || context . console . print ( text ) return . done ( on : context . container ) } } The CommandContext gives you access to everything you will need, including a Container . Now that we have a complete Command , the next step is to configure it.","title":"Run"},{"location":"command/overview/#config","text":"Use the CommandConfig struct to register commands to your container. This is usually done in configure.swift /// Create a `CommandConfig` with default commands. var commandConfig = CommandConfig . default () /// Add the `CowsayCommand`. commandConfig . use ( CowsayCommand (), as : cowsay ) /// Register this `CommandConfig` to services. services . register ( commandConfig ) Check that your command was properly configured using --help . swift run Run cowsay -- help That's it! $ swift run Run cowsay Good job ! - e ^^ - t U --------- Good job ! --------- \\ ^ __ ^ \\ ( ^^ \\ _______ ( __ ) \\ ) \\ / \\ U ||---- w | || ||","title":"Config"},{"location":"console/getting-started/","text":"Getting Started with Console The Console module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for performing console I/O including things like outputting stylized text, requesting user input, and displaying activity indicators like loading bars. Tip For an in-depth look at all of Console's APIs, check out the Console API docs . Usage This package is included with Vapor and exported by default. You will have access to all Console APIs when you import Vapor . import Vapor // implies import Console Standalone The Console module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Console , ... ]) ] ) Use import Console to access the APIs. Overview Continue to Console \u2192 Overview for an overview of Console's features.","title":"Getting Started"},{"location":"console/getting-started/#getting-started-with-console","text":"The Console module is provided as a part of Vapor's Console package ( vapor/console ). This module provides APIs for performing console I/O including things like outputting stylized text, requesting user input, and displaying activity indicators like loading bars. Tip For an in-depth look at all of Console's APIs, check out the Console API docs .","title":"Getting Started with Console"},{"location":"console/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Console APIs when you import Vapor . import Vapor // implies import Console","title":"Usage"},{"location":"console/getting-started/#standalone","text":"The Console module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Console , ... ]) ] ) Use import Console to access the APIs.","title":"Standalone"},{"location":"console/getting-started/#overview","text":"Continue to Console \u2192 Overview for an overview of Console's features.","title":"Overview"},{"location":"console/overview/","text":"Console Overview This guide will give you a brief introduction to the Console module, showing you how to output stylized text and request user input. Terminal A default implementation of the Console protocol called Terminal is provided for you to use. let terminal = Terminal () print ( terminal is Console ) // true terminal . print ( Hello ) The rest of this guide will assume a generic Console , but using Terminal directly will also work fine. You can use any available Container to create a console. let console = try req . make ( Console . self ) console . print ( Hello ) Output Console provides several convenience methods for outputting strings, like print(_:) and warning(_:) . All of these methods eventually call output(_:) which is the most powerful output method. This method accepts ConsoleText which supports independently styled string components. /// Prints Hello, world , but the word world is blue. console . output ( Hello, + world . consoleText ( color : . blue )) You can combine as many differently styled fragments to a ConsoleText as you like. All Console methods that output text should have an overload for accepting ConsoleText . Input Console offers several methods for requesting input from the user, the most basic of which is input(isSecure:) . /// Accepts input from the terminal until the first newline. let input = console . input () console . print ( You wrote: \\( input ) ) Ask Use ask(_:) to supply a prompt and input indicator to the user. /// Outputs the prompt then requests input. let name = console . ask ( What is your name? ) console . print ( You said: \\( name ) ) The above code will output: What is your name? Vapor You said: Vapor Confirm Use confirm(_:) to prompt the user for yes / no input. /// Prompts the user for yes / no input. if console . confirm ( Are you sure? ) { // they are sure } else { // don t do it! } The above code will output: Are you sure ? y / n yes Note confirm(_:) will continue to prompt the user until they respond with something recognized as yes or no.","title":"Overview"},{"location":"console/overview/#console-overview","text":"This guide will give you a brief introduction to the Console module, showing you how to output stylized text and request user input.","title":"Console Overview"},{"location":"console/overview/#terminal","text":"A default implementation of the Console protocol called Terminal is provided for you to use. let terminal = Terminal () print ( terminal is Console ) // true terminal . print ( Hello ) The rest of this guide will assume a generic Console , but using Terminal directly will also work fine. You can use any available Container to create a console. let console = try req . make ( Console . self ) console . print ( Hello )","title":"Terminal"},{"location":"console/overview/#output","text":"Console provides several convenience methods for outputting strings, like print(_:) and warning(_:) . All of these methods eventually call output(_:) which is the most powerful output method. This method accepts ConsoleText which supports independently styled string components. /// Prints Hello, world , but the word world is blue. console . output ( Hello, + world . consoleText ( color : . blue )) You can combine as many differently styled fragments to a ConsoleText as you like. All Console methods that output text should have an overload for accepting ConsoleText .","title":"Output"},{"location":"console/overview/#input","text":"Console offers several methods for requesting input from the user, the most basic of which is input(isSecure:) . /// Accepts input from the terminal until the first newline. let input = console . input () console . print ( You wrote: \\( input ) )","title":"Input"},{"location":"console/overview/#ask","text":"Use ask(_:) to supply a prompt and input indicator to the user. /// Outputs the prompt then requests input. let name = console . ask ( What is your name? ) console . print ( You said: \\( name ) ) The above code will output: What is your name? Vapor You said: Vapor","title":"Ask"},{"location":"console/overview/#confirm","text":"Use confirm(_:) to prompt the user for yes / no input. /// Prompts the user for yes / no input. if console . confirm ( Are you sure? ) { // they are sure } else { // don t do it! } The above code will output: Are you sure ? y / n yes Note confirm(_:) will continue to prompt the user until they respond with something recognized as yes or no.","title":"Confirm"},{"location":"crypto/asymmetric/","text":"Asymmetric Cryptography Asymmetric cryptography (also called public-key cryptography) is a cryptographic system that uses multiple keys usually a \"public\" and \"private\" key. Read more about public-key cryptography on Wikipedia. RSA A popular asymmetric cryptography algorithm is RSA. RSA has two key types: public and private. RSA can create signatures from any data using a private key. let privateKey : String = ... let signature = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) Info Only private keys can create signatures. These signatures can be verified against the same data later using either the public or private key. let publicKey : String = ... try RSA . SHA512 . verify ( signature , signs : vapor , key : . public ( pem : publicKey )) // true If RSA verifies that a signature matches input data for a public key, you can be sure that whoever generated that signature had access to that key's private key. Algorithms RSA supports any of the Crypto module's DigestAlgorithm . let privateKey : String = ... let signature512 = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) let signature256 = try RSA . SHA256 . sign ( vapor , key : . private ( pem : privateKey ))","title":"Asymmetric"},{"location":"crypto/asymmetric/#asymmetric-cryptography","text":"Asymmetric cryptography (also called public-key cryptography) is a cryptographic system that uses multiple keys usually a \"public\" and \"private\" key. Read more about public-key cryptography on Wikipedia.","title":"Asymmetric Cryptography"},{"location":"crypto/asymmetric/#rsa","text":"A popular asymmetric cryptography algorithm is RSA. RSA has two key types: public and private. RSA can create signatures from any data using a private key. let privateKey : String = ... let signature = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) Info Only private keys can create signatures. These signatures can be verified against the same data later using either the public or private key. let publicKey : String = ... try RSA . SHA512 . verify ( signature , signs : vapor , key : . public ( pem : publicKey )) // true If RSA verifies that a signature matches input data for a public key, you can be sure that whoever generated that signature had access to that key's private key.","title":"RSA"},{"location":"crypto/asymmetric/#algorithms","text":"RSA supports any of the Crypto module's DigestAlgorithm . let privateKey : String = ... let signature512 = try RSA . SHA512 . sign ( vapor , key : . private ( pem : privateKey )) let signature256 = try RSA . SHA256 . sign ( vapor , key : . private ( pem : privateKey ))","title":"Algorithms"},{"location":"crypto/ciphers/","text":"Cipher Algorithms Ciphers allow you to encrypt plaintext data with a key yielding ciphertext. This ciphertext can be later decrypted by the same cipher using the same key. Read more about ciphers on Wikipedia. Encrypt Use the global convenience variables for encrypting data with common algorithms. let ciphertext = try AES128 . encrypt ( vapor , key : secret ) print ( ciphertext ) /// Data Decrypt Decryption works very similarly to encryption . The following snippet shows how to decrypt the ciphertext from our previous example. let plaintext = try AES128 . decrypt ( ciphertext , key : secret ) print ( plaintext ) /// vapor See the Crypto module's global variables for a list of all available cipher algorithms. Streaming Both encryption and decryption can work in a streaming mode that allows data to be chunked. This is useful for controlling memory usage while encrypting large amounts of data. let key : Data // 16-bytes let aes128 = Cipher ( algorithm : . aes128ecb ) try aes128 . reset ( key : key , mode : . encrypt ) var buffer = Data () try aes128 . update ( data : hello , into : buffer ) try aes128 . update ( data : world , into : buffer ) try aes128 . finish ( into : buffer ) print ( buffer ) // Completed ciphertext","title":"Ciphers"},{"location":"crypto/ciphers/#cipher-algorithms","text":"Ciphers allow you to encrypt plaintext data with a key yielding ciphertext. This ciphertext can be later decrypted by the same cipher using the same key. Read more about ciphers on Wikipedia.","title":"Cipher Algorithms"},{"location":"crypto/ciphers/#encrypt","text":"Use the global convenience variables for encrypting data with common algorithms. let ciphertext = try AES128 . encrypt ( vapor , key : secret ) print ( ciphertext ) /// Data","title":"Encrypt"},{"location":"crypto/ciphers/#decrypt","text":"Decryption works very similarly to encryption . The following snippet shows how to decrypt the ciphertext from our previous example. let plaintext = try AES128 . decrypt ( ciphertext , key : secret ) print ( plaintext ) /// vapor See the Crypto module's global variables for a list of all available cipher algorithms.","title":"Decrypt"},{"location":"crypto/ciphers/#streaming","text":"Both encryption and decryption can work in a streaming mode that allows data to be chunked. This is useful for controlling memory usage while encrypting large amounts of data. let key : Data // 16-bytes let aes128 = Cipher ( algorithm : . aes128ecb ) try aes128 . reset ( key : key , mode : . encrypt ) var buffer = Data () try aes128 . update ( data : hello , into : buffer ) try aes128 . update ( data : world , into : buffer ) try aes128 . finish ( into : buffer ) print ( buffer ) // Completed ciphertext","title":"Streaming"},{"location":"crypto/digests/","text":"Message Digests Cryptographic hash functions (also known as message digest algorithms) convert data of arbitrary size to a fixed-size digest. These are most often used for generating checksums or identifiers for large data blobs. Read more about Cryptographic hash functions on Wikipedia. Hash Use the global convenience variables to create hashes using common algorithms. import Crypto let digest = try SHA1 . hash ( hello ) print ( digest . hexEncodedString ()) // aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d See the Crypto module's global variables for a list of all available hash algorithms. Streaming You can create a Digest manually and use its instance methods to create a hash for one or more data chunks. var sha256 = try Digest ( algorithm : . sha256 ) try sha256 . reset () try sha256 . update ( data : hello ) try sha256 . update ( data : world ) let digest = try sha256 . finish () print ( digest ) /// Data BCrypt BCrypt is a popular hashing algorithm that has configurable complexity and handles salting automatically. Hash Use the hash(_:cost:salt:) method to create BCrypt hashes. let digest = try BCrypt . hash ( vapor , cost : 4 ) print ( digest ) /// data Increasing the cost value will make hashing and verification take longer. Verify Use the verify(_:created:) method to verify that a BCrypt hash was created by a given plaintext input. let hash = try BCrypt . hash ( vapor , cost : 4 ) try BCrypt . verify ( vapor , created : hash ) // true try BCrypt . verify ( foo , created : hash ) // false HMAC HMAC is an algorithm for creating keyed hashes. HMAC will generate different hashes for the same input if different keys are used. let digest = try HMAC . SHA1 . authenticate ( vapor , key : secret ) print ( digest . hexEncodedString ()) // digest See the HMAC class for a list of all available hash algorithms. Streaming HMAC hashes can also be streamed. The API is identical to hash streaming .","title":"Digests"},{"location":"crypto/digests/#message-digests","text":"Cryptographic hash functions (also known as message digest algorithms) convert data of arbitrary size to a fixed-size digest. These are most often used for generating checksums or identifiers for large data blobs. Read more about Cryptographic hash functions on Wikipedia.","title":"Message Digests"},{"location":"crypto/digests/#hash","text":"Use the global convenience variables to create hashes using common algorithms. import Crypto let digest = try SHA1 . hash ( hello ) print ( digest . hexEncodedString ()) // aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d See the Crypto module's global variables for a list of all available hash algorithms.","title":"Hash"},{"location":"crypto/digests/#streaming","text":"You can create a Digest manually and use its instance methods to create a hash for one or more data chunks. var sha256 = try Digest ( algorithm : . sha256 ) try sha256 . reset () try sha256 . update ( data : hello ) try sha256 . update ( data : world ) let digest = try sha256 . finish () print ( digest ) /// Data","title":"Streaming"},{"location":"crypto/digests/#bcrypt","text":"BCrypt is a popular hashing algorithm that has configurable complexity and handles salting automatically.","title":"BCrypt"},{"location":"crypto/digests/#hash_1","text":"Use the hash(_:cost:salt:) method to create BCrypt hashes. let digest = try BCrypt . hash ( vapor , cost : 4 ) print ( digest ) /// data Increasing the cost value will make hashing and verification take longer.","title":"Hash"},{"location":"crypto/digests/#verify","text":"Use the verify(_:created:) method to verify that a BCrypt hash was created by a given plaintext input. let hash = try BCrypt . hash ( vapor , cost : 4 ) try BCrypt . verify ( vapor , created : hash ) // true try BCrypt . verify ( foo , created : hash ) // false","title":"Verify"},{"location":"crypto/digests/#hmac","text":"HMAC is an algorithm for creating keyed hashes. HMAC will generate different hashes for the same input if different keys are used. let digest = try HMAC . SHA1 . authenticate ( vapor , key : secret ) print ( digest . hexEncodedString ()) // digest See the HMAC class for a list of all available hash algorithms.","title":"HMAC"},{"location":"crypto/digests/#streaming_1","text":"HMAC hashes can also be streamed. The API is identical to hash streaming .","title":"Streaming"},{"location":"crypto/getting-started/","text":"Using Crypto Crypto ( vapor/crypto ) is a library containing common APIs related to cryptography and data generation. The package contains two modules: Crypto Random With Vapor This package is included with Vapor by default, just add: import Crypto import Random Without Vapor To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/crypto.git , . upToNextMajor ( from : x.0.0 )), ], targets : [ . target ( name : Project , dependencies : [ Crypto , Random , ... ]) ] ) Use import Crypto to access Crypto's APIs and import Random to access Random's APIs.","title":"Getting Started"},{"location":"crypto/getting-started/#using-crypto","text":"Crypto ( vapor/crypto ) is a library containing common APIs related to cryptography and data generation. The package contains two modules: Crypto Random","title":"Using Crypto"},{"location":"crypto/getting-started/#with-vapor","text":"This package is included with Vapor by default, just add: import Crypto import Random","title":"With Vapor"},{"location":"crypto/getting-started/#without-vapor","text":"To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/crypto.git , . upToNextMajor ( from : x.0.0 )), ], targets : [ . target ( name : Project , dependencies : [ Crypto , Random , ... ]) ] ) Use import Crypto to access Crypto's APIs and import Random to access Random's APIs.","title":"Without Vapor"},{"location":"crypto/otp/","text":"TOTP and HOTP One-time passwords (OTPs) are commonly used as a form of two-factor authentication . Crypto can be used to generate both TOTP and HOTP in accordance with RFC 6238 and RFC 4226 respectively. TOTP : Time-based One-Time Password. Generates password by combining shared secret with unix timestamp. HOTP : HMAC-Based One-Time Password. Similar to TOTP, except an incrementing counter is used instead of a timestamp. Each time a new OTP is generated, the counter increments. Generating OTP OTP generation is similar for both TOTP and HOTP. The only difference is that HOTP requires the current counter to be passed. import Crypto // Generate TOTP let code = TOTP . SHA1 . generate ( secret : hi ) print ( code ) 123456 // Generate HOTP let code = HOTP . SHA1 . generate ( secret : hi , counter : 0 ) print ( code ) 208503 View the API docs for TOTP and HOTP for more information. Base 32 TOTP and HOTP shared secrets are commonly transferred using Base32 encoding. Crypto provides conveniences for converting to/from Base32. import Crypto // shared secret let secret : Data = ... // base32 encoded secret let encodedSecret = secret . base32EncodedString () See Crypto's Data extensions for more information.","title":"TOTP & HOTP"},{"location":"crypto/otp/#totp-and-hotp","text":"One-time passwords (OTPs) are commonly used as a form of two-factor authentication . Crypto can be used to generate both TOTP and HOTP in accordance with RFC 6238 and RFC 4226 respectively. TOTP : Time-based One-Time Password. Generates password by combining shared secret with unix timestamp. HOTP : HMAC-Based One-Time Password. Similar to TOTP, except an incrementing counter is used instead of a timestamp. Each time a new OTP is generated, the counter increments.","title":"TOTP and HOTP"},{"location":"crypto/otp/#generating-otp","text":"OTP generation is similar for both TOTP and HOTP. The only difference is that HOTP requires the current counter to be passed. import Crypto // Generate TOTP let code = TOTP . SHA1 . generate ( secret : hi ) print ( code ) 123456 // Generate HOTP let code = HOTP . SHA1 . generate ( secret : hi , counter : 0 ) print ( code ) 208503 View the API docs for TOTP and HOTP for more information.","title":"Generating OTP"},{"location":"crypto/otp/#base-32","text":"TOTP and HOTP shared secrets are commonly transferred using Base32 encoding. Crypto provides conveniences for converting to/from Base32. import Crypto // shared secret let secret : Data = ... // base32 encoded secret let encodedSecret = secret . base32EncodedString () See Crypto's Data extensions for more information.","title":"Base 32"},{"location":"crypto/random/","text":"Random The Random module deals with random data generation including random number generation. Data Generator The DataGenerator class powers all of the random data generators. Implementations OSRandom : Provides a random data generator using a platform-specific method. URandom provides random data generation based on the /dev/urandom file. CryptoRandom from the Crypto module provides cryptographically-secure random data using OpenSSL. let random : DataGenerator ... let data = try random . generateData ( bytes : 8 ) Generate DataGenerator s are capable of generating random primitive types using the generate(_:) method. let int = try OSRandom (). generate ( Int . self ) print ( int ) // Int","title":"Random"},{"location":"crypto/random/#random","text":"The Random module deals with random data generation including random number generation.","title":"Random"},{"location":"crypto/random/#data-generator","text":"The DataGenerator class powers all of the random data generators.","title":"Data Generator"},{"location":"crypto/random/#implementations","text":"OSRandom : Provides a random data generator using a platform-specific method. URandom provides random data generation based on the /dev/urandom file. CryptoRandom from the Crypto module provides cryptographically-secure random data using OpenSSL. let random : DataGenerator ... let data = try random . generateData ( bytes : 8 )","title":"Implementations"},{"location":"crypto/random/#generate","text":"DataGenerator s are capable of generating random primitive types using the generate(_:) method. let int = try OSRandom (). generate ( Int . self ) print ( int ) // Int","title":"Generate"},{"location":"database-kit/getting-started/","text":"Getting Started with Database Kit Database Kit ( vapor/database-kit ) is a framework for configuring and working with database connections. It includes core services like caching, logging, and connection pooling. Tip If you use Fluent, you will usually not need to use Database Kit manually. But learning the APIs may come in handy. Package The Database Kit package is lightweight, pure Swift, and has few dependencies. This means it can be used as a core database framework for any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/database-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ DatabaseKit , ... ]) ] ) Use import DatabaseKit to access the APIs. API Docs The rest of this guide will give you an overview of what is available in the DatabaseKit package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"database-kit/getting-started/#getting-started-with-database-kit","text":"Database Kit ( vapor/database-kit ) is a framework for configuring and working with database connections. It includes core services like caching, logging, and connection pooling. Tip If you use Fluent, you will usually not need to use Database Kit manually. But learning the APIs may come in handy.","title":"Getting Started with Database Kit"},{"location":"database-kit/getting-started/#package","text":"The Database Kit package is lightweight, pure Swift, and has few dependencies. This means it can be used as a core database framework for any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/database-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ DatabaseKit , ... ]) ] ) Use import DatabaseKit to access the APIs.","title":"Package"},{"location":"database-kit/getting-started/#api-docs","text":"The rest of this guide will give you an overview of what is available in the DatabaseKit package. As always, feel free to visit the API docs for more in-depth information.","title":"API Docs"},{"location":"database-kit/overview/","text":"Using Database Kit Database Kit is a framework for configuring and working with database connections. It helps you do things like manage and pool connections, create keyed caches, and log queries. Many of Vapor's packages such as the Fluent drivers, Redis, and Vapor core are built on top of Database Kit. This guide will walk you through some of the common APIs you might encounter when using Database Kit. Config Your first interaction with Database Kit will most likely be with the DatabasesConfig struct. This type helps you configure one or more databases to your application and will ultimately yield a Databases struct. This usually takes place in configure.swift . // Create a SQLite database. let sqliteDB = SQLiteDatabase (...) // Create a new, empty DatabasesConfig. var dbsConfig = DatabasesConfig () // Register the SQLite database using .sqlite as an identifier. dbsConfig . add ( sqliteDB , as : . sqlite ) // Register more DBs here if you want // Register the DatabaseConfig to services. services . register ( dbsConfig ) Using the add(...) methods, you can register Database s to the config. You can register instances of a database, a database type, or a closure that creates a database. The latter two methods will be resolved when your container boots. You can also configure options on your databases, such as enabling logging. // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) See the section on logging for more information. Identifier Most database integrations will provide a default DatabaseIdentifier to use. However, you can always create your own. This is usually done by creating a static extension. extension DatabaseIdentifier { /// Test database. static var testing : DatabaseIdentifier MySQLDatabase { return testing } } DatabaseIdentifier is ExpressibleByStringLiteral which allows you to create one with just a String . Databases Once you have registered a DatabasesConfig to your services and booted a container, you can take advantage of the convenience extensions on Container to start creating connections. // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } Read more about creating and managing connections in the next section. Connections Database Kit's main focus is on creating, managing, and pooling connections. Creating new connections takes a non-trivial amount of time for your application and many cloud services limit the total number of connections to a service that can be open. Because of this, it is important for high-concurrency web applications to manage their connections carefully. Pools A common solution to connection management is the use of connection pools. These pools usually have a set maximum number of connections that are allowed to be open at once. Each time the pool is asked for a connection, it will first check if one is available before creating a new connection. If none are available, it will create a new one. If no connections are available and the pool is already at its maximum, the request for a new connection will wait for a connection to be returned. The easiest way to request and release a pooled connection is the method withPooledConnection(...) . // Requests a pooled connection to `.psql` db req . withPooledConnection ( to : . psql ) { conn in return conn . query (...) // do some db query } This method will request a pooled connection to the identified database and call the provided closure when the connection is available. When the Future returned by the closure has completed, the connection will automatically be returned to the pool. If you need access to a connection outside of a closure, you can use the related request / release methods instead. // Request a connection from the pool and wait for it to be ready. let conn = try app . requestPooledConnection ( to : . psql ). wait () // Ensure the connection is released when we exit this scope. defer { app . releasePooledConnection ( conn , to : . psql ) } You can configure your connection pools using the DatabaseConnectionPoolConfig struct. // Create a new, empty pool config. var poolConfig = DatabaseConnectionPoolConfig () // Set max connections per pool to 8. poolConfig . maxConnections = 8 // Register the pool config. services . register ( poolConfig ) To prevent race conditions, pools are never shared between event loops. There is usually one pool per database per event loop. This means that the amount of connections your application can potentially open to a given database is equal to numThreads * maxConns . New You can always create a new connection to your databases if you need to. This will not affect your pooled connections. Creating new connections is especially useful during testing and app boot. But try not to do it in route closures since heavy traffic to your app could end up creating a lot of connections! Similar to pooled connections, opening and closing new connections can be done using withNewConnection(...) . // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } This method will create a new connection, calling the supplied closure when the connection is open. When the Future returned in the closure completes, the connection will be closed automatically. You can also simply open a new connection with newConnection(...) . // Creates a new connection to `.sqlite` db let conn = try app . newConnection ( to : . sqlite ). wait () // Ensure the connection is closed when we exit this scope. defer { conn . close () } Logging Databases can opt into supporting query logging via the LogSupporting protocol. Databases that conform to this protocol can have loggers configured via DatabasesConfig . // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) By default, a simple print logger will be used, but you can pass a custom DatabaseLogHandler . // Create a custom log handler. let myLogger : DatabaseLogHandler = ... // Enable logging on SQLite w/ custom logger. dbsConfig . enableLogging ( for : . sqlite , logger : myLogger ) Log handlers will receive an instance of DatabaseLog for each logged query. This contains information such as the query, parameterized values, database id, and time. Keyed Cache Databases can opt into supporting keyed-caching via the KeyedCacheSupporting protocol. Databases that conform to this protocol can be used to create instances of DatabaseKeyedCache . Keyed caches are capable of getting, setting, and removing Codable values at keys. They are sometimes called \"key value stores\". To create a keyed cache, you can use the extensions on Container . // Creates a DatabaseKeyedCache with .redis connection pool let cache = try app . keyedCache ( for : . redis ) // Sets hello = world try cache . set ( hello , to : world ). wait () // Gets hello let world = try cache . get ( hello , as : String . self ). wait () print ( world ) // world // Removes hello try cache . remove ( hello ). wait () See the KeyedCache protocol for more information. API Docs Check out the API docs for more in-depth information about DatabaseKit's APIs.","title":"Overview"},{"location":"database-kit/overview/#using-database-kit","text":"Database Kit is a framework for configuring and working with database connections. It helps you do things like manage and pool connections, create keyed caches, and log queries. Many of Vapor's packages such as the Fluent drivers, Redis, and Vapor core are built on top of Database Kit. This guide will walk you through some of the common APIs you might encounter when using Database Kit.","title":"Using Database Kit"},{"location":"database-kit/overview/#config","text":"Your first interaction with Database Kit will most likely be with the DatabasesConfig struct. This type helps you configure one or more databases to your application and will ultimately yield a Databases struct. This usually takes place in configure.swift . // Create a SQLite database. let sqliteDB = SQLiteDatabase (...) // Create a new, empty DatabasesConfig. var dbsConfig = DatabasesConfig () // Register the SQLite database using .sqlite as an identifier. dbsConfig . add ( sqliteDB , as : . sqlite ) // Register more DBs here if you want // Register the DatabaseConfig to services. services . register ( dbsConfig ) Using the add(...) methods, you can register Database s to the config. You can register instances of a database, a database type, or a closure that creates a database. The latter two methods will be resolved when your container boots. You can also configure options on your databases, such as enabling logging. // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) See the section on logging for more information.","title":"Config"},{"location":"database-kit/overview/#identifier","text":"Most database integrations will provide a default DatabaseIdentifier to use. However, you can always create your own. This is usually done by creating a static extension. extension DatabaseIdentifier { /// Test database. static var testing : DatabaseIdentifier MySQLDatabase { return testing } } DatabaseIdentifier is ExpressibleByStringLiteral which allows you to create one with just a String .","title":"Identifier"},{"location":"database-kit/overview/#databases","text":"Once you have registered a DatabasesConfig to your services and booted a container, you can take advantage of the convenience extensions on Container to start creating connections. // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } Read more about creating and managing connections in the next section.","title":"Databases"},{"location":"database-kit/overview/#connections","text":"Database Kit's main focus is on creating, managing, and pooling connections. Creating new connections takes a non-trivial amount of time for your application and many cloud services limit the total number of connections to a service that can be open. Because of this, it is important for high-concurrency web applications to manage their connections carefully.","title":"Connections"},{"location":"database-kit/overview/#pools","text":"A common solution to connection management is the use of connection pools. These pools usually have a set maximum number of connections that are allowed to be open at once. Each time the pool is asked for a connection, it will first check if one is available before creating a new connection. If none are available, it will create a new one. If no connections are available and the pool is already at its maximum, the request for a new connection will wait for a connection to be returned. The easiest way to request and release a pooled connection is the method withPooledConnection(...) . // Requests a pooled connection to `.psql` db req . withPooledConnection ( to : . psql ) { conn in return conn . query (...) // do some db query } This method will request a pooled connection to the identified database and call the provided closure when the connection is available. When the Future returned by the closure has completed, the connection will automatically be returned to the pool. If you need access to a connection outside of a closure, you can use the related request / release methods instead. // Request a connection from the pool and wait for it to be ready. let conn = try app . requestPooledConnection ( to : . psql ). wait () // Ensure the connection is released when we exit this scope. defer { app . releasePooledConnection ( conn , to : . psql ) } You can configure your connection pools using the DatabaseConnectionPoolConfig struct. // Create a new, empty pool config. var poolConfig = DatabaseConnectionPoolConfig () // Set max connections per pool to 8. poolConfig . maxConnections = 8 // Register the pool config. services . register ( poolConfig ) To prevent race conditions, pools are never shared between event loops. There is usually one pool per database per event loop. This means that the amount of connections your application can potentially open to a given database is equal to numThreads * maxConns .","title":"Pools"},{"location":"database-kit/overview/#new","text":"You can always create a new connection to your databases if you need to. This will not affect your pooled connections. Creating new connections is especially useful during testing and app boot. But try not to do it in route closures since heavy traffic to your app could end up creating a lot of connections! Similar to pooled connections, opening and closing new connections can be done using withNewConnection(...) . // Creates a new connection to `.sqlite` db app . withNewConnection ( to : . sqlite ) { conn in return conn . query (...) // do some db query } This method will create a new connection, calling the supplied closure when the connection is open. When the Future returned in the closure completes, the connection will be closed automatically. You can also simply open a new connection with newConnection(...) . // Creates a new connection to `.sqlite` db let conn = try app . newConnection ( to : . sqlite ). wait () // Ensure the connection is closed when we exit this scope. defer { conn . close () }","title":"New"},{"location":"database-kit/overview/#logging","text":"Databases can opt into supporting query logging via the LogSupporting protocol. Databases that conform to this protocol can have loggers configured via DatabasesConfig . // Enable logging on the SQLite database dbsConfig . enableLogging ( for : . sqlite ) By default, a simple print logger will be used, but you can pass a custom DatabaseLogHandler . // Create a custom log handler. let myLogger : DatabaseLogHandler = ... // Enable logging on SQLite w/ custom logger. dbsConfig . enableLogging ( for : . sqlite , logger : myLogger ) Log handlers will receive an instance of DatabaseLog for each logged query. This contains information such as the query, parameterized values, database id, and time.","title":"Logging"},{"location":"database-kit/overview/#keyed-cache","text":"Databases can opt into supporting keyed-caching via the KeyedCacheSupporting protocol. Databases that conform to this protocol can be used to create instances of DatabaseKeyedCache . Keyed caches are capable of getting, setting, and removing Codable values at keys. They are sometimes called \"key value stores\". To create a keyed cache, you can use the extensions on Container . // Creates a DatabaseKeyedCache with .redis connection pool let cache = try app . keyedCache ( for : . redis ) // Sets hello = world try cache . set ( hello , to : world ). wait () // Gets hello let world = try cache . get ( hello , as : String . self ). wait () print ( world ) // world // Removes hello try cache . remove ( hello ). wait () See the KeyedCache protocol for more information.","title":"Keyed Cache"},{"location":"database-kit/overview/#api-docs","text":"Check out the API docs for more in-depth information about DatabaseKit's APIs.","title":"API Docs"},{"location":"fluent/getting-started/","text":"Getting Started with Fluent Fluent ( vapor/fluent ) is a type-safe, fast, and easy-to-use ORM framework built for Swift. It takes advantage of Swift's strong type system to provide an elegant foundation for building database integrations. Choosing a Driver Fluent is a framework for building ORMs, not an ORM itself. To use Fluent, you will first need to choose a database driver to use. Fluent can support multiple databases and database drivers per application. Below is a list of officially supported database drivers for Fluent. database repo version dbid notes PostgreSQL fluent-postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL fluent-mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite fluent-sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. MongoDB fluent-mongo n/a mongo Coming soon. Popular NoSQL database. Note Replace any Xcode placholders ( #...# ) in the code snippets below with information from the above table. You can search GitHub for the tag fluent-database for a full list of official and third-party Fluent database drivers. Package Once you have decided which driver you want, the next step is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/ #repo# .git , from : #version# ), ], targets : [ . target ( name : App , dependencies : [ Fluent #Database# , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Creating a Model Now let's create your first model. Models represent tables in your database and they are the primary method of interacting with your data. Each driver provides convenience model protocols ( PostgreSQLModel , SQLiteModel , etc) that extend Fluent's base Model protocol. These convenience types make declaring models more concise by using standard values for ID key and type. Fill in the Xcode placeholders below with the name of your chosen database, i.e., PostgreSQL . import Fluent # Database # import Vapor /// A simple user. final class User : # Database # Model { /// The unique identifier for this user. var id : ID ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : ID ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } The example above shows a simple model representing a user. You can make both structs and classes a model. You can even conform types that come from external modules. The only requirement is that these types conform to Codable , which must be declared on the base type for synthesized (automatic) conformance. Take a look at Fluent Model for more information on creating models with custom ID types and keys. Configuring the Database Now that you have a model, you can configure your database. This is done in configure.swift . Register Provider The first step is to register your database driver's provider. import Fluent # Database # import Vapor // Register providers first try services . register ( Fluent # Database # Provider ()) // Other services.... Registering the provider will add all of the services required for your Fluent database to work properly. It also includes a default database config struct that uses typical development environment credentials. Custom Credentials If you are using default configuration for your database (such as default credentials or other config) then this may be the only setup you need to perform. See the documentation for your specific database type for more information about custom configuration. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDatabase MySQL MySQL Getting Started MySQLDatabase SQLite SQLite Getting Started SQLiteDatabase Creating a Migration If your database driver uses schemas (is a SQL database), you will need to create a Migration for your new model. Migrations allow Fluent to create a table for your model in a reliable, testable way. You can later create additional migrations to update or delete the model's table or even manipulate data in the table. To create a migration, you will normally first create a new struct or class to hold the migration. However, models can take advantage of a convenient shortcut. When you create a migration from an existing model type, Fluent can infer an appropriate schema from the model's codable properties. You can add the migration conformance to a model as an extension or on the base type declaration. import Fluent # Database # import Vapor extension User : # Database # Migration { } Take a look at Fluent Migration if you are interested in learning more about custom migrations. Configuring Migrations Once you have created a migration, you must register it to Fluent using MigrationConfig . This is done in configure.swift . Fill in the database ID ( dbid ) from the table above, i.e., psql . import Fluent # Database # import Vapor // Configure migrations var migrations = MigrationConfig () migrations . add ( model : User . self , database : . # dbid # ) services . register ( migrations ) // Other services.... Tip If the migration you are adding is also a model, you can use the add(model:on:) convenience to automatically set the model's defaultDatabase property. Otherwise, use the add(migration:on) method. Once you have the MigrationConfig added, you should be able to run your application and see the following: Migrating #dbid# DB Migrations complete Server starting on http://localhost:8080 Performing a Query Now that you have created a model and a corresponding schema in your database, let's make your first query. router . get ( users ) { req in return User . query ( on : req ). all () } If you run your app, and query that route, you should see an empty array returned. Now you just need to add some users! Congratulations on getting your first Fluent model working. Raw Queries With Fluent, you always have access to the underlying database driver. Using this underlying driver to perform a query is sometimes called a \"raw query\". To perform raw queries, you need access to a database connection. Vapor's Request type has a number of conveniences for creating new database connections. The recommended method is withPooledConnection(to:) . Learn about other methods in DatabaseKit Overview Connections . router . get ( raw ) { req - Future String in return req . withPooledConnection ( to : . # dbid # ) { conn in // perform raw query using conn } } Once you have the database connection, you can perform a query on it. You can learn more about the methods available in the database's documentation.","title":"Getting Started"},{"location":"fluent/getting-started/#getting-started-with-fluent","text":"Fluent ( vapor/fluent ) is a type-safe, fast, and easy-to-use ORM framework built for Swift. It takes advantage of Swift's strong type system to provide an elegant foundation for building database integrations.","title":"Getting Started with Fluent"},{"location":"fluent/getting-started/#choosing-a-driver","text":"Fluent is a framework for building ORMs, not an ORM itself. To use Fluent, you will first need to choose a database driver to use. Fluent can support multiple databases and database drivers per application. Below is a list of officially supported database drivers for Fluent. database repo version dbid notes PostgreSQL fluent-postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL fluent-mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite fluent-sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. MongoDB fluent-mongo n/a mongo Coming soon. Popular NoSQL database. Note Replace any Xcode placholders ( #...# ) in the code snippets below with information from the above table. You can search GitHub for the tag fluent-database for a full list of official and third-party Fluent database drivers.","title":"Choosing a Driver"},{"location":"fluent/getting-started/#package","text":"Once you have decided which driver you want, the next step is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/ #repo# .git , from : #version# ), ], targets : [ . target ( name : App , dependencies : [ Fluent #Database# , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"fluent/getting-started/#creating-a-model","text":"Now let's create your first model. Models represent tables in your database and they are the primary method of interacting with your data. Each driver provides convenience model protocols ( PostgreSQLModel , SQLiteModel , etc) that extend Fluent's base Model protocol. These convenience types make declaring models more concise by using standard values for ID key and type. Fill in the Xcode placeholders below with the name of your chosen database, i.e., PostgreSQL . import Fluent # Database # import Vapor /// A simple user. final class User : # Database # Model { /// The unique identifier for this user. var id : ID ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : ID ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } The example above shows a simple model representing a user. You can make both structs and classes a model. You can even conform types that come from external modules. The only requirement is that these types conform to Codable , which must be declared on the base type for synthesized (automatic) conformance. Take a look at Fluent Model for more information on creating models with custom ID types and keys.","title":"Creating a Model"},{"location":"fluent/getting-started/#configuring-the-database","text":"Now that you have a model, you can configure your database. This is done in configure.swift .","title":"Configuring the Database"},{"location":"fluent/getting-started/#register-provider","text":"The first step is to register your database driver's provider. import Fluent # Database # import Vapor // Register providers first try services . register ( Fluent # Database # Provider ()) // Other services.... Registering the provider will add all of the services required for your Fluent database to work properly. It also includes a default database config struct that uses typical development environment credentials.","title":"Register Provider"},{"location":"fluent/getting-started/#custom-credentials","text":"If you are using default configuration for your database (such as default credentials or other config) then this may be the only setup you need to perform. See the documentation for your specific database type for more information about custom configuration. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDatabase MySQL MySQL Getting Started MySQLDatabase SQLite SQLite Getting Started SQLiteDatabase","title":"Custom Credentials"},{"location":"fluent/getting-started/#creating-a-migration","text":"If your database driver uses schemas (is a SQL database), you will need to create a Migration for your new model. Migrations allow Fluent to create a table for your model in a reliable, testable way. You can later create additional migrations to update or delete the model's table or even manipulate data in the table. To create a migration, you will normally first create a new struct or class to hold the migration. However, models can take advantage of a convenient shortcut. When you create a migration from an existing model type, Fluent can infer an appropriate schema from the model's codable properties. You can add the migration conformance to a model as an extension or on the base type declaration. import Fluent # Database # import Vapor extension User : # Database # Migration { } Take a look at Fluent Migration if you are interested in learning more about custom migrations.","title":"Creating a Migration"},{"location":"fluent/getting-started/#configuring-migrations","text":"Once you have created a migration, you must register it to Fluent using MigrationConfig . This is done in configure.swift . Fill in the database ID ( dbid ) from the table above, i.e., psql . import Fluent # Database # import Vapor // Configure migrations var migrations = MigrationConfig () migrations . add ( model : User . self , database : . # dbid # ) services . register ( migrations ) // Other services.... Tip If the migration you are adding is also a model, you can use the add(model:on:) convenience to automatically set the model's defaultDatabase property. Otherwise, use the add(migration:on) method. Once you have the MigrationConfig added, you should be able to run your application and see the following: Migrating #dbid# DB Migrations complete Server starting on http://localhost:8080","title":"Configuring Migrations"},{"location":"fluent/getting-started/#performing-a-query","text":"Now that you have created a model and a corresponding schema in your database, let's make your first query. router . get ( users ) { req in return User . query ( on : req ). all () } If you run your app, and query that route, you should see an empty array returned. Now you just need to add some users! Congratulations on getting your first Fluent model working.","title":"Performing a Query"},{"location":"fluent/getting-started/#raw-queries","text":"With Fluent, you always have access to the underlying database driver. Using this underlying driver to perform a query is sometimes called a \"raw query\". To perform raw queries, you need access to a database connection. Vapor's Request type has a number of conveniences for creating new database connections. The recommended method is withPooledConnection(to:) . Learn about other methods in DatabaseKit Overview Connections . router . get ( raw ) { req - Future String in return req . withPooledConnection ( to : . # dbid # ) { conn in // perform raw query using conn } } Once you have the database connection, you can perform a query on it. You can learn more about the methods available in the database's documentation.","title":"Raw Queries"},{"location":"fluent/migrations/","text":"Fluent Migrations Migrations allow you to make organized, testable, and reliable changes to your database's structure-- even while it's in production. Migrations are often used for preparing a database schema for your models. However, they can also be used to make normal queries to your database. In this guide we will cover creating both types of migrations. Creating and Deleting Schemas Let's take a look at how we can use migrations to prepare a schema supporting database to store a theoretical Galaxy model. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String } Automatic Model Migrations Models provide a shortcut for declaring database migrations. If you conform a type that conforms to Model to Migration , Fluent can infer the model's properties and automatically implement the prepare(...) and revert(...) methods. import Fluent # Database # extension Galaxy : # Database # Migration { } This method is especially useful for quick prototyping and simple setups. For most other situations you should consider creating a normal, custom migration. Add this automatic migration to your MigrationConfig using the add(model:database:) method. This is done in configure.swift . var migrations = MigrationConfig () migrations . add ( model : Galaxy . self , database : . # dbid # ) services . register ( migrations ) The add(model:database:) method will automatically set the model's defaultDatabase property. Custom Migrations We can customize the table created for our model by creating a migration and using the static create and delete methods on Database . import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... } Creating a Schema The most important method in a migration is prepare(...) . This is responsible for effecting the migration's changes. For our CreateGalaxy migration, we will use our database's static create method to create a schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . create ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . id , isIdentifier : true ) builder . field ( for : \\ . name ) } } } To create a schema, you must pass a model type and connection as the first two parameters. The third parameter is a closure that accepts the SchemaBuilder . This builder has convenience methods for declaring fields in the schema. You can use the field(for: #KeyPath# ) method to quickly create fields for each of your model's properties. Since this method accepts key paths to the model (indicated by \\. ), Fluent can see what type those properties are. For most common types ( String , Int , Double , etc) Fluent will automatically be able to determine the best database field type to use. You can also choose to manually select which database field type to use for a given field. try builder . field ( for : \\ . name , type : # DataType # ) Each database has it's own unique data types, so refer to your database's documentation for more information. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDataType MySQL MySQL Getting Started MySQLDataType SQLite SQLite Getting Started SQLiteDataType Deleting a Schema Each migration should also include a method for reverting the changes it makes. It is used when you boot your app with the --revert option. For a migration that creates a table in the database, the reversion is quite simple: delete the table. To implement revert for our model, we can use our database's static delete(...) method to indicate that we would like to delete the schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func revert ( on connection : # Database # Connection ) - Future Void { return # Database # Database . delete ( Galaxy . self , on : connection ) } } To delete a schema, you pass a model type and connection as the two required parameters. That's it. You can always choose to skip a reversion by simplying returning conn.future(()) . But note that they are especially useful when testing and debugging your migrations. Add this custom migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () migrations . add ( migration : CreateGalaxy . self , database : . # dbid # ) services . register ( migrations ) Make sure to also set the defaultDatabase property on your model when using a custom migration. Galaxy . defaultDatabase = . # dbid # Updating a Schema After you deploy your application to production, you may find it necessary to add or remove fields on an existing model. You can achieve this by creating a new migration. For this example, let's assume we want to add a new property mass to the Galaxy model from the previous section. import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String var mass : Int } Since our previous migration created a table with fields for both id and name , we need to update that table and add a field for mass . We can do this by using the static update method on Database . import Fluent # Database # struct AddGalaxyMass : # Database # Migration { // ... } Our prepare method will look very similar to the prepare method for a new table, except it will only contain our newly added field. struct AddGalaxyMass : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . mass ) } } } All methods available when creating a schema will be available while updating alongside some new methods for deleting fields. See SchemaUpdater for a list of all available methods. To revert this change, we must delete the mass field from the table. struct AddGalaxyMass : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . deleteField ( for : \\ . mass ) } } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () // ... migrations . add ( migration : AddGalaxyMass . self , database : . # dbid # ) services . register ( migrations ) Migrating Data While migrations are useful for creating and updating schemas in SQL databases, they can also be used for more general purposes in any database. Migrations are passed a connection upon running which can be used to perform arbitrary database queries. For this example, let's assume we want to do a data cleanup migration on our Galaxy model and delete any galaxies with a mass of 0 . The first step is to create our new migration type. struct GalaxyMassCleanup : # Database # Migration { // ... } In the prepare method of this migration, we will perform a query to delete all galaxies which have a mass equal to 0 . struct GalaxyMassCleanup : # Database # Migration { static func prepare ( on conn : # Database # Connection ) - Future Void { return Galaxy . query ( on : conn ). filter ( \\ . mass == 0 ). delete () } // ... } There is no way to undo this migration since it is destructive. You can omit the revert(...) method by returning a pre-completed future. struct GalaxyMassCleanup : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return conn . future (()) } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in configure.swift . var migrations = MigrationConfig () // ... migrations . add ( migration : GalaxyMassCleanup . self , database : . # dbid # ) services . register ( migrations )","title":"Migrations"},{"location":"fluent/migrations/#fluent-migrations","text":"Migrations allow you to make organized, testable, and reliable changes to your database's structure-- even while it's in production. Migrations are often used for preparing a database schema for your models. However, they can also be used to make normal queries to your database. In this guide we will cover creating both types of migrations.","title":"Fluent Migrations"},{"location":"fluent/migrations/#creating-and-deleting-schemas","text":"Let's take a look at how we can use migrations to prepare a schema supporting database to store a theoretical Galaxy model. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String }","title":"Creating and Deleting Schemas"},{"location":"fluent/migrations/#automatic-model-migrations","text":"Models provide a shortcut for declaring database migrations. If you conform a type that conforms to Model to Migration , Fluent can infer the model's properties and automatically implement the prepare(...) and revert(...) methods. import Fluent # Database # extension Galaxy : # Database # Migration { } This method is especially useful for quick prototyping and simple setups. For most other situations you should consider creating a normal, custom migration. Add this automatic migration to your MigrationConfig using the add(model:database:) method. This is done in configure.swift . var migrations = MigrationConfig () migrations . add ( model : Galaxy . self , database : . # dbid # ) services . register ( migrations ) The add(model:database:) method will automatically set the model's defaultDatabase property.","title":"Automatic Model Migrations"},{"location":"fluent/migrations/#custom-migrations","text":"We can customize the table created for our model by creating a migration and using the static create and delete methods on Database . import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... }","title":"Custom Migrations"},{"location":"fluent/migrations/#creating-a-schema","text":"The most important method in a migration is prepare(...) . This is responsible for effecting the migration's changes. For our CreateGalaxy migration, we will use our database's static create method to create a schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . create ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . id , isIdentifier : true ) builder . field ( for : \\ . name ) } } } To create a schema, you must pass a model type and connection as the first two parameters. The third parameter is a closure that accepts the SchemaBuilder . This builder has convenience methods for declaring fields in the schema. You can use the field(for: #KeyPath# ) method to quickly create fields for each of your model's properties. Since this method accepts key paths to the model (indicated by \\. ), Fluent can see what type those properties are. For most common types ( String , Int , Double , etc) Fluent will automatically be able to determine the best database field type to use. You can also choose to manually select which database field type to use for a given field. try builder . field ( for : \\ . name , type : # DataType # ) Each database has it's own unique data types, so refer to your database's documentation for more information. database docs api docs PostgreSQL PostgreSQL Getting Started PostgreSQLDataType MySQL MySQL Getting Started MySQLDataType SQLite SQLite Getting Started SQLiteDataType","title":"Creating a Schema"},{"location":"fluent/migrations/#deleting-a-schema","text":"Each migration should also include a method for reverting the changes it makes. It is used when you boot your app with the --revert option. For a migration that creates a table in the database, the reversion is quite simple: delete the table. To implement revert for our model, we can use our database's static delete(...) method to indicate that we would like to delete the schema. import Fluent # Database # struct CreateGalaxy : # Database # Migration { // ... static func revert ( on connection : # Database # Connection ) - Future Void { return # Database # Database . delete ( Galaxy . self , on : connection ) } } To delete a schema, you pass a model type and connection as the two required parameters. That's it. You can always choose to skip a reversion by simplying returning conn.future(()) . But note that they are especially useful when testing and debugging your migrations. Add this custom migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () migrations . add ( migration : CreateGalaxy . self , database : . # dbid # ) services . register ( migrations ) Make sure to also set the defaultDatabase property on your model when using a custom migration. Galaxy . defaultDatabase = . # dbid #","title":"Deleting a Schema"},{"location":"fluent/migrations/#updating-a-schema","text":"After you deploy your application to production, you may find it necessary to add or remove fields on an existing model. You can achieve this by creating a new migration. For this example, let's assume we want to add a new property mass to the Galaxy model from the previous section. import Fluent # Database # struct Galaxy : # Database # Model { var id : ID ? var name : String var mass : Int } Since our previous migration created a table with fields for both id and name , we need to update that table and add a field for mass . We can do this by using the static update method on Database . import Fluent # Database # struct AddGalaxyMass : # Database # Migration { // ... } Our prepare method will look very similar to the prepare method for a new table, except it will only contain our newly added field. struct AddGalaxyMass : # Database # Migration { // ... static func prepare ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . field ( for : \\ . mass ) } } } All methods available when creating a schema will be available while updating alongside some new methods for deleting fields. See SchemaUpdater for a list of all available methods. To revert this change, we must delete the mass field from the table. struct AddGalaxyMass : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return # Database # Database . update ( Galaxy . self , on : conn ) { builder in builder . deleteField ( for : \\ . mass ) } } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in your configure.swift file. var migrations = MigrationConfig () // ... migrations . add ( migration : AddGalaxyMass . self , database : . # dbid # ) services . register ( migrations )","title":"Updating a Schema"},{"location":"fluent/migrations/#migrating-data","text":"While migrations are useful for creating and updating schemas in SQL databases, they can also be used for more general purposes in any database. Migrations are passed a connection upon running which can be used to perform arbitrary database queries. For this example, let's assume we want to do a data cleanup migration on our Galaxy model and delete any galaxies with a mass of 0 . The first step is to create our new migration type. struct GalaxyMassCleanup : # Database # Migration { // ... } In the prepare method of this migration, we will perform a query to delete all galaxies which have a mass equal to 0 . struct GalaxyMassCleanup : # Database # Migration { static func prepare ( on conn : # Database # Connection ) - Future Void { return Galaxy . query ( on : conn ). filter ( \\ . mass == 0 ). delete () } // ... } There is no way to undo this migration since it is destructive. You can omit the revert(...) method by returning a pre-completed future. struct GalaxyMassCleanup : # Database # Migration { // ... static func revert ( on conn : # Database # Connection ) - Future Void { return conn . future (()) } } Add this migration to your MigrationConfig using the add(migration:database:) method. This is done in configure.swift . var migrations = MigrationConfig () // ... migrations . add ( migration : GalaxyMassCleanup . self , database : . # dbid # ) services . register ( migrations )","title":"Migrating Data"},{"location":"fluent/models/","text":"Fluent Models Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages. Info This guide provides an overview of the Model protocol and its associated methods and properties. If you are just getting started, check out the guide for your database at Fluent Getting Started . Model is a protocol in the Fluent module. It extends the AnyModel protocol which can be used for type-erasure. Conformance Both struct s and class es can conform to Model , however you must pay special attention to Fluent's return types if you use a struct . Since Fluent works asynchronously, any mutations to a value-type ( struct ) model must return a new copy of the model as a future result. Normally, you will conform your model to one of the convenience models available in your database-specific package (i.e., PostgreSQLModel ). However, if you want to customize additional properties, such as the model's idKey , you will want to use the Model protocol itself. Let's take a look at what a basic Model conformance looks like. /// A simple user. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// See `Model.ID` typealias ID = Int /// See `Model.idKey` static let idKey : IDKey = \\ . id /// The unique identifier for this user. var id : Int ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : Int ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } Tip Using final prevents your class from being sub-classed. This makes your life easier. Associated Types Model defines a few associated types that help Fluent create type-safe APIs for you to use. Take a look at AnyModel if you need a type-erased version with no associated types. Database This type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any QueryBuilder s you create with this model. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// ... } It is possible to make this associated type generic by adding a generic type to your class or struct (i.e, User T ). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider. final class User D : Model where D : Database { /// See `Model.Database` typealias Database = D /// ... } You can add further conditions to D , such as QuerySupporting or SchemaSupporting . You can also dynamically extend and conform your generic model using extension User where D: ... { } . That said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver. ID This property defines the type your model will use for its unique identifier. final class User : Model { /// See `Model.ID` typealias ID = UUID /// ... } This will usually be something like Int , UUID , or String although you can theoretically use any type you like. Properties There are several overridable properties on Model that you can use to customize how Fluent interacts with your database. Name This String will be used as a unique identifier for your model whenever Fluent needs one. final class User : Model { /// See `Model.name` static let name = user /// ... } By default, this is the type name of your model. Entity Entity is a generic word used to mean either \"table\" or \"collection\", depending on which type of backend you are using for Fluent. final class Goose : Model { /// See `Model.entity` static let entity = geese /// ... } By default, this property will be name . ID Key The ID key is a writeable key path that points to your model's unique identifier property. Usually this will be a property named id (for some databases it is _id ). However you can theoretically use any key you like. final class User : Model { /// See `Model.ID` typealias ID = String /// See `Model.entity` static let idKey = \\ . username /// The user s unique username var username : String ? /// ... } The idKey property must point to an optional, writeable ( var ) property with type matching ID . Lifecycle There are several lifecycle methods on Model that you can override to hook into Fluent events. method description throwing willCreate Called before Fluent saves your model (for the first time) Cancels the save. didCreate Called after Fluent saves your model (for the first time) Save completes. Query fails. willUpdate Called before Fluent saves your model (subsequent saves) Cancels the save. didUpdate Called after Fluent saves your model (subsequent saves) Save completes. Query fails. willRead Called before Fluent returns your model from a fetch query. Cancels the fetch. willDelete Called before Fluent deletes your model. Cancels the delete. Here's an example of overriding the willUpdate(on:) method. final class User : Model { /// ... /// See `Model.willUpdate(on:)` func willUpdate ( on connection : Database . Connection ) throws - Future Self { /// Throws an error if the username is invalid try validateUsername () /// Return the user. No async work is being done, so we must create a future manually. return Future . map ( on : connection ) { self } } } CRUD The model offers basic CRUD method (create, read, update, delete). Create This method creates a new row / item for an instance of your model in the database. If your model does not have an ID, calls to .save(on:) will redirect to this method. let didCreate = user . create ( on : req ) print ( didCreate ) /// Future User Info If you are using a value-type ( struct ), the instance of your model returned by .create(on:) will contain the model's new ID. Read Two methods are important for reading your model from the database, find(_:on:) and query(on:) . /// Finds a user with ID == 1 let user = User . find ( 1 , on : req ) print ( user ) /// Future User? /// Finds all users with name == Vapor let users = User . query ( on : req ). filter ( \\ . name == Vapor ). all () print ( users ) /// Future [User] Update This method updates the existing row / item associated with an instance of your model in the database. If your model already has an ID, calls to .save(on:) will redirect to this method. /// Updates the user let didUpdate = user . update ( on : req ) print ( didUpdate ) /// Future User Delete This method deletes the existing row / item associated with an instance of your model from the database. /// Deletes the user let didDelete = user . delete ( on : req ) print ( didDelete ) /// Future Void Methods Model offers some convenience methods to make working with it easier. Require ID This method return's the models ID or throws an error. let id = try user . requireID ()","title":"Models"},{"location":"fluent/models/#fluent-models","text":"Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages. Info This guide provides an overview of the Model protocol and its associated methods and properties. If you are just getting started, check out the guide for your database at Fluent Getting Started . Model is a protocol in the Fluent module. It extends the AnyModel protocol which can be used for type-erasure.","title":"Fluent Models"},{"location":"fluent/models/#conformance","text":"Both struct s and class es can conform to Model , however you must pay special attention to Fluent's return types if you use a struct . Since Fluent works asynchronously, any mutations to a value-type ( struct ) model must return a new copy of the model as a future result. Normally, you will conform your model to one of the convenience models available in your database-specific package (i.e., PostgreSQLModel ). However, if you want to customize additional properties, such as the model's idKey , you will want to use the Model protocol itself. Let's take a look at what a basic Model conformance looks like. /// A simple user. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// See `Model.ID` typealias ID = Int /// See `Model.idKey` static let idKey : IDKey = \\ . id /// The unique identifier for this user. var id : Int ? /// The user s full name. var name : String /// The user s current age in years. var age : Int /// Creates a new user. init ( id : Int ? = nil , name : String , age : Int ) { self . id = id self . name = name self . age = age } } Tip Using final prevents your class from being sub-classed. This makes your life easier.","title":"Conformance"},{"location":"fluent/models/#associated-types","text":"Model defines a few associated types that help Fluent create type-safe APIs for you to use. Take a look at AnyModel if you need a type-erased version with no associated types.","title":"Associated Types"},{"location":"fluent/models/#database","text":"This type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any QueryBuilder s you create with this model. final class User : Model { /// See `Model.Database` typealias Database = FooDatabase /// ... } It is possible to make this associated type generic by adding a generic type to your class or struct (i.e, User T ). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider. final class User D : Model where D : Database { /// See `Model.Database` typealias Database = D /// ... } You can add further conditions to D , such as QuerySupporting or SchemaSupporting . You can also dynamically extend and conform your generic model using extension User where D: ... { } . That said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver.","title":"Database"},{"location":"fluent/models/#id","text":"This property defines the type your model will use for its unique identifier. final class User : Model { /// See `Model.ID` typealias ID = UUID /// ... } This will usually be something like Int , UUID , or String although you can theoretically use any type you like.","title":"ID"},{"location":"fluent/models/#properties","text":"There are several overridable properties on Model that you can use to customize how Fluent interacts with your database.","title":"Properties"},{"location":"fluent/models/#name","text":"This String will be used as a unique identifier for your model whenever Fluent needs one. final class User : Model { /// See `Model.name` static let name = user /// ... } By default, this is the type name of your model.","title":"Name"},{"location":"fluent/models/#entity","text":"Entity is a generic word used to mean either \"table\" or \"collection\", depending on which type of backend you are using for Fluent. final class Goose : Model { /// See `Model.entity` static let entity = geese /// ... } By default, this property will be name .","title":"Entity"},{"location":"fluent/models/#id-key","text":"The ID key is a writeable key path that points to your model's unique identifier property. Usually this will be a property named id (for some databases it is _id ). However you can theoretically use any key you like. final class User : Model { /// See `Model.ID` typealias ID = String /// See `Model.entity` static let idKey = \\ . username /// The user s unique username var username : String ? /// ... } The idKey property must point to an optional, writeable ( var ) property with type matching ID .","title":"ID Key"},{"location":"fluent/models/#lifecycle","text":"There are several lifecycle methods on Model that you can override to hook into Fluent events. method description throwing willCreate Called before Fluent saves your model (for the first time) Cancels the save. didCreate Called after Fluent saves your model (for the first time) Save completes. Query fails. willUpdate Called before Fluent saves your model (subsequent saves) Cancels the save. didUpdate Called after Fluent saves your model (subsequent saves) Save completes. Query fails. willRead Called before Fluent returns your model from a fetch query. Cancels the fetch. willDelete Called before Fluent deletes your model. Cancels the delete. Here's an example of overriding the willUpdate(on:) method. final class User : Model { /// ... /// See `Model.willUpdate(on:)` func willUpdate ( on connection : Database . Connection ) throws - Future Self { /// Throws an error if the username is invalid try validateUsername () /// Return the user. No async work is being done, so we must create a future manually. return Future . map ( on : connection ) { self } } }","title":"Lifecycle"},{"location":"fluent/models/#crud","text":"The model offers basic CRUD method (create, read, update, delete).","title":"CRUD"},{"location":"fluent/models/#create","text":"This method creates a new row / item for an instance of your model in the database. If your model does not have an ID, calls to .save(on:) will redirect to this method. let didCreate = user . create ( on : req ) print ( didCreate ) /// Future User Info If you are using a value-type ( struct ), the instance of your model returned by .create(on:) will contain the model's new ID.","title":"Create"},{"location":"fluent/models/#read","text":"Two methods are important for reading your model from the database, find(_:on:) and query(on:) . /// Finds a user with ID == 1 let user = User . find ( 1 , on : req ) print ( user ) /// Future User? /// Finds all users with name == Vapor let users = User . query ( on : req ). filter ( \\ . name == Vapor ). all () print ( users ) /// Future [User]","title":"Read"},{"location":"fluent/models/#update","text":"This method updates the existing row / item associated with an instance of your model in the database. If your model already has an ID, calls to .save(on:) will redirect to this method. /// Updates the user let didUpdate = user . update ( on : req ) print ( didUpdate ) /// Future User","title":"Update"},{"location":"fluent/models/#delete","text":"This method deletes the existing row / item associated with an instance of your model from the database. /// Deletes the user let didDelete = user . delete ( on : req ) print ( didDelete ) /// Future Void","title":"Delete"},{"location":"fluent/models/#methods","text":"Model offers some convenience methods to make working with it easier.","title":"Methods"},{"location":"fluent/models/#require-id","text":"This method return's the models ID or throws an error. let id = try user . requireID ()","title":"Require ID"},{"location":"fluent/querying/","text":"Fluent Queries Once you have a model you can start querying your database to create, read, update, and delete data. Connection The first thing you need to query your database, is a connection to it. Luckily, they are easy to get. Request The easiest way to connect to your database is simply using the incoming Request . This will use the model's defaultDatabase property to automatically fetch a pooled connection to the database. router . get ( galaxies ) { req in return Galaxy . query ( on : req ). all () } You can use convenience methods on a Container to create connections manually. Learn more about that in DatabaseKit Overview Connections . Create One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling create(on:) . router . post ( galaxies ) { req in let galaxy : Galaxy = ... return galaxy . create ( on : req ) } The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values. If your model also conforms to Content you can return the result of the Fluent query directly. Read To read models from the database, you can use query(on:) or find(_:on:) . Find The easiest way to find a single model is by passing its ID to find(_:on:) . Galaxy . find ( 42 , on : conn ) The result will be a future containing an optional value. You can use unwrap(or:) to unwrap the future value or throw an error. Galaxy . find ( 42 , on : conn ). unwrap ( or : Abort (...)) Query You can use the query(on:) method to build database queries with filters, joins, sorts, and more. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way ) Filter The filter(_:) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries. Calls to filter can be chained and even grouped. Galaxy . query ( on : conn ). filter ( \\ . mass = 500 ). filter ( \\ . type == . spiral ) Below is a list of all supported operators. operator type == Equal != Not equal Greater than Less than = Greater than or equal = Less than or equal By default, all chained filters will be used to limit the result set. You can use filter groups to change this behavior. Galaxy . query ( on : conn ). group (. or ) { $0 . filter ( \\ . mass = 250 ). filter ( \\ . mass = 500 ) }. filter ( \\ . type == . spiral ) The above query will include results where the galaxy's mass is below 250 or above 500 and the type is spiral. Range You can apply Swift ranges to a query builder to limit the result set. Galaxy . query ( on : conn ). range (.. 50 ) The above query will include only the first 50 results. For more information on ranges, see docs for Swift's Range type. Sort Query results can be sorted by a given field. Galaxy . query ( on : conn ). sort ( \\ . name , . descending ) You can sort by multiple fields to perform tie breaking behavior where there is duplicate information in the one of the sorted fields. Join Other models can be joined to an existing query in order to further filter the results. Galaxy . query ( on : conn ). join ( \\ Planet . galaxyID , to : \\ Galaxy . id ) . filter ( \\ Planet . name == Earth ) Once a table has been joined using join(_:to:) , you can use fully-qualified key paths to filter results based on data in the joined table. The above query fetches all galaxies that have a planet named Earth. You can even decode the joined models using alsoDecode(...) . Galaxy . query ( on : conn ) // join Planet and filter . alsoDecode ( Planet . self ). all () The above query will decode an array of (Galaxy, Planet) tuples. Fetch To fetch the results of a query, use all() , chunk(max:closure:) , first() or an aggregate method. All The most common method for fetching results is with all() . This will return all matching results according to any fliters applied. Galaxy . query ( on : conn ). all () When combined with range(_:) , you can efficiently limit how many results are returned by the database. Galaxy . query ( on : conn ). range (.. 50 ). all () Chunk For situations where memory conservation is important, use chunk(...) . This method returns the result set in multiple calls of a maximum chunk size. Galaxy . query ( on : conn ). chunk ( max : 32 ) { galaxies in print ( galaxies ) // Array of 32 or less galaxies } First The first() method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way ). first () This method is more efficient than calling all and getting the first item in the array. Update After a model has been fetched from the database and mutated, you can use update(on:) to save the changes. var planet : Planet ... // fetched from database planet . name = Earth planet . update ( on : conn ) Delete After a model has been fetched from the database, you can use delete(on:) to delete it. var planet : Planet ... // fetched from database planet . delete ( on : conn )","title":"Querying"},{"location":"fluent/querying/#fluent-queries","text":"Once you have a model you can start querying your database to create, read, update, and delete data.","title":"Fluent Queries"},{"location":"fluent/querying/#connection","text":"The first thing you need to query your database, is a connection to it. Luckily, they are easy to get.","title":"Connection"},{"location":"fluent/querying/#request","text":"The easiest way to connect to your database is simply using the incoming Request . This will use the model's defaultDatabase property to automatically fetch a pooled connection to the database. router . get ( galaxies ) { req in return Galaxy . query ( on : req ). all () } You can use convenience methods on a Container to create connections manually. Learn more about that in DatabaseKit Overview Connections .","title":"Request"},{"location":"fluent/querying/#create","text":"One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling create(on:) . router . post ( galaxies ) { req in let galaxy : Galaxy = ... return galaxy . create ( on : req ) } The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values. If your model also conforms to Content you can return the result of the Fluent query directly.","title":"Create"},{"location":"fluent/querying/#read","text":"To read models from the database, you can use query(on:) or find(_:on:) .","title":"Read"},{"location":"fluent/querying/#find","text":"The easiest way to find a single model is by passing its ID to find(_:on:) . Galaxy . find ( 42 , on : conn ) The result will be a future containing an optional value. You can use unwrap(or:) to unwrap the future value or throw an error. Galaxy . find ( 42 , on : conn ). unwrap ( or : Abort (...))","title":"Find"},{"location":"fluent/querying/#query","text":"You can use the query(on:) method to build database queries with filters, joins, sorts, and more. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way )","title":"Query"},{"location":"fluent/querying/#filter","text":"The filter(_:) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries. Calls to filter can be chained and even grouped. Galaxy . query ( on : conn ). filter ( \\ . mass = 500 ). filter ( \\ . type == . spiral ) Below is a list of all supported operators. operator type == Equal != Not equal Greater than Less than = Greater than or equal = Less than or equal By default, all chained filters will be used to limit the result set. You can use filter groups to change this behavior. Galaxy . query ( on : conn ). group (. or ) { $0 . filter ( \\ . mass = 250 ). filter ( \\ . mass = 500 ) }. filter ( \\ . type == . spiral ) The above query will include results where the galaxy's mass is below 250 or above 500 and the type is spiral.","title":"Filter"},{"location":"fluent/querying/#range","text":"You can apply Swift ranges to a query builder to limit the result set. Galaxy . query ( on : conn ). range (.. 50 ) The above query will include only the first 50 results. For more information on ranges, see docs for Swift's Range type.","title":"Range"},{"location":"fluent/querying/#sort","text":"Query results can be sorted by a given field. Galaxy . query ( on : conn ). sort ( \\ . name , . descending ) You can sort by multiple fields to perform tie breaking behavior where there is duplicate information in the one of the sorted fields.","title":"Sort"},{"location":"fluent/querying/#join","text":"Other models can be joined to an existing query in order to further filter the results. Galaxy . query ( on : conn ). join ( \\ Planet . galaxyID , to : \\ Galaxy . id ) . filter ( \\ Planet . name == Earth ) Once a table has been joined using join(_:to:) , you can use fully-qualified key paths to filter results based on data in the joined table. The above query fetches all galaxies that have a planet named Earth. You can even decode the joined models using alsoDecode(...) . Galaxy . query ( on : conn ) // join Planet and filter . alsoDecode ( Planet . self ). all () The above query will decode an array of (Galaxy, Planet) tuples.","title":"Join"},{"location":"fluent/querying/#fetch","text":"To fetch the results of a query, use all() , chunk(max:closure:) , first() or an aggregate method.","title":"Fetch"},{"location":"fluent/querying/#all","text":"The most common method for fetching results is with all() . This will return all matching results according to any fliters applied. Galaxy . query ( on : conn ). all () When combined with range(_:) , you can efficiently limit how many results are returned by the database. Galaxy . query ( on : conn ). range (.. 50 ). all ()","title":"All"},{"location":"fluent/querying/#chunk","text":"For situations where memory conservation is important, use chunk(...) . This method returns the result set in multiple calls of a maximum chunk size. Galaxy . query ( on : conn ). chunk ( max : 32 ) { galaxies in print ( galaxies ) // Array of 32 or less galaxies }","title":"Chunk"},{"location":"fluent/querying/#first","text":"The first() method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data. Galaxy . query ( on : conn ). filter ( \\ . name == Milky Way ). first () This method is more efficient than calling all and getting the first item in the array.","title":"First"},{"location":"fluent/querying/#update","text":"After a model has been fetched from the database and mutated, you can use update(on:) to save the changes. var planet : Planet ... // fetched from database planet . name = Earth planet . update ( on : conn )","title":"Update"},{"location":"fluent/querying/#delete","text":"After a model has been fetched from the database, you can use delete(on:) to delete it. var planet : Planet ... // fetched from database planet . delete ( on : conn )","title":"Delete"},{"location":"fluent/relations/","text":"Fluent Relations Fluent supports two methods for relating models: one-to-many (parent-child) and many-to-many (siblings). These relations help make working with a normalized data structure easy. Parent-Child The most common model relation is the one-to-many or parent-child relation. In this relation, each child model stores at most one identifier of a parent model. In most cases, multiple child models can store the same parent identifier at the same time. This means that any given parent can have zero or more related child models. Hence the name, one (parent) to many (children). Note If each child must store a unique parent ID, this relation is called a one-to-one relation. Take a look at the following diagram in which an example parent-child relation between two models ( Galaxy and Planet ) is shown. In the example above, Galaxy is the parent and Planet is the child. Planets store an identifier referencing exactly one galaxy (the galaxy they are in). In turn, each galaxy has zero or more planets that belong to it. Let's take a look at what these models would look like in Fluent. struct Galaxy : Model { // ... var id : Int ? var name : String } struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } For more information on defining models see Fluent Models . Fluent provides two helpers for working with parent-child relations: Parent and Children . These helpers can be created using extensions on the related models for convenient access. extension Galaxy { // this galaxy s related planets var planets : Children Galaxy , Planet { return children ( \\ . galaxyID ) } } Here the children(_:) method is used on Galaxy to create the relation. The resulting type has two generic arguments in the signature that can be thought of as From, To . Since this relation goes from galaxy to planet, they are ordered as such in the generic arguments. Note that this method is not static. That is because it must access the galaxy's identifier to perform the relation lookup. extension Planet { // this planet s related galaxy var galaxy : Parent Planet , Galaxy { return parent ( \\ . galaxyID ) } } Here the parent(_:) method is used on Planet to create the inverse relation. The resulting type also has two generic arguments. In this case, they are reversed since this relation now goes from planet to galaxy. Note that this method is also not static. That is because it must access the referenced identifier to perform the relation lookup. Now that the models and relation properties are created, they can be used to create, read, update, and delete related data. let galaxy : Galaxy = ... let planets = galaxy . planets . query ( on : ...). all () The query(on:) method on a relation creates an instance of QueryBuilder filtered to the related models. See Fluent Querying for more information on working with the query builder. let planet : Planet = ... let galaxy = planet . galaxy . get ( on : ...) Since the child can have at most one parent, the most useful method is [ get(on:) ] which simply returns the parent model. Siblings A more powerful (and complex) relation is the many-to-many or siblings relation. In this relation, two models are related by a third model called a pivot . The pivot is a simple model that carries one identifier for each of the two related models. Because a third model (the pivot) stores identifiers, each model can be related to zero or more models on the other side of the relation. Take a look at the following diagram in which an example siblings relation between two models ( Planet and Tag ) and a pivot ( PlanetTag ) is shown. A siblings relation is required for the above example because: Both Earth and Venus have the Earth Sized tag. Earth has both the Earth Sized and Liquid Water tag. In other words, two planets can share one tag and two tags can share one planet. This is a many-to-many relation. Let's take a look at what these models would look like in Fluent. struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } struct Tag : Model { // ... var id : Int ? var name : String } For more information on defining models see Fluent Models . Now let's take a look at the pivot. It may seem a bit intimidating at first, but it's really quite simple. struct PlanetTag : Pivot { // ... typealias Left = Planet typealias Right = Tag static var leftIDKey : LeftIDKey = \\ . planetID static var rightIDKey : RightIDKey = \\ . tagID var id : Int ? var planetID : Int var tagID : Int } A pivot must have Left and Right model types. In this case, those model types are Planet and Tag . Although it is arbitrary which model is left vs. right, a good rule of thumb is to order things alphabetically for consistency. Once the left and right models are defined, we must supply Fluent with key paths to the stored properties for each ID. We can use the LeftIDKey and RightIDKey type-aliases to do this. A Pivot is also a Model itself. You are free to store any additional properties here if you like. Don't forget to create a migration for it if you are using a database that supports schemas. Once the pivot and your models are created, you can add convenience extensions for interacting with the relation just like the parent-child relation. extension Planet { // this planet s related tags var tags : Siblings Planet , Tag , PlanetTag { return siblings () } } Because the siblings relation requires three models, it has three generic arguments. You can think of the arguments as From, To, Through . This relation goes from a planet to tags through the planet tag pivot. The other side of the relation (on tag) is similar. Only the first two generic arguments are flipped. extension Tag { // all planets that have this tag var planets : Siblings Tag , Planet , PlanetTag { return siblings () } } Now that the relations are setup, we can query a planet's tags. This works just like the Children type in the parent-child relationship. let planet : Planet = ... planet . tags . query ( on : ...). all () Modifiable Pivot If the pivot conforms to ModifiablePivot , then Fluent can help to create and delete pivots (called attaching and detaching). Conforming a pivot is fairly simple. Fluent just needs to be able to initialize the pivot from two related models. extension PlanetTag : ModifiablePivot { init ( _ planet : Planet , _ tag : Tag ) throws { planetID = try planet . requireID () tagID = try tag . requireID () } } Once the pivot type conforms, there will be extra methods available on the siblings relation. let planet : Planet = ... let tag : Tag = ... planet . tags . attach ( tag , on : ...)","title":"Relations"},{"location":"fluent/relations/#fluent-relations","text":"Fluent supports two methods for relating models: one-to-many (parent-child) and many-to-many (siblings). These relations help make working with a normalized data structure easy.","title":"Fluent Relations"},{"location":"fluent/relations/#parent-child","text":"The most common model relation is the one-to-many or parent-child relation. In this relation, each child model stores at most one identifier of a parent model. In most cases, multiple child models can store the same parent identifier at the same time. This means that any given parent can have zero or more related child models. Hence the name, one (parent) to many (children). Note If each child must store a unique parent ID, this relation is called a one-to-one relation. Take a look at the following diagram in which an example parent-child relation between two models ( Galaxy and Planet ) is shown. In the example above, Galaxy is the parent and Planet is the child. Planets store an identifier referencing exactly one galaxy (the galaxy they are in). In turn, each galaxy has zero or more planets that belong to it. Let's take a look at what these models would look like in Fluent. struct Galaxy : Model { // ... var id : Int ? var name : String } struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } For more information on defining models see Fluent Models . Fluent provides two helpers for working with parent-child relations: Parent and Children . These helpers can be created using extensions on the related models for convenient access. extension Galaxy { // this galaxy s related planets var planets : Children Galaxy , Planet { return children ( \\ . galaxyID ) } } Here the children(_:) method is used on Galaxy to create the relation. The resulting type has two generic arguments in the signature that can be thought of as From, To . Since this relation goes from galaxy to planet, they are ordered as such in the generic arguments. Note that this method is not static. That is because it must access the galaxy's identifier to perform the relation lookup. extension Planet { // this planet s related galaxy var galaxy : Parent Planet , Galaxy { return parent ( \\ . galaxyID ) } } Here the parent(_:) method is used on Planet to create the inverse relation. The resulting type also has two generic arguments. In this case, they are reversed since this relation now goes from planet to galaxy. Note that this method is also not static. That is because it must access the referenced identifier to perform the relation lookup. Now that the models and relation properties are created, they can be used to create, read, update, and delete related data. let galaxy : Galaxy = ... let planets = galaxy . planets . query ( on : ...). all () The query(on:) method on a relation creates an instance of QueryBuilder filtered to the related models. See Fluent Querying for more information on working with the query builder. let planet : Planet = ... let galaxy = planet . galaxy . get ( on : ...) Since the child can have at most one parent, the most useful method is [ get(on:) ] which simply returns the parent model.","title":"Parent-Child"},{"location":"fluent/relations/#siblings","text":"A more powerful (and complex) relation is the many-to-many or siblings relation. In this relation, two models are related by a third model called a pivot . The pivot is a simple model that carries one identifier for each of the two related models. Because a third model (the pivot) stores identifiers, each model can be related to zero or more models on the other side of the relation. Take a look at the following diagram in which an example siblings relation between two models ( Planet and Tag ) and a pivot ( PlanetTag ) is shown. A siblings relation is required for the above example because: Both Earth and Venus have the Earth Sized tag. Earth has both the Earth Sized and Liquid Water tag. In other words, two planets can share one tag and two tags can share one planet. This is a many-to-many relation. Let's take a look at what these models would look like in Fluent. struct Planet : Model { // ... var id : Int ? var name : String var galaxyID : Int } struct Tag : Model { // ... var id : Int ? var name : String } For more information on defining models see Fluent Models . Now let's take a look at the pivot. It may seem a bit intimidating at first, but it's really quite simple. struct PlanetTag : Pivot { // ... typealias Left = Planet typealias Right = Tag static var leftIDKey : LeftIDKey = \\ . planetID static var rightIDKey : RightIDKey = \\ . tagID var id : Int ? var planetID : Int var tagID : Int } A pivot must have Left and Right model types. In this case, those model types are Planet and Tag . Although it is arbitrary which model is left vs. right, a good rule of thumb is to order things alphabetically for consistency. Once the left and right models are defined, we must supply Fluent with key paths to the stored properties for each ID. We can use the LeftIDKey and RightIDKey type-aliases to do this. A Pivot is also a Model itself. You are free to store any additional properties here if you like. Don't forget to create a migration for it if you are using a database that supports schemas. Once the pivot and your models are created, you can add convenience extensions for interacting with the relation just like the parent-child relation. extension Planet { // this planet s related tags var tags : Siblings Planet , Tag , PlanetTag { return siblings () } } Because the siblings relation requires three models, it has three generic arguments. You can think of the arguments as From, To, Through . This relation goes from a planet to tags through the planet tag pivot. The other side of the relation (on tag) is similar. Only the first two generic arguments are flipped. extension Tag { // all planets that have this tag var planets : Siblings Tag , Planet , PlanetTag { return siblings () } } Now that the relations are setup, we can query a planet's tags. This works just like the Children type in the parent-child relationship. let planet : Planet = ... planet . tags . query ( on : ...). all ()","title":"Siblings"},{"location":"fluent/relations/#modifiable-pivot","text":"If the pivot conforms to ModifiablePivot , then Fluent can help to create and delete pivots (called attaching and detaching). Conforming a pivot is fairly simple. Fluent just needs to be able to initialize the pivot from two related models. extension PlanetTag : ModifiablePivot { init ( _ planet : Planet , _ tag : Tag ) throws { planetID = try planet . requireID () tagID = try tag . requireID () } } Once the pivot type conforms, there will be extra methods available on the siblings relation. let planet : Planet = ... let tag : Tag = ... planet . tags . attach ( tag , on : ...)","title":"Modifiable Pivot"},{"location":"fluent/transaction/","text":"Fluent Transactions Transactions allow you to ensure multiple operations complete succesfully before saving data to your database. Once a transaction is started, you may run Fluent queries normally. However, no data will be saved to the database until the transaction completes. If an error is thrown at any point during the transaction (by you or the database), none of the changes will take effect. To perform a transaction, you need access to something that can connect to the database. This is usually an incoming HTTP request. Use the transaction(on:_:) method. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . req . transaction ( on : . # dbid # ) { conn in // use conn as your connection } Once inside the transaction closure, you must use the supplied connection (named conn in the example) to perform queries. The closure expects a generic future return value. Once this future completes succesfully, the transaction will be committed. var userA : User = ... var userB : User = ... return req . transaction ( on : . # dbid # ) { conn in return userA . save ( on : conn ). flatMap { _ in return userB . save ( on : conn ) }. transform ( to : HTTPStatus . ok ) } The above example will save User A then User B before completing the transaction. If either user fails to save, neither will save. Once the transaction has completed, the result is transformed to a simple HTTP status response indicating completion.","title":"Transaction"},{"location":"fluent/transaction/#fluent-transactions","text":"Transactions allow you to ensure multiple operations complete succesfully before saving data to your database. Once a transaction is started, you may run Fluent queries normally. However, no data will be saved to the database until the transaction completes. If an error is thrown at any point during the transaction (by you or the database), none of the changes will take effect. To perform a transaction, you need access to something that can connect to the database. This is usually an incoming HTTP request. Use the transaction(on:_:) method. Fill in the Xcode placeholders below with your database's name from Getting Started Choosing a Driver . req . transaction ( on : . # dbid # ) { conn in // use conn as your connection } Once inside the transaction closure, you must use the supplied connection (named conn in the example) to perform queries. The closure expects a generic future return value. Once this future completes succesfully, the transaction will be committed. var userA : User = ... var userB : User = ... return req . transaction ( on : . # dbid # ) { conn in return userA . save ( on : conn ). flatMap { _ in return userB . save ( on : conn ) }. transform ( to : HTTPStatus . ok ) } The above example will save User A then User B before completing the transaction. If either user fails to save, neither will save. Once the transaction has completed, the result is transformed to a simple HTTP status response indicating completion.","title":"Fluent Transactions"},{"location":"getting-started/application/","text":"Application Every Vapor project has an Application . You use the application to run your server and create any services you might need at boot time. The best place to access the application is in your project's boot.swift file. import Vapor public func boot ( _ app : Application ) throws { // your code here } Unlike some other web frameworks, Vapor doesn't support statically accessing the application. If you need to access it from another class or struct, you should pass through a method or initializer. Info Avoiding static access to variables helps make Vapor performant by preventing the need for thread-safe locks or semaphores. Services The application's main function is to boot your server. try app . run () However, the application is also a container. You may use it to create services required to boot your application. Warning Do not use the application, or any services created from it, inside a route closure. Use the Request to create services instead. let client = try app . make ( Client . self ) let res = try client . get ( http://vapor.codes ). wait () print ( res ) // Response Tip It's okay to use .wait() here instead of .map / .flatMap because we are not inside of a route closure. Learn more about services in Getting Started Services .","title":"Application"},{"location":"getting-started/application/#application","text":"Every Vapor project has an Application . You use the application to run your server and create any services you might need at boot time. The best place to access the application is in your project's boot.swift file. import Vapor public func boot ( _ app : Application ) throws { // your code here } Unlike some other web frameworks, Vapor doesn't support statically accessing the application. If you need to access it from another class or struct, you should pass through a method or initializer. Info Avoiding static access to variables helps make Vapor performant by preventing the need for thread-safe locks or semaphores.","title":"Application"},{"location":"getting-started/application/#services","text":"The application's main function is to boot your server. try app . run () However, the application is also a container. You may use it to create services required to boot your application. Warning Do not use the application, or any services created from it, inside a route closure. Use the Request to create services instead. let client = try app . make ( Client . self ) let res = try client . get ( http://vapor.codes ). wait () print ( res ) // Response Tip It's okay to use .wait() here instead of .map / .flatMap because we are not inside of a route closure. Learn more about services in Getting Started Services .","title":"Services"},{"location":"getting-started/async/","text":"Async You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. This guide will give you a quick introduction to working with Async. Check out Async \u2192 Overview for more information. Futures Since Future s work asynchronously, we must use closures to interact with and transform their values. Just like optionals in Swift, futures can be mapped and flat-mapped. Map The .map(to:_:) method allows you to transform the future's value to another value. The closure provided will be called once the Future 's data becomes available. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int Flat Map The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes! Chaining The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown. Worker You may see methods in Vapor that have an on: Worker parameter. These are usually methods that perform asynchronous work and require access to the EventLoop . The most common Worker s you will interact with in Vapor are: Application Request Response /// Assume we have a Request and some ViewRenderer let req : Request = ... let view : ViewRenderer = ... /// Render the view, using the Request as a worker. /// This ensures the async work happens on the correct event loop. /// /// This assumes the signature is: /// func render(_: String, on: Worker) view . render ( home.html , on : req )","title":"Async"},{"location":"getting-started/async/#async","text":"You may have noticed some APIs in Vapor expect or return a generic Future type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use. This guide will give you a quick introduction to working with Async. Check out Async \u2192 Overview for more information.","title":"Async"},{"location":"getting-started/async/#futures","text":"Since Future s work asynchronously, we must use closures to interact with and transform their values. Just like optionals in Swift, futures can be mapped and flat-mapped.","title":"Futures"},{"location":"getting-started/async/#map","text":"The .map(to:_:) method allows you to transform the future's value to another value. The closure provided will be called once the Future 's data becomes available. /// Assume we get a future string back from some API let futureString : Future String = ... /// Map the future string to an integer let futureInt = futureString . map ( to : Int . self ) { string in print ( string ) // The actual String return Int ( string ) ?? 0 } /// We now have a future integer print ( futureInt ) // Future Int","title":"Map"},{"location":"getting-started/async/#flat-map","text":"The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes!","title":"Flat Map"},{"location":"getting-started/async/#chaining","text":"The great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily. Let's modify the examples from above to see how we can take advantage of chaining. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Transform the string to a url, then to a response let futureResponse = futureString . map ( to : URL . self ) { string in guard let url = URL ( string : string ) else { throw Abort (. badRequest , reason : Invalid URL string: \\( string ) ) } return url }. flatMap ( to : Response . self ) { url in return client . get ( url ) } print ( futureResponse ) // Future Response After the initial call to map, there is a temporary Future URL created. This future is then immediately flat-mapped to a Future Response Tip You can throw errors inside of map and flat-map closures. This will result in the future failing with the error thrown.","title":"Chaining"},{"location":"getting-started/async/#worker","text":"You may see methods in Vapor that have an on: Worker parameter. These are usually methods that perform asynchronous work and require access to the EventLoop . The most common Worker s you will interact with in Vapor are: Application Request Response /// Assume we have a Request and some ViewRenderer let req : Request = ... let view : ViewRenderer = ... /// Render the view, using the Request as a worker. /// This ensures the async work happens on the correct event loop. /// /// This assumes the signature is: /// func render(_: String, on: Worker) view . render ( home.html , on : req )","title":"Worker"},{"location":"getting-started/cache/","text":"TODO","title":"Cache"},{"location":"getting-started/cloud/","text":"Deployment Deploying code is the process of making your Vapor project publically available. It can be one of the most difficult aspects of web development. Fortunately, there are services to help. Vapor Cloud The best way to deploy your application is through Vapor Cloud. It's a cloud platform built specifically for the Vapor web framework. This means it's incredibly easy to deploy your project quickly and be confident that it will be fast and stable. Deploying your project to Vapor Cloud is simple, it's built right into the Vapor Toolbox . Just run this command from within the root directory of your project. vapor cloud deploy For a detailed guide, visit Vapor Cloud Quick Start . Other Options Vapor can be deployed anywhere that supports Ubuntu (basically everywhere). Guides on deploying to other systems are coming soon (contributions welcome)!","title":"Deployment"},{"location":"getting-started/cloud/#deployment","text":"Deploying code is the process of making your Vapor project publically available. It can be one of the most difficult aspects of web development. Fortunately, there are services to help.","title":"Deployment"},{"location":"getting-started/cloud/#vapor-cloud","text":"The best way to deploy your application is through Vapor Cloud. It's a cloud platform built specifically for the Vapor web framework. This means it's incredibly easy to deploy your project quickly and be confident that it will be fast and stable. Deploying your project to Vapor Cloud is simple, it's built right into the Vapor Toolbox . Just run this command from within the root directory of your project. vapor cloud deploy For a detailed guide, visit Vapor Cloud Quick Start .","title":"Vapor Cloud"},{"location":"getting-started/cloud/#other-options","text":"Vapor can be deployed anywhere that supports Ubuntu (basically everywhere). Guides on deploying to other systems are coming soon (contributions welcome)!","title":"Other Options"},{"location":"getting-started/content/","text":"Content In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use JSON as an example. But keep in mind the API is the same for any supported content type. Request Let's take a look at how you would parse the following HTTP request. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Then simply conform this struct or class to Content . Now we are ready to decode that HTTP request. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map ( to : HTTPStatus . self ) { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return . ok } } We use .map(to:) here since req.content.decode(_:) returns a future . Response Let's take a look at how you would create the following HTTP response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content . Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } Great job! Now you know how to encode and decode data in Vapor. Tip See Vapor Content for more in-depth information. The next section in this guide is Async .","title":"Content"},{"location":"getting-started/content/#content","text":"In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use JSON as an example. But keep in mind the API is the same for any supported content type.","title":"Content"},{"location":"getting-started/content/#request","text":"Let's take a look at how you would parse the following HTTP request. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Then simply conform this struct or class to Content . Now we are ready to decode that HTTP request. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map ( to : HTTPStatus . self ) { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return . ok } } We use .map(to:) here since req.content.decode(_:) returns a future .","title":"Request"},{"location":"getting-started/content/#response","text":"Let's take a look at how you would create the following HTTP response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content . Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } Great job! Now you know how to encode and decode data in Vapor. Tip See Vapor Content for more in-depth information. The next section in this guide is Async .","title":"Response"},{"location":"getting-started/controllers/","text":"Controllers Controllers are a great way to organize your code. They are collections of methods that accept a request and return a response. A good place to put your controllers is in the Controllers folder. Methods Let's take a look at an example controller. import Vapor final class HelloController { func greet ( _ req : Request ) throws - String { return Hello! } } Controller methods should always accept a Request and return something ResponseEncodable . Note Futures whose expectations are ResponseEncodable (i.e, Future String ) are also ResponseEncodable . To use this controller, we can simply initialize it, then pass the method to a router. let helloController = HelloController () router . get ( greet , use : helloController . greet ) Using Services You will probably want to access your services from within your controllers. Just use the Request as a container to create services from within your route closures. Vapor will take care of caching the services. final class HelloController { func greet ( _ req : Request ) throws - String { return try req . make ( BCryptHasher . self ). hash ( hello ) } }","title":"Controllers"},{"location":"getting-started/controllers/#controllers","text":"Controllers are a great way to organize your code. They are collections of methods that accept a request and return a response. A good place to put your controllers is in the Controllers folder.","title":"Controllers"},{"location":"getting-started/controllers/#methods","text":"Let's take a look at an example controller. import Vapor final class HelloController { func greet ( _ req : Request ) throws - String { return Hello! } } Controller methods should always accept a Request and return something ResponseEncodable . Note Futures whose expectations are ResponseEncodable (i.e, Future String ) are also ResponseEncodable . To use this controller, we can simply initialize it, then pass the method to a router. let helloController = HelloController () router . get ( greet , use : helloController . greet )","title":"Methods"},{"location":"getting-started/controllers/#using-services","text":"You will probably want to access your services from within your controllers. Just use the Request as a container to create services from within your route closures. Vapor will take care of caching the services. final class HelloController { func greet ( _ req : Request ) throws - String { return try req . make ( BCryptHasher . self ). hash ( hello ) } }","title":"Using Services"},{"location":"getting-started/databases/","text":"Databases Databases are an important choice for many applications. They come in many flavours for many different use cases. This article covers the four most popular databases used by our users. Database terminology Databases are a data management system. They allow storing data such as users, articles, relations (such as friends) and any other data structures. Databases allow querying and managing (large) data sets efficiently. Queries are a request for (mutation of) information. The most popular query language is SQL, a simple, string based and easily readable query language. NoSQL databases are databases which do not query using the SQL syntax. They often also serve a more specific use case. MongoDB MongoDB is the only database in this list that is not an SQL database (or NoSQL). It is designed for extremely large datasets, often with a complex structure. MongoDB supports recursive structures, unlike SQL databases which are one-dimensional. MongoDB's advantages lie in its architectural difference. It's more easily integrated in data models and more scalable. The downsides of MongoDB are that the familiar SQL syntax and some table joins are not supported. MongoDB is also a fairly new player, so although it has become very stable and mature it is not as battle tested over the years compared to MySQL. MongoDB does not support auto incremented integers. MySQL MySQL is one of the oldest and most robust databases in this list. Its old age has proven the database to be stable and trustworthy. It is an SQL database, meaning its queries are standardized, widely used, familiar and supported. This makes it extremely attractive to established businesses running SQL. MySQL documentation can be found here. SQLite SQLite is a database that is designed for small applications. It is extremely easy to use in that it only requires a filesystem. It must not be used on cloud services such as Vapor cloud or heroku as those don't persist the SQLite file. SQLite is very limited in its supported datatypes and should only be used for the most basic applications that should be developed in little time. SQLite databases aren't scalable across multiple servers. Using SQLite is described more thoroughly here.","title":"Databases"},{"location":"getting-started/databases/#databases","text":"Databases are an important choice for many applications. They come in many flavours for many different use cases. This article covers the four most popular databases used by our users.","title":"Databases"},{"location":"getting-started/databases/#database-terminology","text":"Databases are a data management system. They allow storing data such as users, articles, relations (such as friends) and any other data structures. Databases allow querying and managing (large) data sets efficiently. Queries are a request for (mutation of) information. The most popular query language is SQL, a simple, string based and easily readable query language. NoSQL databases are databases which do not query using the SQL syntax. They often also serve a more specific use case.","title":"Database terminology"},{"location":"getting-started/databases/#mongodb","text":"MongoDB is the only database in this list that is not an SQL database (or NoSQL). It is designed for extremely large datasets, often with a complex structure. MongoDB supports recursive structures, unlike SQL databases which are one-dimensional. MongoDB's advantages lie in its architectural difference. It's more easily integrated in data models and more scalable. The downsides of MongoDB are that the familiar SQL syntax and some table joins are not supported. MongoDB is also a fairly new player, so although it has become very stable and mature it is not as battle tested over the years compared to MySQL. MongoDB does not support auto incremented integers.","title":"MongoDB"},{"location":"getting-started/databases/#mysql","text":"MySQL is one of the oldest and most robust databases in this list. Its old age has proven the database to be stable and trustworthy. It is an SQL database, meaning its queries are standardized, widely used, familiar and supported. This makes it extremely attractive to established businesses running SQL. MySQL documentation can be found here.","title":"MySQL"},{"location":"getting-started/databases/#sqlite","text":"SQLite is a database that is designed for small applications. It is extremely easy to use in that it only requires a filesystem. It must not be used on cloud services such as Vapor cloud or heroku as those don't persist the SQLite file. SQLite is very limited in its supported datatypes and should only be used for the most basic applications that should be developed in little time. SQLite databases aren't scalable across multiple servers. Using SQLite is described more thoroughly here.","title":"SQLite"},{"location":"getting-started/hello-world/","text":"Hello, world Now that you've installed Vapor, let's create your first Vapor app! This guide will take you step by step through creating a new project, building, and running it. New Project The first step is to create a new Vapor project on your computer. For this guide, we will call the project Hello . Open up your terminal, and use Vapor Toolbox's new command. vapor new Hello Once that finishes, change into the newly created directory. cd Hello Generate Xcode Project Let's now use the Vapor Toolbox's xcode command to generate an Xcode project. This will allow us to build and run our app from inside of Xcode, just like an iOS app. vapor xcode The toolbox will ask you if you'd like to open Xcode automatically, select yes . Build Run You should now have Xcode open and running. Select the run scheme from the scheme menu and My Mac as the deployment target, then click the play button. You should see the terminal pop up at the bottom of the screen. Server starting on http://localhost:8080 Visit Localhost Open your web browser, and visit localhost:8080/hello You should see the following page. Hello, world! Congratulations on creating, building, and running your first Vapor app! \ud83c\udf89","title":"Hello, world"},{"location":"getting-started/hello-world/#hello-world","text":"Now that you've installed Vapor, let's create your first Vapor app! This guide will take you step by step through creating a new project, building, and running it.","title":"Hello, world"},{"location":"getting-started/hello-world/#new-project","text":"The first step is to create a new Vapor project on your computer. For this guide, we will call the project Hello . Open up your terminal, and use Vapor Toolbox's new command. vapor new Hello Once that finishes, change into the newly created directory. cd Hello","title":"New Project"},{"location":"getting-started/hello-world/#generate-xcode-project","text":"Let's now use the Vapor Toolbox's xcode command to generate an Xcode project. This will allow us to build and run our app from inside of Xcode, just like an iOS app. vapor xcode The toolbox will ask you if you'd like to open Xcode automatically, select yes .","title":"Generate Xcode Project"},{"location":"getting-started/hello-world/#build-run","text":"You should now have Xcode open and running. Select the run scheme from the scheme menu and My Mac as the deployment target, then click the play button. You should see the terminal pop up at the bottom of the screen. Server starting on http://localhost:8080","title":"Build & Run"},{"location":"getting-started/hello-world/#visit-localhost","text":"Open your web browser, and visit localhost:8080/hello You should see the following page. Hello, world! Congratulations on creating, building, and running your first Vapor app! \ud83c\udf89","title":"Visit Localhost"},{"location":"getting-started/routing/","text":"Routing Routing is the process of finding the appropriate response to an incoming request. Making a Router In Vapor the default Router is the EngineRouter . You can implement custom routers by implementing one conforming to the Router protocol. let router = try EngineRouter . default () This is usually done in your configure.swift file. Registering a route Imagine you want to return a list of users when someone visits GET /users . Leaving authorization aside, that would look something like this. router . get ( users ) { req in return // fetch the users } In Vapor, routing is usually done using the .get , .put , .post , .patch and .delete shorthands. You can supply the path as / or comma-separated strings. We recommend comma separated, as it's more readable. router . get ( path , to , something ) { ... } Routes The best place to add routes is in the routes.swift file. Use the router supplied as a parameter to this function to register your routes. import Vapor public func routes ( _ router : Router ) throws { // Basic Hello, world! example router . get ( hello ) { req in return Hello, world! } /// ... } See Getting Started Content for more information about what can be returned in a route closure. Parameters Sometimes you may want one of the components of your route path to be dynamic. This is often used when you want to get an item with a supplied identifier, e.g., GET /users/:id router . get ( users , Int . parameter ) { req - String in let id = try req . parameters . next ( Int . self ) return requested id # \\( id ) } Instead of passing a string, pass the type of parameter you expect. In this case, our User has an Int ID. Tip You can define your own custom parameter types as well. After registering your routes After registering your routes you must register the Router as a Getting Started Services","title":"Routing"},{"location":"getting-started/routing/#routing","text":"Routing is the process of finding the appropriate response to an incoming request.","title":"Routing"},{"location":"getting-started/routing/#making-a-router","text":"In Vapor the default Router is the EngineRouter . You can implement custom routers by implementing one conforming to the Router protocol. let router = try EngineRouter . default () This is usually done in your configure.swift file.","title":"Making a Router"},{"location":"getting-started/routing/#registering-a-route","text":"Imagine you want to return a list of users when someone visits GET /users . Leaving authorization aside, that would look something like this. router . get ( users ) { req in return // fetch the users } In Vapor, routing is usually done using the .get , .put , .post , .patch and .delete shorthands. You can supply the path as / or comma-separated strings. We recommend comma separated, as it's more readable. router . get ( path , to , something ) { ... }","title":"Registering a route"},{"location":"getting-started/routing/#routes","text":"The best place to add routes is in the routes.swift file. Use the router supplied as a parameter to this function to register your routes. import Vapor public func routes ( _ router : Router ) throws { // Basic Hello, world! example router . get ( hello ) { req in return Hello, world! } /// ... } See Getting Started Content for more information about what can be returned in a route closure.","title":"Routes"},{"location":"getting-started/routing/#parameters","text":"Sometimes you may want one of the components of your route path to be dynamic. This is often used when you want to get an item with a supplied identifier, e.g., GET /users/:id router . get ( users , Int . parameter ) { req - String in let id = try req . parameters . next ( Int . self ) return requested id # \\( id ) } Instead of passing a string, pass the type of parameter you expect. In this case, our User has an Int ID. Tip You can define your own custom parameter types as well.","title":"Parameters"},{"location":"getting-started/routing/#after-registering-your-routes","text":"After registering your routes you must register the Router as a Getting Started Services","title":"After registering your routes"},{"location":"getting-started/services/","text":"Services Services is a dependency injection (also called inversion of control) framework for Vapor. The services framework allows you to register, configure, and initialize anything you might need in your application. Container Most of your interaction with services will happen through a container. A container is a combination of the following: Services : A collection of registered services. Config : Declared preferences for certain services over others. Environment : The application's current environment type (testing, production, etc) Worker : The event loop associated with this container. The most common containers you will interact with in Vapor are: Application Request Response You should use the Application as a container to create services required for booting your app. You should use the Request or Response containers to create services for responding to requests (in route closures and controllers). Make Making services is simple, just call .make(_:) on a container and pass the type you want, usually a protocol like Client . let client = try req . make ( Client . self ) You can also specify a concrete type if you know exactly what you want. let leaf = try req . make ( LeafRenderer . self ) print ( leaf ) /// Definitely a LeafRenderer let view = try req . make ( ViewRenderer . self ) print ( view ) /// ViewRenderer, might be a LeafRenderer Tip Try to rely on protocols over concrete types if you can. This will make testing your code easier (you can easily swap in dummy implementations) and it can help keep your code decoupled. Services The Services struct contains all of the services you or the service providers you have added have registered. You will usually register and configure your services in configure.swift . Instance You can register initialized service instances using .register(_:) . /// Create an in-memory SQLite database let sqlite = SQLiteDatabase ( storage : . memory ) /// Register to sevices. services . register ( sqlite ) After you register a service, it will be available for creation by a Container . let db = app . make ( SQLiteDatabase . self ) print ( db ) // SQLiteDatabase (the one we registered earlier) Protocol When registering services, you can also declare conformance to a particular protocol. You might have noticed that this is how Vapor registers its main router. /// Register routes to the router let router = EngineRouter . default () try routes ( router ) services . register ( router , as : Router . self ) Since we register the router variable with as: Router.self , it can be created using either the concrete type or the protocol. let router = app . make ( Router . self ) let engineRouter = app . make ( EngineRouter . self ) print ( router ) // Router (actually EngineRouter) print ( engineRouter ) // EngineRouter print ( router === engineRouter ) // true Environment The environment is used to dynamically change how your Vapor app behaves in certain situations. For example, you probably want to use a different username and password for your database when your application is deployed. The Environment type makes managing this easy. When you run your Vapor app from the command line, you can pass an optional --env flag to specify the environment. By default, the environment will be .development . swift run Run --env prod In the above example, we are running Vapor in the .production environment. This environment specifies isRelease = true . You can use the environment passed into configure.swift to dynamically register services. let sqlite : SQLiteDatabase if env . isRelease { /// Create file-based SQLite db using $SQLITE_PATH from process env sqlite = try SQLiteDatabase ( storage : . file ( path : Environment . get ( SQLITE_PATH ) ! )) } else { /// Create an in-memory SQLite database sqlite = try SQLiteDatabase ( storage : . memory ) } services . register ( sqlite ) Info Use the static method Environment.get(_:) to fetch string values from the process environment. You can also dynamically register services based on environment using the factory .register(_:) method. services . register { container - BCryptConfig in let cost : Int switch container . environment { case . production : cost = 12 default : cost = 4 } return BCryptConfig ( cost : cost ) } Config If multiple services are available for a given protocol, you will need to use the Config struct to declare which service you prefer. ServiceError.ambiguity: Please choose which KeyedCache you prefer, multiple are available: MemoryKeyedCache, FluentCache SQLiteDatabase . This is also done in configure.swift , just use the config.prefer(_:for:) method. /// Declare preference for MemoryKeyedCache anytime a container is asked to create a KeyedCache config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) /// ... /// Create a KeyedCache using the Request container let cache = req . make ( KeyedCache . self ) print ( cache is MemoryKeyedCache ) // true","title":"Services"},{"location":"getting-started/services/#services","text":"Services is a dependency injection (also called inversion of control) framework for Vapor. The services framework allows you to register, configure, and initialize anything you might need in your application.","title":"Services"},{"location":"getting-started/services/#container","text":"Most of your interaction with services will happen through a container. A container is a combination of the following: Services : A collection of registered services. Config : Declared preferences for certain services over others. Environment : The application's current environment type (testing, production, etc) Worker : The event loop associated with this container. The most common containers you will interact with in Vapor are: Application Request Response You should use the Application as a container to create services required for booting your app. You should use the Request or Response containers to create services for responding to requests (in route closures and controllers).","title":"Container"},{"location":"getting-started/services/#make","text":"Making services is simple, just call .make(_:) on a container and pass the type you want, usually a protocol like Client . let client = try req . make ( Client . self ) You can also specify a concrete type if you know exactly what you want. let leaf = try req . make ( LeafRenderer . self ) print ( leaf ) /// Definitely a LeafRenderer let view = try req . make ( ViewRenderer . self ) print ( view ) /// ViewRenderer, might be a LeafRenderer Tip Try to rely on protocols over concrete types if you can. This will make testing your code easier (you can easily swap in dummy implementations) and it can help keep your code decoupled.","title":"Make"},{"location":"getting-started/services/#services_1","text":"The Services struct contains all of the services you or the service providers you have added have registered. You will usually register and configure your services in configure.swift .","title":"Services"},{"location":"getting-started/services/#instance","text":"You can register initialized service instances using .register(_:) . /// Create an in-memory SQLite database let sqlite = SQLiteDatabase ( storage : . memory ) /// Register to sevices. services . register ( sqlite ) After you register a service, it will be available for creation by a Container . let db = app . make ( SQLiteDatabase . self ) print ( db ) // SQLiteDatabase (the one we registered earlier)","title":"Instance"},{"location":"getting-started/services/#protocol","text":"When registering services, you can also declare conformance to a particular protocol. You might have noticed that this is how Vapor registers its main router. /// Register routes to the router let router = EngineRouter . default () try routes ( router ) services . register ( router , as : Router . self ) Since we register the router variable with as: Router.self , it can be created using either the concrete type or the protocol. let router = app . make ( Router . self ) let engineRouter = app . make ( EngineRouter . self ) print ( router ) // Router (actually EngineRouter) print ( engineRouter ) // EngineRouter print ( router === engineRouter ) // true","title":"Protocol"},{"location":"getting-started/services/#environment","text":"The environment is used to dynamically change how your Vapor app behaves in certain situations. For example, you probably want to use a different username and password for your database when your application is deployed. The Environment type makes managing this easy. When you run your Vapor app from the command line, you can pass an optional --env flag to specify the environment. By default, the environment will be .development . swift run Run --env prod In the above example, we are running Vapor in the .production environment. This environment specifies isRelease = true . You can use the environment passed into configure.swift to dynamically register services. let sqlite : SQLiteDatabase if env . isRelease { /// Create file-based SQLite db using $SQLITE_PATH from process env sqlite = try SQLiteDatabase ( storage : . file ( path : Environment . get ( SQLITE_PATH ) ! )) } else { /// Create an in-memory SQLite database sqlite = try SQLiteDatabase ( storage : . memory ) } services . register ( sqlite ) Info Use the static method Environment.get(_:) to fetch string values from the process environment. You can also dynamically register services based on environment using the factory .register(_:) method. services . register { container - BCryptConfig in let cost : Int switch container . environment { case . production : cost = 12 default : cost = 4 } return BCryptConfig ( cost : cost ) }","title":"Environment"},{"location":"getting-started/services/#config","text":"If multiple services are available for a given protocol, you will need to use the Config struct to declare which service you prefer. ServiceError.ambiguity: Please choose which KeyedCache you prefer, multiple are available: MemoryKeyedCache, FluentCache SQLiteDatabase . This is also done in configure.swift , just use the config.prefer(_:for:) method. /// Declare preference for MemoryKeyedCache anytime a container is asked to create a KeyedCache config . prefer ( MemoryKeyedCache . self , for : KeyedCache . self ) /// ... /// Create a KeyedCache using the Request container let cache = req . make ( KeyedCache . self ) print ( cache is MemoryKeyedCache ) // true","title":"Config"},{"location":"getting-started/spm/","text":"Managing your project The Swift Package Manager (SPM for short) is used for building your project's source code and dependencies. It's a similar idea to Cocoapods, Ruby gems, and NPM. Most of the time the Vapor Toolbox will interact with SPM on your behalf. However, it's important to understand the basics. Tip Learn more about SPM on Swift.org Package Manifest The first place SPM looks in your project is the package manifest. This should always be located in the root directory of your project and named Package.swift . Dependencies Dependencies are other SPM packages that your package relies on. All Vapor applications rely on the Vapor package, but you can add as many other dependencies as you want. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ // \ud83d\udca7 A server-side Swift web framework. . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0-rc ), ], targets : [ ... ] ) In the above example, you can see vapor/vapor version 3.0 or later is a dependency of this package. When you add a dependency to your package, you must next signal which targets depend on the newly available modules. Warning Anytime you modify the package manifest, call vapor update to effect the changes. Targets Targets are all of the modules, executables, and tests that your package contains. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ ... ], targets : [ . target ( name : App , dependencies : [ Vapor ]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Most Vapor apps will have three targets, although you can add as many as you like to organize your code. Each target declares which modules it depends on. You must add module names here in order to import them in your code. A target can depend on other targets in your project or any modules exposed by packages you've added to the main dependencies array. Tip Executable targets (targets that contain a main.swift file) cannot be imported by other modules. This is why Vapor has both an App and a Run target. Any code you include in App can be tested in the AppTests . Folder Structure Below is the typical folder structure for an SPM package. . \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u2514\u2500\u2500 (Source code) \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Each .target corresponds to a folder in the Sources folder. Each .testTarget corresponds to a folder in the Tests folder. Troubleshooting If you are experiencing problems with SPM, sometimes cleaning your project can help. vapor clean","title":"SPM"},{"location":"getting-started/spm/#managing-your-project","text":"The Swift Package Manager (SPM for short) is used for building your project's source code and dependencies. It's a similar idea to Cocoapods, Ruby gems, and NPM. Most of the time the Vapor Toolbox will interact with SPM on your behalf. However, it's important to understand the basics. Tip Learn more about SPM on Swift.org","title":"Managing your project"},{"location":"getting-started/spm/#package-manifest","text":"The first place SPM looks in your project is the package manifest. This should always be located in the root directory of your project and named Package.swift .","title":"Package Manifest"},{"location":"getting-started/spm/#dependencies","text":"Dependencies are other SPM packages that your package relies on. All Vapor applications rely on the Vapor package, but you can add as many other dependencies as you want. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ // \ud83d\udca7 A server-side Swift web framework. . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0-rc ), ], targets : [ ... ] ) In the above example, you can see vapor/vapor version 3.0 or later is a dependency of this package. When you add a dependency to your package, you must next signal which targets depend on the newly available modules. Warning Anytime you modify the package manifest, call vapor update to effect the changes.","title":"Dependencies"},{"location":"getting-started/spm/#targets","text":"Targets are all of the modules, executables, and tests that your package contains. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : VaporApp , dependencies : [ ... ], targets : [ . target ( name : App , dependencies : [ Vapor ]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Most Vapor apps will have three targets, although you can add as many as you like to organize your code. Each target declares which modules it depends on. You must add module names here in order to import them in your code. A target can depend on other targets in your project or any modules exposed by packages you've added to the main dependencies array. Tip Executable targets (targets that contain a main.swift file) cannot be imported by other modules. This is why Vapor has both an App and a Run target. Any code you include in App can be tested in the AppTests .","title":"Targets"},{"location":"getting-started/spm/#folder-structure","text":"Below is the typical folder structure for an SPM package. . \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u2514\u2500\u2500 (Source code) \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Each .target corresponds to a folder in the Sources folder. Each .testTarget corresponds to a folder in the Tests folder.","title":"Folder Structure"},{"location":"getting-started/spm/#troubleshooting","text":"If you are experiencing problems with SPM, sometimes cleaning your project can help. vapor clean","title":"Troubleshooting"},{"location":"getting-started/structure/","text":"Structure This section explains the structure of a typical Vapor application to help get you familiar with where things go. Folder Structure Vapor's folder structure builds on top of SPM's folder structure . . \u251c\u2500\u2500 Public \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u251c\u2500\u2500 Controllers \u2502 \u2502 \u251c\u2500\u2500 Models \u2502 \u2502 \u251c\u2500\u2500 boot.swift \u2502 \u2502 \u251c\u2500\u2500 configure.swift \u2502 \u2502 \u2514\u2500\u2500 routes.swift \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Let's take a look at what each of these folders and files does. Public This folder contains any public files that will be served by your app. This is usually images, style sheets, and browser scripts. Whenever Vapor responds to a request, it will first check if the requested item is in this folder. If it is, it skips your application logic and returns the file immediately. For example, a request to localhost:8080/favicon.ico will check to see if Public/favicon.ico exists. If it does, Vapor will return it. Sources This folder contains all of the Swift source files for your project. The top level folders ( App and Run ) reflect your package's modules, as declared in the package manifest . App This is the most important folder in your application, it's where all of the application logic goes! Controllers Controllers are great way of grouping together application logic. Most controllers have many functions that accept a request and return some sort of response. Tip Vapor supports, but does not enforce the MVC pattern Models The Models folder is a great place to store your Content structs or Fluent Model s. boot.swift This file contains a function that will be called after your application has booted, but before it has started running. This is a great place do things that should happen every time your application starts. You have access to the Application here which you can use to create any services you might need. configure.swift This file contains a function that receives the config, environment, and services for your application as input. This is a great place to make changes to your config or register services to your application. routes.swift This file contains a function for adding routes to your router. You will notice there's one example route in there that returns the \"hello, world\" response we saw earlier. You can create as many methods as you want to further organize your code. Just make sure to call them in this main route collection. Tests Each non-executable module in your Sources folder should have a corresponding ...Tests folder. AppTests This folder contains the unit tests for code in your App module. Learn more about testing in Testing Getting Started . Package.swift Finally is SPM's package manifest .","title":"Folder Structure"},{"location":"getting-started/structure/#structure","text":"This section explains the structure of a typical Vapor application to help get you familiar with where things go.","title":"Structure"},{"location":"getting-started/structure/#folder-structure","text":"Vapor's folder structure builds on top of SPM's folder structure . . \u251c\u2500\u2500 Public \u251c\u2500\u2500 Sources \u2502 \u251c\u2500\u2500 App \u2502 \u2502 \u251c\u2500\u2500 Controllers \u2502 \u2502 \u251c\u2500\u2500 Models \u2502 \u2502 \u251c\u2500\u2500 boot.swift \u2502 \u2502 \u251c\u2500\u2500 configure.swift \u2502 \u2502 \u2514\u2500\u2500 routes.swift \u2502 \u2514\u2500\u2500 Run \u2502 \u2514\u2500\u2500 main.swift \u251c\u2500\u2500 Tests \u2502 \u2514\u2500\u2500 AppTests \u2514\u2500\u2500 Package.swift Let's take a look at what each of these folders and files does.","title":"Folder Structure"},{"location":"getting-started/structure/#public","text":"This folder contains any public files that will be served by your app. This is usually images, style sheets, and browser scripts. Whenever Vapor responds to a request, it will first check if the requested item is in this folder. If it is, it skips your application logic and returns the file immediately. For example, a request to localhost:8080/favicon.ico will check to see if Public/favicon.ico exists. If it does, Vapor will return it.","title":"Public"},{"location":"getting-started/structure/#sources","text":"This folder contains all of the Swift source files for your project. The top level folders ( App and Run ) reflect your package's modules, as declared in the package manifest .","title":"Sources"},{"location":"getting-started/structure/#app","text":"This is the most important folder in your application, it's where all of the application logic goes!","title":"App"},{"location":"getting-started/structure/#controllers","text":"Controllers are great way of grouping together application logic. Most controllers have many functions that accept a request and return some sort of response. Tip Vapor supports, but does not enforce the MVC pattern","title":"Controllers"},{"location":"getting-started/structure/#models","text":"The Models folder is a great place to store your Content structs or Fluent Model s.","title":"Models"},{"location":"getting-started/structure/#bootswift","text":"This file contains a function that will be called after your application has booted, but before it has started running. This is a great place do things that should happen every time your application starts. You have access to the Application here which you can use to create any services you might need.","title":"boot.swift"},{"location":"getting-started/structure/#configureswift","text":"This file contains a function that receives the config, environment, and services for your application as input. This is a great place to make changes to your config or register services to your application.","title":"configure.swift"},{"location":"getting-started/structure/#routesswift","text":"This file contains a function for adding routes to your router. You will notice there's one example route in there that returns the \"hello, world\" response we saw earlier. You can create as many methods as you want to further organize your code. Just make sure to call them in this main route collection.","title":"routes.swift"},{"location":"getting-started/structure/#tests","text":"Each non-executable module in your Sources folder should have a corresponding ...Tests folder.","title":"Tests"},{"location":"getting-started/structure/#apptests","text":"This folder contains the unit tests for code in your App module. Learn more about testing in Testing Getting Started .","title":"AppTests"},{"location":"getting-started/structure/#packageswift","text":"Finally is SPM's package manifest .","title":"Package.swift"},{"location":"getting-started/toolbox/","text":"Install Toolbox Vapor's command line interface provides shortcuts and assistance for common tasks. Help prints useful information about available commands and flags. vapor --help You can also run the --help option on any Toolbox command. vapor new --help The --help flag should be your goto for learning about the toolbox as it is the most up-to-date. New The Toolbox's most important feature is helping you create a new project. vapor new name Just pass the name of your project as the first argument to the new command. Note Project names should be PascalCase , like HelloWorld or MyProject . Templates By default, Vapor will create your new project from the API template. You can choose a different template by passing the --template flag. Name Flag Description API --template=api JSON API with Fluent database. Web --template=web HTML website with Leaf templates. Auth --template=auth-template JSON API with Fluent DB and Auth. Info There are lots of unofficial Vapor templates on GitHub under the vapor + template topcs . You can use these by passing the full GitHub URL to the --template option. Build Run You can use the toolbox to build and run your Vapor app. vapor build vapor run Tip We recommend building and running through Xcode if you have a Mac. It's a bit faster and you can set breakpoints! Just use vapor xcode to generate an Xcode project. Updating The toolbox should be updated by the package manager it was installed with. Homebrew brew upgrade vapor APT sudo apt-get update sudo apt-get install vapor","title":"Toolbox"},{"location":"getting-started/toolbox/#install-toolbox","text":"Vapor's command line interface provides shortcuts and assistance for common tasks. Help prints useful information about available commands and flags. vapor --help You can also run the --help option on any Toolbox command. vapor new --help The --help flag should be your goto for learning about the toolbox as it is the most up-to-date.","title":"Install Toolbox"},{"location":"getting-started/toolbox/#new","text":"The Toolbox's most important feature is helping you create a new project. vapor new name Just pass the name of your project as the first argument to the new command. Note Project names should be PascalCase , like HelloWorld or MyProject .","title":"New"},{"location":"getting-started/toolbox/#templates","text":"By default, Vapor will create your new project from the API template. You can choose a different template by passing the --template flag. Name Flag Description API --template=api JSON API with Fluent database. Web --template=web HTML website with Leaf templates. Auth --template=auth-template JSON API with Fluent DB and Auth. Info There are lots of unofficial Vapor templates on GitHub under the vapor + template topcs . You can use these by passing the full GitHub URL to the --template option.","title":"Templates"},{"location":"getting-started/toolbox/#build-run","text":"You can use the toolbox to build and run your Vapor app. vapor build vapor run Tip We recommend building and running through Xcode if you have a Mac. It's a bit faster and you can set breakpoints! Just use vapor xcode to generate an Xcode project.","title":"Build & Run"},{"location":"getting-started/toolbox/#updating","text":"The toolbox should be updated by the package manager it was installed with.","title":"Updating"},{"location":"getting-started/toolbox/#homebrew","text":"brew upgrade vapor","title":"Homebrew"},{"location":"getting-started/toolbox/#apt","text":"sudo apt-get update sudo apt-get install vapor","title":"APT"},{"location":"getting-started/xcode/","text":"Xcode If you're on a Mac, you can develop your Vapor project using Xcode. You can build, run, and stop your server from within Xcode, as well as use breakpoints and instruments to debug your code. Xcode is a great way to develop Vapor apps, but you can use any text editor you like. Generate Project To use Xcode, you just need to generate an Xcode project using Vapor Toolbox . vapor xcode Tip Don't worry about comitting the generated Xcode Project to git, just generate a new one whenever you need it. Run To build and run your Vapor app, first make sure you have the Run scheme selected from the schemes menu. Also make sure to select \"My Mac\" as the device. Once that's selected, just click the play button or press Command + R on your keyboard. Test To run your unit tests, select the scheme ending in -Package and press Command + U . Warning There may be a few extraneous schemes in the dropdown menu. Ignore them!","title":"Xcode"},{"location":"getting-started/xcode/#xcode","text":"If you're on a Mac, you can develop your Vapor project using Xcode. You can build, run, and stop your server from within Xcode, as well as use breakpoints and instruments to debug your code. Xcode is a great way to develop Vapor apps, but you can use any text editor you like.","title":"Xcode"},{"location":"getting-started/xcode/#generate-project","text":"To use Xcode, you just need to generate an Xcode project using Vapor Toolbox . vapor xcode Tip Don't worry about comitting the generated Xcode Project to git, just generate a new one whenever you need it.","title":"Generate Project"},{"location":"getting-started/xcode/#run","text":"To build and run your Vapor app, first make sure you have the Run scheme selected from the schemes menu. Also make sure to select \"My Mac\" as the device. Once that's selected, just click the play button or press Command + R on your keyboard.","title":"Run"},{"location":"getting-started/xcode/#test","text":"To run your unit tests, select the scheme ending in -Package and press Command + U . Warning There may be a few extraneous schemes in the dropdown menu. Ignore them!","title":"Test"},{"location":"http/client/","text":"Using HTTPClient HTTP clients send requests to remote HTTP servers which then generate and return responses. HTTP clients are usually only active for a matter of seconds to minutes and may send one or more requests. The HTTPClient type is what powers Vapor's higher-level client. This short guide will show you how to send HTTP requests to servers manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Client for the more convenient APIs. For this example, we will fetch Vapor's homepage. The first step is to create a connected HTTP client. Use the static connect(...) method to do this. // Connect a new client to the supplied hostname. let client = try HTTPClient . connect ( hostname : vapor.codes , on : ...). wait () print ( client ) // HTTPClient // Create an HTTP request: GET / let httpReq = HTTPRequest ( method : . GET , url : / ) // Send the HTTP request, fetching a response let httpRes = try client . send ( httpReq ). wait () print ( httpRes ) // HTTPResponse Take note that we are passing the hostname . This is different from a full URL. You can use URL and URLComponents from Foundation to parse out a hostname. Vapor's convenience APIs do this automatically. Warning This guide assumes you are on the main thread. Don't use wait() if you are inside of a route closure. See Async Overview for more information. After we have a connected HTTP client, we can send an HTTPRequest using send(...) . This will return an HTTPResponse containing the headers and body sent back from the server. See HTTP Message for more information on HTTP messages. API Docs That's it! Congratulations on making your first HTTP request. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"Client"},{"location":"http/client/#using-httpclient","text":"HTTP clients send requests to remote HTTP servers which then generate and return responses. HTTP clients are usually only active for a matter of seconds to minutes and may send one or more requests. The HTTPClient type is what powers Vapor's higher-level client. This short guide will show you how to send HTTP requests to servers manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Client for the more convenient APIs. For this example, we will fetch Vapor's homepage. The first step is to create a connected HTTP client. Use the static connect(...) method to do this. // Connect a new client to the supplied hostname. let client = try HTTPClient . connect ( hostname : vapor.codes , on : ...). wait () print ( client ) // HTTPClient // Create an HTTP request: GET / let httpReq = HTTPRequest ( method : . GET , url : / ) // Send the HTTP request, fetching a response let httpRes = try client . send ( httpReq ). wait () print ( httpRes ) // HTTPResponse Take note that we are passing the hostname . This is different from a full URL. You can use URL and URLComponents from Foundation to parse out a hostname. Vapor's convenience APIs do this automatically. Warning This guide assumes you are on the main thread. Don't use wait() if you are inside of a route closure. See Async Overview for more information. After we have a connected HTTP client, we can send an HTTPRequest using send(...) . This will return an HTTPResponse containing the headers and body sent back from the server. See HTTP Message for more information on HTTP messages.","title":"Using HTTPClient"},{"location":"http/client/#api-docs","text":"That's it! Congratulations on making your first HTTP request. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"API Docs"},{"location":"http/getting-started/","text":"Getting Started with HTTP HTTP ( vapor/http ) is a non-blocking, event-driven HTTP library built on SwiftNIO. It makes working with SwiftNIO's HTTP handlers easy and offers higher-level functionality like media types, client upgrading, streaming bodies, and more. Creating an HTTP echo server takes just a few lines of code. Tip If you use Vapor, most of HTTP's APIs will be wrapped by more convenient methods. Usually the only HTTP type you will interact with is the http property of Request or Response . Vapor This package is included with Vapor and exported by default. You will have access to all HTTP APIs when you import Vapor . import Vapor Standalone The HTTP package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as an HTTP framework in any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/http.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ HTTP , ... ]) ] ) Use import HTTP to access the APIs. The rest of this guide will give you an overview of what is available in the HTTP package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"http/getting-started/#getting-started-with-http","text":"HTTP ( vapor/http ) is a non-blocking, event-driven HTTP library built on SwiftNIO. It makes working with SwiftNIO's HTTP handlers easy and offers higher-level functionality like media types, client upgrading, streaming bodies, and more. Creating an HTTP echo server takes just a few lines of code. Tip If you use Vapor, most of HTTP's APIs will be wrapped by more convenient methods. Usually the only HTTP type you will interact with is the http property of Request or Response .","title":"Getting Started with HTTP"},{"location":"http/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all HTTP APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"http/getting-started/#standalone","text":"The HTTP package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as an HTTP framework in any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/http.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ HTTP , ... ]) ] ) Use import HTTP to access the APIs. The rest of this guide will give you an overview of what is available in the HTTP package. As always, feel free to visit the API docs for more in-depth information.","title":"Standalone"},{"location":"http/message/","text":"Using HTTP Message There are two types of HTTP messages, HTTPRequest and HTTPResponse . For the most part they are very similar, but there are a couple of differences. Request HTTP requests are sent by clients to a server and they should always receive exactly one HTTP response. HTTP requests contain two unique fields over a standard HTTP message: method url The method and URL define what content on the server is being requested. /// GET /hello let httpReq = HTTPRequest ( method : . GET , url : /hello ) You can define these when initializing an HTTP request, or set them later if the request is mutable. var httpReq : HTTPRequest = ... httpReq . method = . POST httpReq . url = URL (...) You can use Foundation's URLComponents to create URL s from their base components. HTTP request also has a property urlString that you can use to set a custom URL String manually, without going through URL . Here is what a serialized HTTP request looks like. This one is querying /hello . GET /hello HTTP / 1.1 Content-Length : 0 Response HTTP responses are generated by servers in response to an HTTP request. HTTP response only has one unique field over general HTTP messages: status The HTTP status is used to inform the client of any errors. The status consists of a status code and a reason. The code is always a three digit number and the reason is a short string explaining the code. You can see all of the status codes on httpstatuses.com . let httpRes = HTTPResponse ( status : . ok , body : hello ) All of the commonly used HTTP statuses will have pre-defined values you can use, like .ok for 200 OK . You can also define your own custom status codes. You can define the status when initializing an HTTP response, or set it later if the response is mutable. var httpRes : HTTPResponse = ... httpRes . status = . notFound Here is an example of a serialized HTTP response. HTTP / 1.1 200 OK Content-Length : 5 Content-Type : text/plain hello Headers Every HTTP message has a collection of headers. Headers contain metadata about the message and help to explain what is in the message's body. Content-Length: 5 Content-Type: text/plain There must be at least a \"Content-Length\" or \"Transfer-Encoding\" header to define how long the message's body is. There is almost always a \"Content-Type\" header that explains what type of data the body contains. There are many other common headers such as \"Date\" which specifies when the message was created, and more. You can access an HTTP message's headers using the headers property. var message : HTTPMessage ... message . headers . firstValue ( for : . contentLength ) // 5 If you are interacting with common HTTP headers, you can use the convenience HTTP names instead of a raw String . Body HTTP messages can have an HTTPBody containing arbitrary data. This data can be either static or streaming and can be in whatever format you want. Use the contentType header to describe the type of data. var message : HTTPMessage = ... message . body = HTTPBody ( string : Hello, world! ) message . contentType = . plainText Tip Setting the body property will automatically update the \"Content-Length\" or \"Transfer-Encoding\" headers if required. var message : HTTPMessage = ... message . body = HTTPBody ( string : { message : Hello , world ! } ) message . contentType = . json Codable Two protocols are defined for making it easy to use Codable with HTTP: HTTPMessageEncoder HTTPMessageDecoder These two coders allow you to encode and decode your custom Codable types into an HTTP body, setting the appropriate content type headers. By default, HTTP provides conformance for JSONEncoder and JSONDecoder , but Vapor includes coders for many more types. Here is an example of encoding a Codable struct to an HTTP response. struct Greeting : Codable { var message : String } // Create an instance of Greeting let greeting = Greeting ( message : Hello, world! ) // Create a 200 OK response var httpRes = HTTPResponse ( status : . ok ) // Encode the greeting to the response try JSONEncoder (). encode ( greeting , to : httpRes , on : ...) API Docs Check out the API docs for more in-depth information about all of the methods.","title":"Message"},{"location":"http/message/#using-http-message","text":"There are two types of HTTP messages, HTTPRequest and HTTPResponse . For the most part they are very similar, but there are a couple of differences.","title":"Using HTTP Message"},{"location":"http/message/#request","text":"HTTP requests are sent by clients to a server and they should always receive exactly one HTTP response. HTTP requests contain two unique fields over a standard HTTP message: method url The method and URL define what content on the server is being requested. /// GET /hello let httpReq = HTTPRequest ( method : . GET , url : /hello ) You can define these when initializing an HTTP request, or set them later if the request is mutable. var httpReq : HTTPRequest = ... httpReq . method = . POST httpReq . url = URL (...) You can use Foundation's URLComponents to create URL s from their base components. HTTP request also has a property urlString that you can use to set a custom URL String manually, without going through URL . Here is what a serialized HTTP request looks like. This one is querying /hello . GET /hello HTTP / 1.1 Content-Length : 0","title":"Request"},{"location":"http/message/#response","text":"HTTP responses are generated by servers in response to an HTTP request. HTTP response only has one unique field over general HTTP messages: status The HTTP status is used to inform the client of any errors. The status consists of a status code and a reason. The code is always a three digit number and the reason is a short string explaining the code. You can see all of the status codes on httpstatuses.com . let httpRes = HTTPResponse ( status : . ok , body : hello ) All of the commonly used HTTP statuses will have pre-defined values you can use, like .ok for 200 OK . You can also define your own custom status codes. You can define the status when initializing an HTTP response, or set it later if the response is mutable. var httpRes : HTTPResponse = ... httpRes . status = . notFound Here is an example of a serialized HTTP response. HTTP / 1.1 200 OK Content-Length : 5 Content-Type : text/plain hello","title":"Response"},{"location":"http/message/#headers","text":"Every HTTP message has a collection of headers. Headers contain metadata about the message and help to explain what is in the message's body. Content-Length: 5 Content-Type: text/plain There must be at least a \"Content-Length\" or \"Transfer-Encoding\" header to define how long the message's body is. There is almost always a \"Content-Type\" header that explains what type of data the body contains. There are many other common headers such as \"Date\" which specifies when the message was created, and more. You can access an HTTP message's headers using the headers property. var message : HTTPMessage ... message . headers . firstValue ( for : . contentLength ) // 5 If you are interacting with common HTTP headers, you can use the convenience HTTP names instead of a raw String .","title":"Headers"},{"location":"http/message/#body","text":"HTTP messages can have an HTTPBody containing arbitrary data. This data can be either static or streaming and can be in whatever format you want. Use the contentType header to describe the type of data. var message : HTTPMessage = ... message . body = HTTPBody ( string : Hello, world! ) message . contentType = . plainText Tip Setting the body property will automatically update the \"Content-Length\" or \"Transfer-Encoding\" headers if required. var message : HTTPMessage = ... message . body = HTTPBody ( string : { message : Hello , world ! } ) message . contentType = . json","title":"Body"},{"location":"http/message/#codable","text":"Two protocols are defined for making it easy to use Codable with HTTP: HTTPMessageEncoder HTTPMessageDecoder These two coders allow you to encode and decode your custom Codable types into an HTTP body, setting the appropriate content type headers. By default, HTTP provides conformance for JSONEncoder and JSONDecoder , but Vapor includes coders for many more types. Here is an example of encoding a Codable struct to an HTTP response. struct Greeting : Codable { var message : String } // Create an instance of Greeting let greeting = Greeting ( message : Hello, world! ) // Create a 200 OK response var httpRes = HTTPResponse ( status : . ok ) // Encode the greeting to the response try JSONEncoder (). encode ( greeting , to : httpRes , on : ...)","title":"Codable"},{"location":"http/message/#api-docs","text":"Check out the API docs for more in-depth information about all of the methods.","title":"API Docs"},{"location":"http/server/","text":"Using HTTPServer HTTP servers respond to incoming HTTPRequests with HTTPResponses . The HTTPServer type is what powers Vapor's higher-level server. This short guide will show you how to set up your own HTTP server manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Getting Started for the more convenient APIs. Responder Creating an HTTP server is easy, and only takes a few lines of code. The first step is to create an HTTPServerResponder . This will be directly responsible for generating responses to incoming requests. Let's create a simple responder that will echo the request's content. /// Echoes the request as a response. struct EchoResponder : HTTPServerResponder { /// See `HTTPServerResponder`. func respond ( to req : HTTPRequest , on worker : Worker ) - Future HTTPResponse { // Create an HTTPResponse with the same body as the HTTPRequest let res = HTTPResponse ( body : req . body ) // We don t need to do any async work here, we can just // se the Worker s event-loop to create a succeeded future. return worker . eventLoop . newSucceededFuture ( result : res ) } } Start Now that we have a responder, we can create our HTTPServer . We just need to choose a hostname and port for the server to bind to. In this example, we will bind to http://localhost:8123 . // Create an EventLoopGroup with an appropriate number // of threads for the system we are running on. let group = MultiThreadedEventLoopGroup ( numThreads : System . coreCount ) // Make sure to shutdown the group when the application exits. defer { try ! group . syncShutdownGracefully () } // Start an HTTPServer using our EchoResponder // We are fine to use `wait()` here since we are on the main thread. let server = try HTTPServer . start ( hostname : localhost , port : 8123 , responder : EchoResponder (), on : group ). wait () // Wait for the server to close (indefinitely). try server . onClose . wait () The static start(...) method creates and returns a new HTTPServer asynchronously. The future will be completed when the server has finished booting succesfully, or it will contain an error if something went wrong. Once the start future is complete, our server is running. By waiting for the server's onClose future to complete, we can keep our application alive until the server closes. Normally the server will not close itself--it will just run indefinitely. However if server.close() is ever called, the application can exit gracefully. API Docs That's it! Congratulations on making your first HTTP server and responder. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"Server"},{"location":"http/server/#using-httpserver","text":"HTTP servers respond to incoming HTTPRequests with HTTPResponses . The HTTPServer type is what powers Vapor's higher-level server. This short guide will show you how to set up your own HTTP server manually. Tip If you are using Vapor, you probably don't need to use HTTP's APIs directly. Refer to Vapor Getting Started for the more convenient APIs.","title":"Using HTTPServer"},{"location":"http/server/#responder","text":"Creating an HTTP server is easy, and only takes a few lines of code. The first step is to create an HTTPServerResponder . This will be directly responsible for generating responses to incoming requests. Let's create a simple responder that will echo the request's content. /// Echoes the request as a response. struct EchoResponder : HTTPServerResponder { /// See `HTTPServerResponder`. func respond ( to req : HTTPRequest , on worker : Worker ) - Future HTTPResponse { // Create an HTTPResponse with the same body as the HTTPRequest let res = HTTPResponse ( body : req . body ) // We don t need to do any async work here, we can just // se the Worker s event-loop to create a succeeded future. return worker . eventLoop . newSucceededFuture ( result : res ) } }","title":"Responder"},{"location":"http/server/#start","text":"Now that we have a responder, we can create our HTTPServer . We just need to choose a hostname and port for the server to bind to. In this example, we will bind to http://localhost:8123 . // Create an EventLoopGroup with an appropriate number // of threads for the system we are running on. let group = MultiThreadedEventLoopGroup ( numThreads : System . coreCount ) // Make sure to shutdown the group when the application exits. defer { try ! group . syncShutdownGracefully () } // Start an HTTPServer using our EchoResponder // We are fine to use `wait()` here since we are on the main thread. let server = try HTTPServer . start ( hostname : localhost , port : 8123 , responder : EchoResponder (), on : group ). wait () // Wait for the server to close (indefinitely). try server . onClose . wait () The static start(...) method creates and returns a new HTTPServer asynchronously. The future will be completed when the server has finished booting succesfully, or it will contain an error if something went wrong. Once the start future is complete, our server is running. By waiting for the server's onClose future to complete, we can keep our application alive until the server closes. Normally the server will not close itself--it will just run indefinitely. However if server.close() is ever called, the application can exit gracefully.","title":"Start"},{"location":"http/server/#api-docs","text":"That's it! Congratulations on making your first HTTP server and responder. Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"API Docs"},{"location":"install/macos/","text":"Install on macOS To use Vapor on macOS, you just need to have Xcode 9.3 or greater installed. Install Xcode Install Xcode 9.3 or greater from the Mac App Store. Warning After Xcode has been downloaded, you must open it to finish the installation. This may take a while. Verify Installation Double check the installation was successful by opening Terminal and running: swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater. Install Vapor Now that you have Swift 4.1, let's install the Vapor Toolbox . The toolbox includes all of Vapor's dependencies as well as a handy CLI tool for creating new projects. brew install vapor/tap/vapor Tip If you don't already have Homebrew installed, install it at brew.sh Verify Installation Double check the installation was successful by opening Terminal and running: vapor --help You should see a long list of available commands. Done Now that you have installed Vapor, create your first app in Getting Started Hello, world .","title":"macOS"},{"location":"install/macos/#install-on-macos","text":"To use Vapor on macOS, you just need to have Xcode 9.3 or greater installed.","title":"Install on macOS"},{"location":"install/macos/#install-xcode","text":"Install Xcode 9.3 or greater from the Mac App Store. Warning After Xcode has been downloaded, you must open it to finish the installation. This may take a while.","title":"Install Xcode"},{"location":"install/macos/#verify-installation","text":"Double check the installation was successful by opening Terminal and running: swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater.","title":"Verify Installation"},{"location":"install/macos/#install-vapor","text":"Now that you have Swift 4.1, let's install the Vapor Toolbox . The toolbox includes all of Vapor's dependencies as well as a handy CLI tool for creating new projects. brew install vapor/tap/vapor Tip If you don't already have Homebrew installed, install it at brew.sh","title":"Install Vapor"},{"location":"install/macos/#verify-installation_1","text":"Double check the installation was successful by opening Terminal and running: vapor --help You should see a long list of available commands.","title":"Verify Installation"},{"location":"install/macos/#done","text":"Now that you have installed Vapor, create your first app in Getting Started Hello, world .","title":"Done"},{"location":"install/ubuntu/","text":"Install on Ubuntu Installing Vapor on Ubuntu only takes a couple of minutes. Supported Vapor supports the same versions of Ubuntu that Swift supports. Version Codename 16.10 Yakkety Yak 16.04 Xenial Xerus 14.04 Trusty Tahr APT Repo Add Vapor's APT repo to get access to all of Vapor's Ubuntu packages. Quick Script Easily add Vapor's APT repo with this handy script. eval $( curl -sL https://apt.vapor.sh ) Tip This command requires curl which can be installed using sudo apt-get install curl Dockerfile When configuring Ubuntu from a Dockerfile, adding the APT repo can be done via this command: RUN /bin/bash -c $( wget -qO- https://apt.vapor.sh ) Manual Or add the repo manually. wget -q https://repo.vapor.codes/apt/keyring.gpg -O- | sudo apt-key add - echo deb https://repo.vapor.codes/apt $( lsb_release -sc ) main | sudo tee /etc/apt/sources.list.d/vapor.list sudo apt-get update Install Vapor Now that you have added Vapor's APT repo, you can install the required dependencies. sudo apt-get install swift vapor Verify Installation Double check everything worked with the following commands. Swift swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater. Vapor Toolbox vapor --help You should see a long list of available commands. Done Now that you have installed Vapor, create your first app in Getting Started Hello, world . Swift.org Check out Swift.org 's guide to using downloads if you need more detailed instructions for installing Swift 4.1.","title":"Ubuntu"},{"location":"install/ubuntu/#install-on-ubuntu","text":"Installing Vapor on Ubuntu only takes a couple of minutes.","title":"Install on Ubuntu"},{"location":"install/ubuntu/#supported","text":"Vapor supports the same versions of Ubuntu that Swift supports. Version Codename 16.10 Yakkety Yak 16.04 Xenial Xerus 14.04 Trusty Tahr","title":"Supported"},{"location":"install/ubuntu/#apt-repo","text":"Add Vapor's APT repo to get access to all of Vapor's Ubuntu packages.","title":"APT Repo"},{"location":"install/ubuntu/#quick-script","text":"Easily add Vapor's APT repo with this handy script. eval $( curl -sL https://apt.vapor.sh ) Tip This command requires curl which can be installed using sudo apt-get install curl","title":"Quick Script"},{"location":"install/ubuntu/#dockerfile","text":"When configuring Ubuntu from a Dockerfile, adding the APT repo can be done via this command: RUN /bin/bash -c $( wget -qO- https://apt.vapor.sh )","title":"Dockerfile"},{"location":"install/ubuntu/#manual","text":"Or add the repo manually. wget -q https://repo.vapor.codes/apt/keyring.gpg -O- | sudo apt-key add - echo deb https://repo.vapor.codes/apt $( lsb_release -sc ) main | sudo tee /etc/apt/sources.list.d/vapor.list sudo apt-get update","title":"Manual"},{"location":"install/ubuntu/#install-vapor","text":"Now that you have added Vapor's APT repo, you can install the required dependencies. sudo apt-get install swift vapor","title":"Install Vapor"},{"location":"install/ubuntu/#verify-installation","text":"Double check everything worked with the following commands.","title":"Verify Installation"},{"location":"install/ubuntu/#swift","text":"swift --version You should see output similar to: Apple Swift version 4 .1.0 ( swiftlang-900.0.69.2 clang-900.0.38 ) Target: x86_64-apple-macosx10.9 Vapor requires Swift 4.1 or greater.","title":"Swift"},{"location":"install/ubuntu/#vapor-toolbox","text":"vapor --help You should see a long list of available commands.","title":"Vapor Toolbox"},{"location":"install/ubuntu/#done","text":"Now that you have installed Vapor, create your first app in Getting Started Hello, world .","title":"Done"},{"location":"install/ubuntu/#swiftorg","text":"Check out Swift.org 's guide to using downloads if you need more detailed instructions for installing Swift 4.1.","title":"Swift.org"},{"location":"jwt/getting-started/","text":"Getting Started with JWT JWT ( vapor/jwt ) is a package for parsing and serializing J SON W eb T okens supporting both HMAC and RSA signing. JWTs are often used for implementing decentralized authentication and authorization. Since all of the authenticated user's information can be embedded within a JWT, there is no need to query a central authentication server with each request to your service. Unlike standard bearer tokens that must be looked up in a centralized database, JWTs contain cryptographic signatures that can be used to independently verify their authenticity. If implemented correctly, JWTs can be a powerful tool for making your application horizontally scalable . Learn more about JWT at jwt.io . Tip If your goal is not horizontal scalability, a standard bearer token will likely be a better solution. JWTs have some downsides worth considering such as the inability to revoke a token once it has been issued (until it expires normally). Let's take a look at how you can get started using JWT. Package The first step to using JWT is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd0f JSON Web Token signing and verification (HMAC, RSA). . package ( url : https://github.com/vapor/jwt.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ JWT , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) That's it for basic setup. The next section will give you an overview of the package's APIs. As always, feel free to visit the API Docs for more specific information.","title":"Getting Started"},{"location":"jwt/getting-started/#getting-started-with-jwt","text":"JWT ( vapor/jwt ) is a package for parsing and serializing J SON W eb T okens supporting both HMAC and RSA signing. JWTs are often used for implementing decentralized authentication and authorization. Since all of the authenticated user's information can be embedded within a JWT, there is no need to query a central authentication server with each request to your service. Unlike standard bearer tokens that must be looked up in a centralized database, JWTs contain cryptographic signatures that can be used to independently verify their authenticity. If implemented correctly, JWTs can be a powerful tool for making your application horizontally scalable . Learn more about JWT at jwt.io . Tip If your goal is not horizontal scalability, a standard bearer token will likely be a better solution. JWTs have some downsides worth considering such as the inability to revoke a token once it has been issued (until it expires normally). Let's take a look at how you can get started using JWT.","title":"Getting Started with JWT"},{"location":"jwt/getting-started/#package","text":"The first step to using JWT is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd0f JSON Web Token signing and verification (HMAC, RSA). . package ( url : https://github.com/vapor/jwt.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ JWT , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) That's it for basic setup. The next section will give you an overview of the package's APIs. As always, feel free to visit the API Docs for more specific information.","title":"Package"},{"location":"jwt/overview/","text":"Using JWT JSON Web Tokens are a great tool for implementing decentralized authentication and authorization. Once you are finished configuring your app to use the JWT package (see JWT Getting Started ), you are ready to begin using JWTs in your app. Structure Like other forms of token-based auth, JWTs are sent using the bearer authorization header. GET /hello HTTP / 1.1 Authorization : Bearer token ... In the example HTTP request above, token would be replaced by the serialized JWT. jwt.io hosts an online tool for parsing and serializing JWTs. We will use that tool to create a token for testing. Header The header is mainly used to specify which algorithm was used to generate the token's signature. This is used by the accepting app to verify the token's authenticity. Here is the raw JSON data for our header: { alg : HS256 , typ : JWT } This specifies the HMAC SHA-256 signing algorithm and that our token is indeed a JWT. Payload The payload is where you store information to identify the authenticated user. You can store any data you want here, but be careful not to store too much as some web browsers limit HTTP header sizes. The payload is also where you store claims . Claims are standardized key / value pairs that many JWT implementations can recognize and act on automatically. A commonly used claim is Expiration Time which stores the token's expiration date as a unix timestamp at key \"exp\" . See a full list of supported claims in RFC 7519 4.1 . To keep things simple, we will just include our user's identifier and name in the payload: { id : 42 , name : Vapor Developer } Secret Last but not least is the secret key used to sign and verify the JWT. For this example, we are using the HS256 algorithm (specified in the JWT header). HMAC algorithms use a single secret key for both signing and verifying. To keep things simple, we will use the following string as our key: secret Other algorithms, like RSA, use asymmetric (public and private) keys. With these types of algorithms, only the private key is able to create (sign) JWTs. Both the public and private keys can verify JWTs. This allows for an added layer of security as you can distribute the public key to services that should only be able to verify tokens, not create them. Serialized Finally, here is our fully serialized token. This will be sent via the bearer authorization header. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Each segment is separated by a . . The overall structure of the token is the following: header . payload . signature Note that the header and payload segments are simply base64-url encoded JSON. It is important to remember that all information your store in a normal JWT is publically readable. Parse Let's take a look at how to parse and verify incoming JWTs. Payload First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now. Route Now that our payload type is ready, we can parse and verify an incoming JWT. import JWT import Vapor router . get ( hello ) { req - String in // fetches the token from `Authorization: Bearer token ` header guard let bearer = req . http . headers . bearerAuthorization else { throw Abort (. unauthorized ) } // parse JWT from token string, using HS-256 signer let jwt = try JWT User ( from : bearer . token , verifiedUsing : . hs256 ( key : secret )) return Hello, \\( jwt . payload . name ) ! } This snippet creates a new route at GET /hello . The first part of the route handler fetches the token value from the bearer authorization header. The second part uses the JWT struct to parse the token using an HS256 signer. Once the JWT is parsed, we access the payload property which contains an instance of our User type. We then access the name property to say hello! Run the following request and check the output: GET /hello HTTP / 1.1 Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Content-Length : 0 You should see the following response: HTTP / 1.1 200 OK Content-Length : 23 Hello, Vapor Developer! Serialize Let's take a look at how to create and sign a JWT. Payload First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now. Route Now that our payload type is ready, we can generate a JWT. router . post ( login ) { req - String in // create payload let user = User ( id : 42 , name : Vapor Developer ) // create JWT and sign let data = try JWT ( payload : user ). sign ( using : . hs256 ( key : secret )) return String ( data : data , encoding : . utf8 ) ?? } This snippet creates a new route at POST /login . The first part of the route handler creates an instance of our User payload type. The second part creates an instance of JWT using our payload, and calls the sign(using:) method. This method returns Data , which we convert to a String . If you visit this route, you should get the following output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM If you plug that JWT into jwt.io and enter the secret ( secret ), you should see the encoded data and a message \"Signature Verified\".","title":"Overview"},{"location":"jwt/overview/#using-jwt","text":"JSON Web Tokens are a great tool for implementing decentralized authentication and authorization. Once you are finished configuring your app to use the JWT package (see JWT Getting Started ), you are ready to begin using JWTs in your app.","title":"Using JWT"},{"location":"jwt/overview/#structure","text":"Like other forms of token-based auth, JWTs are sent using the bearer authorization header. GET /hello HTTP / 1.1 Authorization : Bearer token ... In the example HTTP request above, token would be replaced by the serialized JWT. jwt.io hosts an online tool for parsing and serializing JWTs. We will use that tool to create a token for testing.","title":"Structure"},{"location":"jwt/overview/#header","text":"The header is mainly used to specify which algorithm was used to generate the token's signature. This is used by the accepting app to verify the token's authenticity. Here is the raw JSON data for our header: { alg : HS256 , typ : JWT } This specifies the HMAC SHA-256 signing algorithm and that our token is indeed a JWT.","title":"Header"},{"location":"jwt/overview/#payload","text":"The payload is where you store information to identify the authenticated user. You can store any data you want here, but be careful not to store too much as some web browsers limit HTTP header sizes. The payload is also where you store claims . Claims are standardized key / value pairs that many JWT implementations can recognize and act on automatically. A commonly used claim is Expiration Time which stores the token's expiration date as a unix timestamp at key \"exp\" . See a full list of supported claims in RFC 7519 4.1 . To keep things simple, we will just include our user's identifier and name in the payload: { id : 42 , name : Vapor Developer }","title":"Payload"},{"location":"jwt/overview/#secret","text":"Last but not least is the secret key used to sign and verify the JWT. For this example, we are using the HS256 algorithm (specified in the JWT header). HMAC algorithms use a single secret key for both signing and verifying. To keep things simple, we will use the following string as our key: secret Other algorithms, like RSA, use asymmetric (public and private) keys. With these types of algorithms, only the private key is able to create (sign) JWTs. Both the public and private keys can verify JWTs. This allows for an added layer of security as you can distribute the public key to services that should only be able to verify tokens, not create them.","title":"Secret"},{"location":"jwt/overview/#serialized","text":"Finally, here is our fully serialized token. This will be sent via the bearer authorization header. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Each segment is separated by a . . The overall structure of the token is the following: header . payload . signature Note that the header and payload segments are simply base64-url encoded JSON. It is important to remember that all information your store in a normal JWT is publically readable.","title":"Serialized"},{"location":"jwt/overview/#parse","text":"Let's take a look at how to parse and verify incoming JWTs.","title":"Parse"},{"location":"jwt/overview/#payload_1","text":"First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now.","title":"Payload"},{"location":"jwt/overview/#route","text":"Now that our payload type is ready, we can parse and verify an incoming JWT. import JWT import Vapor router . get ( hello ) { req - String in // fetches the token from `Authorization: Bearer token ` header guard let bearer = req . http . headers . bearerAuthorization else { throw Abort (. unauthorized ) } // parse JWT from token string, using HS-256 signer let jwt = try JWT User ( from : bearer . token , verifiedUsing : . hs256 ( key : secret )) return Hello, \\( jwt . payload . name ) ! } This snippet creates a new route at GET /hello . The first part of the route handler fetches the token value from the bearer authorization header. The second part uses the JWT struct to parse the token using an HS256 signer. Once the JWT is parsed, we access the payload property which contains an instance of our User type. We then access the name property to say hello! Run the following request and check the output: GET /hello HTTP / 1.1 Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM Content-Length : 0 You should see the following response: HTTP / 1.1 200 OK Content-Length : 23 Hello, Vapor Developer!","title":"Route"},{"location":"jwt/overview/#serialize","text":"Let's take a look at how to create and sign a JWT.","title":"Serialize"},{"location":"jwt/overview/#payload_2","text":"First, we need to create a Codable type that represents our payload. This should also conform to JWTPayload . struct User : JWTPayload { var id : Int var name : String func verify ( using signer : JWTSigner ) throws { // nothing to verify } } Since our simple payload does not include any claims, we can leave the verify(using:) method empty for now.","title":"Payload"},{"location":"jwt/overview/#route_1","text":"Now that our payload type is ready, we can generate a JWT. router . post ( login ) { req - String in // create payload let user = User ( id : 42 , name : Vapor Developer ) // create JWT and sign let data = try JWT ( payload : user ). sign ( using : . hs256 ( key : secret )) return String ( data : data , encoding : . utf8 ) ?? } This snippet creates a new route at POST /login . The first part of the route handler creates an instance of our User payload type. The second part creates an instance of JWT using our payload, and calls the sign(using:) method. This method returns Data , which we convert to a String . If you visit this route, you should get the following output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsIm5hbWUiOiJWYXBvciBEZXZlbG9wZXIifQ.__Dm_tr1Ky2VYhZNoN6XpEkaRHjtRgaM6HdgDFcc9PM If you plug that JWT into jwt.io and enter the secret ( secret ), you should see the encoded data and a message \"Signature Verified\".","title":"Route"},{"location":"leaf/custom-tags/","text":"Custom Tags You can create custom Leaf tags using the TagRenderer protocol. To demonstrate this, let's take a look at creating a custom tag #now that prints the current timestamp. The tag will also support a single, optional parameter for specifying the date format. Tag Renderer First create a class called NowTag and conform it to TagRenderer . final class NowTag : TagRenderer { init () { } func render ( tag : TagContext ) throws - EventLoopFuture TemplateData { ... } } Now let's implement the render(tag:) method. The TagContext context passed to this method has everything we should need. let formatter = DateFormatter () switch tag . parameters . count { case 0 : formatter . dateFormat = yyyy-MM-dd HH:mm:ss case 1 : guard let string = tag . parameters [ 0 ]. string else { throw ... } formatter . dateFormat = string default : throw ... } let string = formatter . string ( from : . init ()) return tag . container . future (. string ( string )) Configure Tag Now that we've implemented NowTag , we just need to configure it. You can configure any TagRenderer like this--even if they come from a separate package. services . register { container - LeafTagConfig in var config = LeafTagConfig . default () config . use ( NowTag (), as : now ) return config } And that's it! We can now use our custom tag in Leaf. The time is #now ( )","title":"Custom tags"},{"location":"leaf/custom-tags/#custom-tags","text":"You can create custom Leaf tags using the TagRenderer protocol. To demonstrate this, let's take a look at creating a custom tag #now that prints the current timestamp. The tag will also support a single, optional parameter for specifying the date format.","title":"Custom Tags"},{"location":"leaf/custom-tags/#tag-renderer","text":"First create a class called NowTag and conform it to TagRenderer . final class NowTag : TagRenderer { init () { } func render ( tag : TagContext ) throws - EventLoopFuture TemplateData { ... } } Now let's implement the render(tag:) method. The TagContext context passed to this method has everything we should need. let formatter = DateFormatter () switch tag . parameters . count { case 0 : formatter . dateFormat = yyyy-MM-dd HH:mm:ss case 1 : guard let string = tag . parameters [ 0 ]. string else { throw ... } formatter . dateFormat = string default : throw ... } let string = formatter . string ( from : . init ()) return tag . container . future (. string ( string ))","title":"Tag Renderer"},{"location":"leaf/custom-tags/#configure-tag","text":"Now that we've implemented NowTag , we just need to configure it. You can configure any TagRenderer like this--even if they come from a separate package. services . register { container - LeafTagConfig in var config = LeafTagConfig . default () config . use ( NowTag (), as : now ) return config } And that's it! We can now use our custom tag in Leaf. The time is #now ( )","title":"Configure Tag"},{"location":"leaf/getting-started/","text":"Leaf Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API. Package The first step to using Leaf is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/leaf.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Leaf , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Configure Once you have added the package to your project, you can configure Vapor to use it. This is usually done in configure.swift . import Leaf try services . register ( LeafProvider ()) If your application supports multiple view renderers, you may need to specify that you would like to use Leaf. config . prefer ( LeafRenderer . self , for : ViewRenderer . self ) Folder Structure Once you have configured Leaf, you will need to ensure you have a Views folder to store your .leaf files in. By default, Leaf expects the views folder to be a ./Resources/Views relative to your project's root. You will also likely want to enable Vapor's FileMiddleware to serve files from your /Public folder. VaporApp \u251c\u2500\u2500 Package.swift \u251c\u2500\u2500 Resources \u2502 \u251c\u2500\u2500 Views \u2502 \u2502 \u2514\u2500\u2500 hello.leaf \u251c\u2500\u2500 Public \u2502 \u251c\u2500\u2500 images (images resources) \u2502 \u251c\u2500\u2500 styles (css resources) \u2514\u2500\u2500 Sources \u2514\u2500\u2500 ... Syntax Highlighting You may also wish to install one of these third-party packages that provide support for syntax highlighting in Leaf templates. Sublime Install the package Leaf from package control. Atom language-leaf by ButkiewiczP Xcode It is not currently possible to implement Leaf Syntax Highlighting in Xcode, however, using Xcode's HTML Syntax Coloring can help a bit. Select one or more Leaf files and then choose Editor Syntax Coloring HTML. Your selected Leaf files will now use Xcode's HTML Syntax Coloring. Unfortunately the usefulness of this is limited because this association will be removed when vapor xcode is run. There appears to be a way to make Xcode file associations persist but that requires a bit more kung-fu. VS Code html-leaf by FranciscoAmado CLion AppCode Some preliminary work has been done to implement a Leaf Plugin for CLion AppCode but lack of skill and interest in Java has slowed progress! If you have IntelliJ SDK experience and want to help with this, message Tom Holland on Vapor Slack Rendering a View Now that Leaf is configured, let's render your first template. Inside of the Resources/Views folder, create a new file called hello.leaf with the following contents: Hello, # ( name) ! Then, register a route (usually done in routes.swift or a controller) to render the view. import Leaf router . get ( hello ) { req - Future View in return try req . view (). render ( hello , [ name : Leaf ]) } Open your browser and visit /hello . You should see Hello, Leaf! . Congratulations on rendering your first Leaf view!","title":"Getting Started"},{"location":"leaf/getting-started/#leaf","text":"Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API.","title":"Leaf"},{"location":"leaf/getting-started/#package","text":"The first step to using Leaf is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... . package ( url : https://github.com/vapor/leaf.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Leaf , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] )","title":"Package"},{"location":"leaf/getting-started/#configure","text":"Once you have added the package to your project, you can configure Vapor to use it. This is usually done in configure.swift . import Leaf try services . register ( LeafProvider ()) If your application supports multiple view renderers, you may need to specify that you would like to use Leaf. config . prefer ( LeafRenderer . self , for : ViewRenderer . self )","title":"Configure"},{"location":"leaf/getting-started/#folder-structure","text":"Once you have configured Leaf, you will need to ensure you have a Views folder to store your .leaf files in. By default, Leaf expects the views folder to be a ./Resources/Views relative to your project's root. You will also likely want to enable Vapor's FileMiddleware to serve files from your /Public folder. VaporApp \u251c\u2500\u2500 Package.swift \u251c\u2500\u2500 Resources \u2502 \u251c\u2500\u2500 Views \u2502 \u2502 \u2514\u2500\u2500 hello.leaf \u251c\u2500\u2500 Public \u2502 \u251c\u2500\u2500 images (images resources) \u2502 \u251c\u2500\u2500 styles (css resources) \u2514\u2500\u2500 Sources \u2514\u2500\u2500 ...","title":"Folder Structure"},{"location":"leaf/getting-started/#syntax-highlighting","text":"You may also wish to install one of these third-party packages that provide support for syntax highlighting in Leaf templates.","title":"Syntax Highlighting"},{"location":"leaf/getting-started/#sublime","text":"Install the package Leaf from package control.","title":"Sublime"},{"location":"leaf/getting-started/#atom","text":"language-leaf by ButkiewiczP","title":"Atom"},{"location":"leaf/getting-started/#xcode","text":"It is not currently possible to implement Leaf Syntax Highlighting in Xcode, however, using Xcode's HTML Syntax Coloring can help a bit. Select one or more Leaf files and then choose Editor Syntax Coloring HTML. Your selected Leaf files will now use Xcode's HTML Syntax Coloring. Unfortunately the usefulness of this is limited because this association will be removed when vapor xcode is run. There appears to be a way to make Xcode file associations persist but that requires a bit more kung-fu.","title":"Xcode"},{"location":"leaf/getting-started/#vs-code","text":"html-leaf by FranciscoAmado","title":"VS Code"},{"location":"leaf/getting-started/#clion-appcode","text":"Some preliminary work has been done to implement a Leaf Plugin for CLion AppCode but lack of skill and interest in Java has slowed progress! If you have IntelliJ SDK experience and want to help with this, message Tom Holland on Vapor Slack","title":"CLion & AppCode"},{"location":"leaf/getting-started/#rendering-a-view","text":"Now that Leaf is configured, let's render your first template. Inside of the Resources/Views folder, create a new file called hello.leaf with the following contents: Hello, # ( name) ! Then, register a route (usually done in routes.swift or a controller) to render the view. import Leaf router . get ( hello ) { req - Future View in return try req . view (). render ( hello , [ name : Leaf ]) } Open your browser and visit /hello . You should see Hello, Leaf! . Congratulations on rendering your first Leaf view!","title":"Rendering a View"},{"location":"leaf/overview/","text":"Leaf Overview Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API. This guide will give you an overview of Leaf's syntax and the available tags. Template syntax Here is an example of a basic Leaf tag usage. There are #count ( users) users. Leaf tags are made up of four elements: Token # : This signals the leaf parser to begin looking for a tag. Name count : that identifies the tag. Parameter List (users) : May accept zero or more arguments. Body: An optional body can be supplied to some tags. This is similar to Swift's trailing-closure syntax. There can be many different usages of these four elements depending on the tag's implementation. Let's look at a few examples of how Leaf's built-in tags might be used: # ( variable) #embed ( template ) #set ( title ) { Welcome to Vapor } #count ( friends) #for ( friend in friends) { li # ( friend . name) /li } Leaf also supports many expressions you are familiar with in Swift. + == || etc. #if ( 1 + 1 == 2 ) { Hello! } Context In the example from Getting Started , we used a [String: String] dictionary to pass data to Leaf. However, you can pass anything that conforms to Encodable . It's actually preferred to use Encodable structs since [String: Any] is not supported. struct WelcomeContext : Encodable { var title : String var number : Int } return try req . view (). make ( home , WelcomeContext ( title : Hello! , number : 42 )) That will expose title and message to our Leaf template, which can then be used inside tags. For example: h1 # ( title) /h1 p # ( number) /p Usage Here are some common Leaf usage examples. Conditions Leaf is able to evaluate a range of conditions using its #if tag. For example, if you provide a variable it will check that variable exists in its context: #if ( title) { The title is # ( title) } else { No title was provided. } You can also write comparisons, for example: #if ( title == Welcome ) { This is a friendly web page. } else { No strangers allowed! } If you want to use another tag as part of your condition, you should omit the # for the inner tag. For example: #if ( lowercase (title) == welcome ) { This is a friendly web page. } else { No strangers allowed! } Just like in Swift, you can also use else if statement.s #if ( title == Welcome ) { This is a friendly web page. } else if ( 1 == 2 ) { What? } else { No strangers allowed! } Loops If you provide an array of items, Leaf can loop over them and let you manipulate each item individually using its #for tag. For example, we could update our Swift code to provide a list of planets: struct SolarSystem : Codable { let planets = [ Venus , Earth , Mars ] } return try req . view (). render (..., SolarSystem ()) We could then loop over them in Leaf like this: Planets: ul #for ( planet in planets) { li # ( planet) /li } /ul This would render a view that looks like: Planets: - Venus - Earth - Mars Leaf provides some extra variables inside a #for loop to give you more information about the loop's progress: The isFirst variable is true when the current iteration is the first one. The isLast variable is true when it's the last iteration. The index variable will be set to the number of the current iteration, counting from 0. Here's how we could use a loop variable to print just the first name in our array: #for ( planet in planets) { #if ( isFirst) { # ( planet) is first! } } Embedding templates Leaf\u2019s #embed tag allows you to copy the contents of one template into another. When use this, you should always omit the template file's .leaf extension. Embedding is useful for copying in a standard piece of content, for example a page footer or advert code: #embed ( footer ) This tag is also useful for building one template on top of another. For example, you might have a master.leaf file that includes all the code required to lay out your website \u2013 HTML structure, CSS and JavaScript \u2013 with some gaps in place that represent where page content varies. Using this approach, you would construct a child template that fills in its unique content, then embeds the parent template that places the content appropriately. For example, you might create a child.leaf template like this: #set ( body ) { p Welcome to Vapor! /p } #embed ( master ) That configures one item of context, body , but doesn\u2019t display it directly. Instead, it embeds master.leaf, which can render body along with any other context variables passed in from Swift. For example, master.leaf might look like this: html head title # ( title) /title /head body #get ( body) /body /html When given the context [\"title\": \"Hi there!\"] , child.leaf will render as follows: html head title Hi there! / title / head body p Welcome to Vapor! / p / body / html Comments You can write single or multiline comments with Leaf. They will be discarded when rendering the view. #// Say hello to the user Hello, # ( name) ! Multi-line comments are opened with #/* and closed with */ . #/* Say hello to the user */ Hello, # ( name) ! Other tags #date The #date tag formats dates into a readable string. render (..., [ now : Date ()]) The time is #date ( now) You can pass a custom date formatter string as the second argument. See Swift's DateFormatter for more information. The date is #date ( now, yyyy-MM-dd ) #capitalize The #capitalize tag uppercases the first letter of any string. #capitalize ( name) #contains The #contains tag accepts an array and a value as its two parameters, and returns true if the array in parameter one contains the value in parameter two. #if ( contains (planets, Earth )) { Earth is here! } else { Earth is not in this array. } #count The #count tag returns the number of items in an array. For example: Your search matched #count ( matches) pages. #lowercase The #lowercase tag lowercases all letters in a string. #lowercase ( name) #uppercase The #uppercase tag uppercases all letters in a string. #uppercase ( name)","title":"Overview"},{"location":"leaf/overview/#leaf-overview","text":"Leaf is a powerful templating language with Swift-inspired syntax. You can use it to generate dynamic HTML pages for a front-end website or generate rich emails to send from an API. This guide will give you an overview of Leaf's syntax and the available tags.","title":"Leaf Overview"},{"location":"leaf/overview/#template-syntax","text":"Here is an example of a basic Leaf tag usage. There are #count ( users) users. Leaf tags are made up of four elements: Token # : This signals the leaf parser to begin looking for a tag. Name count : that identifies the tag. Parameter List (users) : May accept zero or more arguments. Body: An optional body can be supplied to some tags. This is similar to Swift's trailing-closure syntax. There can be many different usages of these four elements depending on the tag's implementation. Let's look at a few examples of how Leaf's built-in tags might be used: # ( variable) #embed ( template ) #set ( title ) { Welcome to Vapor } #count ( friends) #for ( friend in friends) { li # ( friend . name) /li } Leaf also supports many expressions you are familiar with in Swift. + == || etc. #if ( 1 + 1 == 2 ) { Hello! }","title":"Template syntax"},{"location":"leaf/overview/#context","text":"In the example from Getting Started , we used a [String: String] dictionary to pass data to Leaf. However, you can pass anything that conforms to Encodable . It's actually preferred to use Encodable structs since [String: Any] is not supported. struct WelcomeContext : Encodable { var title : String var number : Int } return try req . view (). make ( home , WelcomeContext ( title : Hello! , number : 42 )) That will expose title and message to our Leaf template, which can then be used inside tags. For example: h1 # ( title) /h1 p # ( number) /p","title":"Context"},{"location":"leaf/overview/#usage","text":"Here are some common Leaf usage examples.","title":"Usage"},{"location":"leaf/overview/#conditions","text":"Leaf is able to evaluate a range of conditions using its #if tag. For example, if you provide a variable it will check that variable exists in its context: #if ( title) { The title is # ( title) } else { No title was provided. } You can also write comparisons, for example: #if ( title == Welcome ) { This is a friendly web page. } else { No strangers allowed! } If you want to use another tag as part of your condition, you should omit the # for the inner tag. For example: #if ( lowercase (title) == welcome ) { This is a friendly web page. } else { No strangers allowed! } Just like in Swift, you can also use else if statement.s #if ( title == Welcome ) { This is a friendly web page. } else if ( 1 == 2 ) { What? } else { No strangers allowed! }","title":"Conditions"},{"location":"leaf/overview/#loops","text":"If you provide an array of items, Leaf can loop over them and let you manipulate each item individually using its #for tag. For example, we could update our Swift code to provide a list of planets: struct SolarSystem : Codable { let planets = [ Venus , Earth , Mars ] } return try req . view (). render (..., SolarSystem ()) We could then loop over them in Leaf like this: Planets: ul #for ( planet in planets) { li # ( planet) /li } /ul This would render a view that looks like: Planets: - Venus - Earth - Mars Leaf provides some extra variables inside a #for loop to give you more information about the loop's progress: The isFirst variable is true when the current iteration is the first one. The isLast variable is true when it's the last iteration. The index variable will be set to the number of the current iteration, counting from 0. Here's how we could use a loop variable to print just the first name in our array: #for ( planet in planets) { #if ( isFirst) { # ( planet) is first! } }","title":"Loops"},{"location":"leaf/overview/#embedding-templates","text":"Leaf\u2019s #embed tag allows you to copy the contents of one template into another. When use this, you should always omit the template file's .leaf extension. Embedding is useful for copying in a standard piece of content, for example a page footer or advert code: #embed ( footer ) This tag is also useful for building one template on top of another. For example, you might have a master.leaf file that includes all the code required to lay out your website \u2013 HTML structure, CSS and JavaScript \u2013 with some gaps in place that represent where page content varies. Using this approach, you would construct a child template that fills in its unique content, then embeds the parent template that places the content appropriately. For example, you might create a child.leaf template like this: #set ( body ) { p Welcome to Vapor! /p } #embed ( master ) That configures one item of context, body , but doesn\u2019t display it directly. Instead, it embeds master.leaf, which can render body along with any other context variables passed in from Swift. For example, master.leaf might look like this: html head title # ( title) /title /head body #get ( body) /body /html When given the context [\"title\": \"Hi there!\"] , child.leaf will render as follows: html head title Hi there! / title / head body p Welcome to Vapor! / p / body / html","title":"Embedding templates"},{"location":"leaf/overview/#comments","text":"You can write single or multiline comments with Leaf. They will be discarded when rendering the view. #// Say hello to the user Hello, # ( name) ! Multi-line comments are opened with #/* and closed with */ . #/* Say hello to the user */ Hello, # ( name) !","title":"Comments"},{"location":"leaf/overview/#other-tags","text":"","title":"Other tags"},{"location":"leaf/overview/#date","text":"The #date tag formats dates into a readable string. render (..., [ now : Date ()]) The time is #date ( now) You can pass a custom date formatter string as the second argument. See Swift's DateFormatter for more information. The date is #date ( now, yyyy-MM-dd )","title":"#date"},{"location":"leaf/overview/#capitalize","text":"The #capitalize tag uppercases the first letter of any string. #capitalize ( name)","title":"#capitalize"},{"location":"leaf/overview/#contains","text":"The #contains tag accepts an array and a value as its two parameters, and returns true if the array in parameter one contains the value in parameter two. #if ( contains (planets, Earth )) { Earth is here! } else { Earth is not in this array. }","title":"#contains"},{"location":"leaf/overview/#count","text":"The #count tag returns the number of items in an array. For example: Your search matched #count ( matches) pages.","title":"#count"},{"location":"leaf/overview/#lowercase","text":"The #lowercase tag lowercases all letters in a string. #lowercase ( name)","title":"#lowercase"},{"location":"leaf/overview/#uppercase","text":"The #uppercase tag uppercases all letters in a string. #uppercase ( name)","title":"#uppercase"},{"location":"logging/getting-started/","text":"Getting Started with Logging The Logging module is provided as a part of Vapor's Console package ( vapor/console ). This module provides convenience APIs for creating log Tip For an in-depth look at all of Logging's APIs, check out the Logging API docs . Usage This package is included with Vapor and exported by default. You will have access to all Logging APIs when you import Vapor . import Vapor // implies import Logging Standalone The Logging module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Logging , ... ]) ] ) Use import Logging to access the APIs. Overview Continue to Logging \u2192 Overview for an overview of Logging's features.","title":"Getting Started"},{"location":"logging/getting-started/#getting-started-with-logging","text":"The Logging module is provided as a part of Vapor's Console package ( vapor/console ). This module provides convenience APIs for creating log Tip For an in-depth look at all of Logging's APIs, check out the Logging API docs .","title":"Getting Started with Logging"},{"location":"logging/getting-started/#usage","text":"This package is included with Vapor and exported by default. You will have access to all Logging APIs when you import Vapor . import Vapor // implies import Logging","title":"Usage"},{"location":"logging/getting-started/#standalone","text":"The Logging module, part of the larger Vapor Console package, can also be used on its own with any Swift project. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... /// \ud83d\udcbb APIs for creating interactive CLI tools. . package ( url : https://github.com/vapor/console.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Logging , ... ]) ] ) Use import Logging to access the APIs.","title":"Standalone"},{"location":"logging/getting-started/#overview","text":"Continue to Logging \u2192 Overview for an overview of Logging's features.","title":"Overview"},{"location":"logging/overview/","text":"Logging Overview The logging package provides convenience APIs for logging information while your app is running. The Logger protocol declares a common interface for logging information. A default PrintLogger is available, but you can implement custom loggers to suit your specific needs. Log First, you will want to use a Container to create an instance of Logger . Then you can use the convenience methods to log information. let logger = try req . make ( Logger . self ) logger . info ( Logger created! ) See Logger in the API docs for a list of all available methods. Check out Service Services for more information on how to register a custom logger.","title":"Overview"},{"location":"logging/overview/#logging-overview","text":"The logging package provides convenience APIs for logging information while your app is running. The Logger protocol declares a common interface for logging information. A default PrintLogger is available, but you can implement custom loggers to suit your specific needs.","title":"Logging Overview"},{"location":"logging/overview/#log","text":"First, you will want to use a Container to create an instance of Logger . Then you can use the convenience methods to log information. let logger = try req . make ( Logger . self ) logger . info ( Logger created! ) See Logger in the API docs for a list of all available methods. Check out Service Services for more information on how to register a custom logger.","title":"Log"},{"location":"multipart/getting-started/","text":"Getting Started with Multipart Multipart ( vapor/multipart ) is a small package that helps you parse and serialize multipart encoded data. Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. The Multipart package makes it easy to use this encoding by integrating directly with Codable . Vapor This package is included with Vapor and exported by default. You will have access to all Multipart APIs when you import Vapor . import Vapor Standalone The Multipart package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with multipart-encoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/multipart.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Multipart , ... ]) ] ) Use import Multipart to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Multipart package in general. Visit the API Docs for Multipart-specific API info.","title":"Getting Started"},{"location":"multipart/getting-started/#getting-started-with-multipart","text":"Multipart ( vapor/multipart ) is a small package that helps you parse and serialize multipart encoded data. Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. The Multipart package makes it easy to use this encoding by integrating directly with Codable .","title":"Getting Started with Multipart"},{"location":"multipart/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Multipart APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"multipart/getting-started/#standalone","text":"The Multipart package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with multipart-encoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/multipart.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Multipart , ... ]) ] ) Use import Multipart to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Multipart package in general. Visit the API Docs for Multipart-specific API info.","title":"Standalone"},{"location":"multipart/overview/","text":"Using Multipart Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. It allows for arbitrary data to be encoded in each part thanks to a unique delimiter boundary that is defined separately. This boundary is guaranteed by the client to not appear anywhere in the data. Multipart is a powerful encoding, however it is rarely used in its base format. Most commonly, multipart/form-data is used. This encoding adds a \"name\" property to each part of the multipart data. This is required for serializing web forms. For the rest of this guide, assume we are talking about multipart/form-data unless otherwise specified. Tip Multipart integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a multipart/form-data -encoded request. Decode Most often, you will be decoding multipart/form-data -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like. Request Here is an example multipart/form-data -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : multipart/form-data; boundary=123 --123 Content-Disposition: form-data; name= name Vapor --123 Content-Disposition: form-data; name= age 3 --123 Content-Disposition: form-data; name= image ; filename= droplet.png contents of image --123-- You can see the multipart data uses a boundary (in this case it is \"123\" ) to separate the data. This will usually be a longer string. The client sending a multipart-encoded request must ensure that the boundary it supplies does not appear anywhere in the content it is sending you. That's what allows this encoding to be used to send things like files. Form There are many ways to create a multipart-encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users enctype = multipart/form-data input type = text name = name input type = text name = age input type = file name = image / form Take note of the enctype attribute on the form as well as the file type input. This is what allows us to send files via the web form. Content Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var image : Data } Tip You can use File instead of Data if you would also like to access the filename. Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . image ) // Raw image data return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work! Encode APIs encode multipart data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a multipart-encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , image : Data (...)) res . content . encode ( user , as : . formData ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure. Parsing Serializing The Multipart package also offers APIs for parsing and serializing multipart/form-data data without using Codable . Check out the API Docs for more information on using those APIs.","title":"Overview"},{"location":"multipart/overview/#using-multipart","text":"Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. It allows for arbitrary data to be encoded in each part thanks to a unique delimiter boundary that is defined separately. This boundary is guaranteed by the client to not appear anywhere in the data. Multipart is a powerful encoding, however it is rarely used in its base format. Most commonly, multipart/form-data is used. This encoding adds a \"name\" property to each part of the multipart data. This is required for serializing web forms. For the rest of this guide, assume we are talking about multipart/form-data unless otherwise specified. Tip Multipart integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a multipart/form-data -encoded request.","title":"Using Multipart"},{"location":"multipart/overview/#decode","text":"Most often, you will be decoding multipart/form-data -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like.","title":"Decode"},{"location":"multipart/overview/#request","text":"Here is an example multipart/form-data -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : multipart/form-data; boundary=123 --123 Content-Disposition: form-data; name= name Vapor --123 Content-Disposition: form-data; name= age 3 --123 Content-Disposition: form-data; name= image ; filename= droplet.png contents of image --123-- You can see the multipart data uses a boundary (in this case it is \"123\" ) to separate the data. This will usually be a longer string. The client sending a multipart-encoded request must ensure that the boundary it supplies does not appear anywhere in the content it is sending you. That's what allows this encoding to be used to send things like files.","title":"Request"},{"location":"multipart/overview/#form","text":"There are many ways to create a multipart-encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users enctype = multipart/form-data input type = text name = name input type = text name = age input type = file name = image / form Take note of the enctype attribute on the form as well as the file type input. This is what allows us to send files via the web form.","title":"Form"},{"location":"multipart/overview/#content","text":"Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var image : Data } Tip You can use File instead of Data if you would also like to access the filename. Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . image ) // Raw image data return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work!","title":"Content"},{"location":"multipart/overview/#encode","text":"APIs encode multipart data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a multipart-encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , image : Data (...)) res . content . encode ( user , as : . formData ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure.","title":"Encode"},{"location":"multipart/overview/#parsing-serializing","text":"The Multipart package also offers APIs for parsing and serializing multipart/form-data data without using Codable . Check out the API Docs for more information on using those APIs.","title":"Parsing & Serializing"},{"location":"mysql/getting-started/","text":"MySQL MySQL ( vapor/mysql ) is a pure Swift MySQL (and MariaDB) client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the MySQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. MySQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent MySQL , all of the features of MySQL core will be available to you. Getting Started Let's take a look at how you can get started using MySQL core. Package The first step to using MySQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc2c Pure Swift MySQL client built on non-blocking, event-driven sockets. . package ( url : https://github.com/vapor/mysql.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ MySQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Config The next step is to configure the database in configure.swift . import MySQL /// Register providers first try services . register ( MySQLProvider ()) Registering the provider will add all of the services required for MySQL to work properly. It also includes a default database config struct that uses standard credentials. Customizing Config You can of course override the default configuration provided by MySQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a MySQL database let mysql = try MySQLDatabase ( config : MySQLDatabaseConfig (...)) /// Register the configured MySQL database to the database config. var databases = DatabasesConfig () databases . add ( database : mysql , as : . mysql ) services . register ( databases ) See MySQLDatabase and MySQLDatabaseConfig for more information. MySQL's default database identifier is .mysql . You can create a custom identifier if you want by extending DatabaseIdentifier . Query Now that the database is configured, you can make your first query. struct MySQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . mysql ) { conn in return conn . raw ( SELECT @@version as version ) . all ( decoding : MySQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your MySQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit MySQL's API docs for detailed information about all available types and methods.","title":"Getting Started"},{"location":"mysql/getting-started/#mysql","text":"MySQL ( vapor/mysql ) is a pure Swift MySQL (and MariaDB) client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the MySQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. MySQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent MySQL , all of the features of MySQL core will be available to you.","title":"MySQL"},{"location":"mysql/getting-started/#getting-started","text":"Let's take a look at how you can get started using MySQL core.","title":"Getting Started"},{"location":"mysql/getting-started/#package","text":"The first step to using MySQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc2c Pure Swift MySQL client built on non-blocking, event-driven sockets. . package ( url : https://github.com/vapor/mysql.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ MySQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"mysql/getting-started/#config","text":"The next step is to configure the database in configure.swift . import MySQL /// Register providers first try services . register ( MySQLProvider ()) Registering the provider will add all of the services required for MySQL to work properly. It also includes a default database config struct that uses standard credentials.","title":"Config"},{"location":"mysql/getting-started/#customizing-config","text":"You can of course override the default configuration provided by MySQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a MySQL database let mysql = try MySQLDatabase ( config : MySQLDatabaseConfig (...)) /// Register the configured MySQL database to the database config. var databases = DatabasesConfig () databases . add ( database : mysql , as : . mysql ) services . register ( databases ) See MySQLDatabase and MySQLDatabaseConfig for more information. MySQL's default database identifier is .mysql . You can create a custom identifier if you want by extending DatabaseIdentifier .","title":"Customizing Config"},{"location":"mysql/getting-started/#query","text":"Now that the database is configured, you can make your first query. struct MySQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . mysql ) { conn in return conn . raw ( SELECT @@version as version ) . all ( decoding : MySQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your MySQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit MySQL's API docs for detailed information about all available types and methods.","title":"Query"},{"location":"postgresql/getting-started/","text":"PostgreSQL PostgreSQL ( vapor/postgresql ) is a pure Swift PostgreSQL client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the PostgreSQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. PostgreSQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent PostgreSQL , all of the features of PostgreSQL core will be available to you. Getting Started Let's take a look at how you can get started using PostgreSQL core. Package The first step to using PostgreSQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc18 Non-blocking, event-driven Swift client for PostgreSQL. . package ( url : https://github.com/vapor/postgresql.git , from : 1.0.0 ), ], targets : [ . target ( name : App , dependencies : [ PostgreSQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Config The next step is to configure the database in configure.swift . import PostgreSQL /// Register providers first try services . register ( PostgreSQLProvider ()) Registering the provider will add all of the services required for PostgreSQL to work properly. It also includes a default database config struct that uses standard credentials. Customizing Config You can of course override the default configuration provided by PostgreSQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a PostgreSQL database let postgresql = try PostgreSQLDatabase ( config : PostgreSQLDatabaseConfig (...)) /// Register the configured PostgreSQL database to the database config. var databases = DatabasesConfig () databases . add ( database : postgresql , as : . psql ) services . register ( databases ) See PostgreSQLDatabase and PostgreSQLDatabaseConfig for more information. PostgreSQL's default database identifier is .psql . You can create a custom identifier if you want by extending DatabaseIdentifier . Query Now that the database is configured, you can make your first query. struct PostgreSQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . psql ) { conn in return conn . raw ( SELECT version() ) . all ( decoding : PostgreSQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your PostgreSQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit PostgreSQL's API docs for detailed information about all available types and methods.","title":"Getting Started"},{"location":"postgresql/getting-started/#postgresql","text":"PostgreSQL ( vapor/postgresql ) is a pure Swift PostgreSQL client built on top of SwiftNIO . The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the PostgreSQL package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. PostgreSQL core extends DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent PostgreSQL , all of the features of PostgreSQL core will be available to you.","title":"PostgreSQL"},{"location":"postgresql/getting-started/#getting-started","text":"Let's take a look at how you can get started using PostgreSQL core.","title":"Getting Started"},{"location":"postgresql/getting-started/#package","text":"The first step to using PostgreSQL core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udc18 Non-blocking, event-driven Swift client for PostgreSQL. . package ( url : https://github.com/vapor/postgresql.git , from : 1.0.0 ), ], targets : [ . target ( name : App , dependencies : [ PostgreSQL , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"postgresql/getting-started/#config","text":"The next step is to configure the database in configure.swift . import PostgreSQL /// Register providers first try services . register ( PostgreSQLProvider ()) Registering the provider will add all of the services required for PostgreSQL to work properly. It also includes a default database config struct that uses standard credentials.","title":"Config"},{"location":"postgresql/getting-started/#customizing-config","text":"You can of course override the default configuration provided by PostgreSQLProvider if you'd like. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a PostgreSQL database let postgresql = try PostgreSQLDatabase ( config : PostgreSQLDatabaseConfig (...)) /// Register the configured PostgreSQL database to the database config. var databases = DatabasesConfig () databases . add ( database : postgresql , as : . psql ) services . register ( databases ) See PostgreSQLDatabase and PostgreSQLDatabaseConfig for more information. PostgreSQL's default database identifier is .psql . You can create a custom identifier if you want by extending DatabaseIdentifier .","title":"Customizing Config"},{"location":"postgresql/getting-started/#query","text":"Now that the database is configured, you can make your first query. struct PostgreSQLVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . psql ) { conn in return conn . raw ( SELECT version() ) . all ( decoding : PostgreSQLVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your PostgreSQL version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Learn more about building queries in SQL Getting Started . Visit PostgreSQL's API docs for detailed information about all available types and methods.","title":"Query"},{"location":"redis/getting-started/","text":"Getting Started with Redis Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface. Let's take a look at how you can get started using Redis. Package The first step to using Redis is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \u26a1\ufe0fNon-blocking, event-driven Redis client. . package ( url : https://github.com/vapor/redis.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Redis , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Provider Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Redis // register Redis provider try services . register ( RedisProvider ()) That's it for basic setup. The next step is to create a Redis connection and send a command. Command First, create a new connection to your Redis database. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. See DatabaseKit Overview for more information. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } Once you have a connection, you can use it to send a command. Let's send the \"INFO\" command which should return information about our Redis server. // send INFO command to redis return redis . command ( INFO ) // map the resulting RedisData to a String . map { $0 . string ?? } Run your app and query GET /redis . You should see information about your Redis server printed as output. Congratulations!","title":"Getting Started"},{"location":"redis/getting-started/#getting-started-with-redis","text":"Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface. Let's take a look at how you can get started using Redis.","title":"Getting Started with Redis"},{"location":"redis/getting-started/#package","text":"The first step to using Redis is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \u26a1\ufe0fNon-blocking, event-driven Redis client. . package ( url : https://github.com/vapor/redis.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ Redis , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] )","title":"Package"},{"location":"redis/getting-started/#provider","text":"Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in configure.swift . import Redis // register Redis provider try services . register ( RedisProvider ()) That's it for basic setup. The next step is to create a Redis connection and send a command.","title":"Provider"},{"location":"redis/getting-started/#command","text":"First, create a new connection to your Redis database. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. See DatabaseKit Overview for more information. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } Once you have a connection, you can use it to send a command. Let's send the \"INFO\" command which should return information about our Redis server. // send INFO command to redis return redis . command ( INFO ) // map the resulting RedisData to a String . map { $0 . string ?? } Run your app and query GET /redis . You should see information about your Redis server printed as output. Congratulations!","title":"Command"},{"location":"redis/overview/","text":"Using Redis Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface. Redis Commands Let's take a look at how to send and recieve data using Redis commands. Connection The first thing you will need to send a Redis command is a connection. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. For this example, we will use the withNewConnection(to:) method to create a new connection to Redis. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } See DatabaseKit Overview for more information. Available Commands See RedisClient for a list of all available commands. Here we'll take a look at some common commands. Get / Set Redis's GET and SET commands allow you to store and later retrieve data from the server. You can pass any Codable type as the value to this command. router . get ( set ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // save a new key/value pair to the cache return redis . set ( hello , to : world ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } router . get ( get ) { req - Future String in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . get ( hello , as : String . self ) // handle nil case . map { $0 ?? } } } Delete Redis's DELETE command allows you to clear a previously stored key/value pair. router . get ( del ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . delete ( hello ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } See RedisClient for a list of all available commands. Keyed Cache You can also use Redis as the backend to Vapor's KeyedCache protocol. router . get ( set ) { req - Future HTTPStatus in let string = try req . query . get ( String . self , at : string ) return try req . keyedCache ( for : . redis ). set ( string , to : string ) . transform ( to : . ok ) } router . get ( get ) { req - Future String in return try req . keyedCache ( for : . redis ). get ( string , as : String . self ) . unwrap ( or : Abort (. badRequest , reason : No string set yet. )) } See DatabaseKit Overview for more information.","title":"Overview"},{"location":"redis/overview/#using-redis","text":"Redis ( vapor/redis ) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO. You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's KeyedCache interface.","title":"Using Redis"},{"location":"redis/overview/#redis-commands","text":"Let's take a look at how to send and recieve data using Redis commands.","title":"Redis Commands"},{"location":"redis/overview/#connection","text":"The first thing you will need to send a Redis command is a connection. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. For this example, we will use the withNewConnection(to:) method to create a new connection to Redis. router . get ( redis ) { req - Future String in return req . withNewConnection ( to : . redis ) { redis in // use redis connection } } See DatabaseKit Overview for more information.","title":"Connection"},{"location":"redis/overview/#available-commands","text":"See RedisClient for a list of all available commands. Here we'll take a look at some common commands.","title":"Available Commands"},{"location":"redis/overview/#get-set","text":"Redis's GET and SET commands allow you to store and later retrieve data from the server. You can pass any Codable type as the value to this command. router . get ( set ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // save a new key/value pair to the cache return redis . set ( hello , to : world ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } router . get ( get ) { req - Future String in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . get ( hello , as : String . self ) // handle nil case . map { $0 ?? } } }","title":"Get / Set"},{"location":"redis/overview/#delete","text":"Redis's DELETE command allows you to clear a previously stored key/value pair. router . get ( del ) { req - Future HTTPStatus in // create a new redis connection return req . withNewConnection ( to : . redis ) { redis in // fetch the key/value pair from the cache, decoding a String return redis . delete ( hello ) // convert void future to HTTPStatus.ok . transform ( to : . ok ) } } See RedisClient for a list of all available commands.","title":"Delete"},{"location":"redis/overview/#keyed-cache","text":"You can also use Redis as the backend to Vapor's KeyedCache protocol. router . get ( set ) { req - Future HTTPStatus in let string = try req . query . get ( String . self , at : string ) return try req . keyedCache ( for : . redis ). set ( string , to : string ) . transform ( to : . ok ) } router . get ( get ) { req - Future String in return try req . keyedCache ( for : . redis ). get ( string , as : String . self ) . unwrap ( or : Abort (. badRequest , reason : No string set yet. )) } See DatabaseKit Overview for more information.","title":"Keyed Cache"},{"location":"routing/getting-started/","text":"Routing Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. For example, the routing package can help you route a request like the following and collect the values of the dynamic components. /users/:user_id/comments/:comment_id Vapor This package is included with Vapor and exported by default. You will have access to all Routing APIs when you import Vapor . Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See Getting Started Routing for more information. import Vapor Standalone The Routing package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a routing framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/routing.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Routing , ... ]) ] ) Use import Routing to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Routing package in general. Visit the API Docs for Routing-specific API info.","title":"Getting Started"},{"location":"routing/getting-started/#routing","text":"Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. For example, the routing package can help you route a request like the following and collect the values of the dynamic components. /users/:user_id/comments/:comment_id","title":"Routing"},{"location":"routing/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Routing APIs when you import Vapor . Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See Getting Started Routing for more information. import Vapor","title":"Vapor"},{"location":"routing/getting-started/#standalone","text":"The Routing package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a routing framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/routing.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Routing , ... ]) ] ) Use import Routing to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Routing package in general. Visit the API Docs for Routing-specific API info.","title":"Standalone"},{"location":"routing/overview/","text":"Routing Overview Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See [Vapor \u2192 Routing] for more information. This guide will show you how to register a static route and a dynamic route and how to use Parameter s. Register The first step to routing is to register some routes. Let's take a look at how to do that with a simple router a TrieRouter Double which holds numbers. Usually you would store something like HTTP responders, but we'll keep things simple for this example. // Create a router that stores Doubles let router = TrieRouter ( Double . self ) // Register some routes and values to the router router . register ( route : Route ( path : [ funny , meaning_of_universe ], output : 42 )) router . register ( route : Route ( path : [ funny , leet ], output : 1337 )) router . register ( route : Route ( path : [ math , pi ], output : 3.14 )) // Create empty Parameters to hold dynamic params (none yet) var params = Parameters () // Test fetching some routes print ( router . route ( path : [ fun , meaning_of_universe ], parameters : params )) // 42 print ( router . route ( path : [ foo ], parameters : params )) // nil Here we are using register(...) to register routes to our router, then later route(...) to fetch them. The TrieRouter uses a trie (digital tree) internally to make finding value in the router fast. Parameter Let's take a look at registering some dynamic path components. These are parts of the path that are variable and whose value should be collected for later use. You will often see this used for situations like show a webpage for a user: /users/:user_id Here is how you would implement that with TrieRouter . For this example, we will ignore the route output. // Create a route for /users/:user_id let user = Route ( path : [. constant ( users ), . parameter ( user_id )], output : ...) // Create a router and register our route let router = TrieRouter (...) router . register ( route : user ) // Create empty Parameters to hold dynamic values var params = Parameters () // Route the path /users/42 _ = router . route ( path : [ users , 42 ], parameters : params ) // The params contains our dynamic value! print ( params ) // [ user_id : 42 ] Note that the String used for .parameter(...) will be the key to fetch the value from Parameters . API Docs Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"Overview"},{"location":"routing/overview/#routing-overview","text":"Routing ( vapor/routing ) is a small framework for routing things like HTTP requests. It lets you register and lookup routes in a router using nested, dynamic path components. Tip If you use Vapor, most of Routing's APIs will be wrapped by more convenient methods. See [Vapor \u2192 Routing] for more information. This guide will show you how to register a static route and a dynamic route and how to use Parameter s.","title":"Routing Overview"},{"location":"routing/overview/#register","text":"The first step to routing is to register some routes. Let's take a look at how to do that with a simple router a TrieRouter Double which holds numbers. Usually you would store something like HTTP responders, but we'll keep things simple for this example. // Create a router that stores Doubles let router = TrieRouter ( Double . self ) // Register some routes and values to the router router . register ( route : Route ( path : [ funny , meaning_of_universe ], output : 42 )) router . register ( route : Route ( path : [ funny , leet ], output : 1337 )) router . register ( route : Route ( path : [ math , pi ], output : 3.14 )) // Create empty Parameters to hold dynamic params (none yet) var params = Parameters () // Test fetching some routes print ( router . route ( path : [ fun , meaning_of_universe ], parameters : params )) // 42 print ( router . route ( path : [ foo ], parameters : params )) // nil Here we are using register(...) to register routes to our router, then later route(...) to fetch them. The TrieRouter uses a trie (digital tree) internally to make finding value in the router fast.","title":"Register"},{"location":"routing/overview/#parameter","text":"Let's take a look at registering some dynamic path components. These are parts of the path that are variable and whose value should be collected for later use. You will often see this used for situations like show a webpage for a user: /users/:user_id Here is how you would implement that with TrieRouter . For this example, we will ignore the route output. // Create a route for /users/:user_id let user = Route ( path : [. constant ( users ), . parameter ( user_id )], output : ...) // Create a router and register our route let router = TrieRouter (...) router . register ( route : user ) // Create empty Parameters to hold dynamic values var params = Parameters () // Route the path /users/42 _ = router . route ( path : [ users , 42 ], parameters : params ) // The params contains our dynamic value! print ( params ) // [ user_id : 42 ] Note that the String used for .parameter(...) will be the key to fetch the value from Parameters .","title":"Parameter"},{"location":"routing/overview/#api-docs","text":"Check out the API docs for more in-depth information about all of the available parameters and methods.","title":"API Docs"},{"location":"service/getting-started/","text":"Getting Started with Service Service ( vapor/service ) is a dependency injection (inversion of control) framework. It allows you to register, configure, and create your application's dependencies in a maintainable way. /// register a service during boot services . register ( PrintLogger . self , as : Logger . self ) /// you can then create that service later let logger = try someContainer . make ( Logger . self ) print ( logger is PrintLogger ) // true You can read more about dependency injection on Wikipedia. Also be sure to check out the Getting Started Services guide. Vapor This package is included with Vapor and exported by default. You will have access to all Service APIs when you import Vapor . import Vapor Standalone The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a dependency injection framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/service.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Service , ... ]) ] ) Use import Service to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Services package in general. Visit the API Docs for Service-specific API info.","title":"Getting Started"},{"location":"service/getting-started/#getting-started-with-service","text":"Service ( vapor/service ) is a dependency injection (inversion of control) framework. It allows you to register, configure, and create your application's dependencies in a maintainable way. /// register a service during boot services . register ( PrintLogger . self , as : Logger . self ) /// you can then create that service later let logger = try someContainer . make ( Logger . self ) print ( logger is PrintLogger ) // true You can read more about dependency injection on Wikipedia. Also be sure to check out the Getting Started Services guide.","title":"Getting Started with Service"},{"location":"service/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Service APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"service/getting-started/#standalone","text":"The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a dependency injection framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/service.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Service , ... ]) ] ) Use import Service to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Services package in general. Visit the API Docs for Service-specific API info.","title":"Standalone"},{"location":"service/provider/","text":"Using Providers The Provider protocol make it easy to integrate external services into your application. All of Vapor's official packages, like Fluent , use the provider system to expose their services. Providers can: Register services to your Services struct. Hook into your Container 's lifecycle. Register Once you have added a Service-exposing SPM dependency to your project, adding the provider is easy. import Foo try services . register ( FooProvider ()) This is usually done in configure.swift . Note You can search GitHub for the vapor-service tag for a list of packages that expose services using this method. Create Creating a custom provider can be a great way to organize your code. You will also want to create a provider if you are working on a third-party package for Vapor. Here is what a simple provider would look like for the Logger examples from the Services section. public final class LoggerProvider : Provider { /// See `Provider`. public func register ( _ services : inout Services ) throws { services . register ( PrintLogger . self ) services . register ( FileLogger . self ) } /// See `Provider`. public func didBoot ( _ container : Container ) throws - Future Void { let logger = try container . make ( Logger . self ) logger . log ( Hello from LoggerProvider! ) return . done ( on : container ) } } Now when someone registers the LoggerProvider to their Services struct, it will automatically register the print and file loggers. When the container boots, the success message will be printed to verify the provider was added. See the Provider protocol's API docs for more information.","title":"Provider"},{"location":"service/provider/#using-providers","text":"The Provider protocol make it easy to integrate external services into your application. All of Vapor's official packages, like Fluent , use the provider system to expose their services. Providers can: Register services to your Services struct. Hook into your Container 's lifecycle.","title":"Using Providers"},{"location":"service/provider/#register","text":"Once you have added a Service-exposing SPM dependency to your project, adding the provider is easy. import Foo try services . register ( FooProvider ()) This is usually done in configure.swift . Note You can search GitHub for the vapor-service tag for a list of packages that expose services using this method.","title":"Register"},{"location":"service/provider/#create","text":"Creating a custom provider can be a great way to organize your code. You will also want to create a provider if you are working on a third-party package for Vapor. Here is what a simple provider would look like for the Logger examples from the Services section. public final class LoggerProvider : Provider { /// See `Provider`. public func register ( _ services : inout Services ) throws { services . register ( PrintLogger . self ) services . register ( FileLogger . self ) } /// See `Provider`. public func didBoot ( _ container : Container ) throws - Future Void { let logger = try container . make ( Logger . self ) logger . log ( Hello from LoggerProvider! ) return . done ( on : container ) } } Now when someone registers the LoggerProvider to their Services struct, it will automatically register the print and file loggers. When the container boots, the success message will be printed to verify the provider was added. See the Provider protocol's API docs for more information.","title":"Create"},{"location":"service/services/","text":"Using Services This guide will show you how to register, configure, and create your own service. In this example we will be assuming two different Logger implementations. PrintLogger : Prints logs. FileLogger : Saves logs to a file. Already conforms to ServiceType . Register Let's take a look at how we can register our PrintLogger . First you must conform your type to Service . The easiest way to do this is simply adding the conformance in an extension. extension PrintLogger : Service { } It's an empty protocol so there should be no missing requirements. Factory Now the service can be registered to the Services struct. This is usually done in configure.swift . services . register ( Logger . self ) { container in return PrintLogger () } By registering the PrintLogger using a factory (closure) method, we allow the Container to dynamically create the service once it is needed. Any SubContainer s created later can call this method again to create their own PrintLogger s. Service Type To make registering a service easier, you can conform it to ServiceType . extension PrintLogger : ServiceType { /// See `ServiceType`. static var serviceSupports : [ Any . Type ] { return [ Logger . self ] } /// See `ServiceType`. static func makeService ( for worker : Container ) throws - PrintLogger { return PrintLogger () } } Services conforming to ServiceType can be registered using just the type name. This will automatically conform to Service as well. services . register ( PrintLogger . self ) Instance You can also register pre-initialized instances to Services . services . register ( PrintLogger (), as : Logger . self ) Warning If using reference types ( class ) this method will share the same object between all Container s and SubContainer s. Be careful to protect against race conditions. Configure If more than one service is registered for a given interface, we will need to choose which service is used. services . register ( PrintLogger . self ) services . register ( FileLogger . self ) Assuming the above services are registered, we can use service Config to pick which one we want. switch env { case . production : config . prefer ( FileLogger . self , for : Logger . self ) default : config . prefer ( PrintLogger . self , for : Logger . self ) } Here we are using the Environment to dynamically prefer a service. This is usually done in configure.swift . Note You can also dynamically register services based on environment instead of using service config. However, service config is required for choosing services that come from the framework or a provider. Create After you have registered your services, you can use a Container to create them. let logger = try someContainer . make ( Logger . self ) logger . log ( Hello, world! ) // PrintLogger or FileLogger depending on the container s environment print ( type ( of : logger )) Tip Usually the framework will create any required containers for you. You can use BasicContainer if you want to create one for testing.","title":"Services"},{"location":"service/services/#using-services","text":"This guide will show you how to register, configure, and create your own service. In this example we will be assuming two different Logger implementations. PrintLogger : Prints logs. FileLogger : Saves logs to a file. Already conforms to ServiceType .","title":"Using Services"},{"location":"service/services/#register","text":"Let's take a look at how we can register our PrintLogger . First you must conform your type to Service . The easiest way to do this is simply adding the conformance in an extension. extension PrintLogger : Service { } It's an empty protocol so there should be no missing requirements.","title":"Register"},{"location":"service/services/#factory","text":"Now the service can be registered to the Services struct. This is usually done in configure.swift . services . register ( Logger . self ) { container in return PrintLogger () } By registering the PrintLogger using a factory (closure) method, we allow the Container to dynamically create the service once it is needed. Any SubContainer s created later can call this method again to create their own PrintLogger s.","title":"Factory"},{"location":"service/services/#service-type","text":"To make registering a service easier, you can conform it to ServiceType . extension PrintLogger : ServiceType { /// See `ServiceType`. static var serviceSupports : [ Any . Type ] { return [ Logger . self ] } /// See `ServiceType`. static func makeService ( for worker : Container ) throws - PrintLogger { return PrintLogger () } } Services conforming to ServiceType can be registered using just the type name. This will automatically conform to Service as well. services . register ( PrintLogger . self )","title":"Service Type"},{"location":"service/services/#instance","text":"You can also register pre-initialized instances to Services . services . register ( PrintLogger (), as : Logger . self ) Warning If using reference types ( class ) this method will share the same object between all Container s and SubContainer s. Be careful to protect against race conditions.","title":"Instance"},{"location":"service/services/#configure","text":"If more than one service is registered for a given interface, we will need to choose which service is used. services . register ( PrintLogger . self ) services . register ( FileLogger . self ) Assuming the above services are registered, we can use service Config to pick which one we want. switch env { case . production : config . prefer ( FileLogger . self , for : Logger . self ) default : config . prefer ( PrintLogger . self , for : Logger . self ) } Here we are using the Environment to dynamically prefer a service. This is usually done in configure.swift . Note You can also dynamically register services based on environment instead of using service config. However, service config is required for choosing services that come from the framework or a provider.","title":"Configure"},{"location":"service/services/#create","text":"After you have registered your services, you can use a Container to create them. let logger = try someContainer . make ( Logger . self ) logger . log ( Hello, world! ) // PrintLogger or FileLogger depending on the container s environment print ( type ( of : logger )) Tip Usually the framework will create any required containers for you. You can use BasicContainer if you want to create one for testing.","title":"Create"},{"location":"sql/getting-started/","text":"Getting Started with SQL SQL ( vapor/sql ) is a library for building and serializing SQL queries in Swift. It has an extensible, protocol-based design and supports DQL, DML, and DDL. Tip If you use Fluent, you will usually not need to build SQL queries manually. Choosing a Driver Vapor's SQL database packages are built on top of this library. database repo version dbid notes PostgreSQL postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. Once you have selected a driver and added it to your Package.swift file, you can continue following this guide.","title":"Getting Started"},{"location":"sql/getting-started/#getting-started-with-sql","text":"SQL ( vapor/sql ) is a library for building and serializing SQL queries in Swift. It has an extensible, protocol-based design and supports DQL, DML, and DDL. Tip If you use Fluent, you will usually not need to build SQL queries manually.","title":"Getting Started with SQL"},{"location":"sql/getting-started/#choosing-a-driver","text":"Vapor's SQL database packages are built on top of this library. database repo version dbid notes PostgreSQL postgresql 1.0.0 psql Recommended . Open source, standards compliant SQL database. Available on most cloud hosting providers. MySQL mysql 3.0.0 mysql Popular open source SQL database. Available on most cloud hosting providers. This driver also supports MariaDB. SQLite sqlite 3.0.0 sqlite Open source, embedded SQL database. Its simplistic nature makes it a great candiate for prototyping and testing. Once you have selected a driver and added it to your Package.swift file, you can continue following this guide.","title":"Choosing a Driver"},{"location":"sql/overview/","text":"Using SQL The SQL library helps you build and serialize SQL queries in Swift. It has an extensible, protocol-based design that supports many standard SQL queries like: SELECT , INSERT , UPDATE , DELETE CREATE TABLE , ALTER TABLE , DROP TABLE CREATE INDEX , DROP INDEX This package also integrates deeply with Codable and parameter binding to make working with your database fast and secure. This guide assumes you have already chosen and configured a driver in SQL Getting Started . In some cases, these SQL dialects will have different syntaxes or supported features. Be sure to check their API docs for additional functionality. Connection The first step to building a SQL query is getting access to a connection. Most often, you will use withPooledConnection(to:) followed by your database's dbid . Note Refer to the table in SQL Getting Started for your database's default dbid . The dbid allows you to use multiple databases per application. router . get ( sql ) { req in return req . withPooledConnection ( to : . # dbid # ) { conn in return // use conn to perform a query } } Check out Database Kit Overview Connections for more information. The rest of this guide will assume you have access to a SQL database connection. Select Use the select() method on a connection to create a SQLSelectBuilder . This builder helps you create SELECT statements and supports: * , columns, and expressions like functions FROM JOIN GROUP BY ORDER BY The select builder conforms to SQLPredicateBuilder for building WHERE predicates. It also conforms to SQLQueryFetcher for decoding Codable models from the result set. Let's take a look at an example SELECT query. Replace the Xcode placeholder with the name of the database you are using, i.e., SQLite . struct User : SQLTable , Codable { static let sqlTableIdentifierString = users let id : Int ? let name : String } let users = conn . select () . all (). from ( User . self ) . where ( \\ User . name == Vapor ) . all ( decoding : User . self ) print ( users ) // Future [User] The resulting SQL will look something like this: SELECT * FROM users WHERE users . name = ? As you can see, the Swift code reads similarly to actual SQL. Be sure to visit the API docs for the various builder protocols to see all available methods. API Docs Check out the API docs for more in-depth information about SQL's APIs.","title":"Overview"},{"location":"sql/overview/#using-sql","text":"The SQL library helps you build and serialize SQL queries in Swift. It has an extensible, protocol-based design that supports many standard SQL queries like: SELECT , INSERT , UPDATE , DELETE CREATE TABLE , ALTER TABLE , DROP TABLE CREATE INDEX , DROP INDEX This package also integrates deeply with Codable and parameter binding to make working with your database fast and secure. This guide assumes you have already chosen and configured a driver in SQL Getting Started . In some cases, these SQL dialects will have different syntaxes or supported features. Be sure to check their API docs for additional functionality.","title":"Using SQL"},{"location":"sql/overview/#connection","text":"The first step to building a SQL query is getting access to a connection. Most often, you will use withPooledConnection(to:) followed by your database's dbid . Note Refer to the table in SQL Getting Started for your database's default dbid . The dbid allows you to use multiple databases per application. router . get ( sql ) { req in return req . withPooledConnection ( to : . # dbid # ) { conn in return // use conn to perform a query } } Check out Database Kit Overview Connections for more information. The rest of this guide will assume you have access to a SQL database connection.","title":"Connection"},{"location":"sql/overview/#select","text":"Use the select() method on a connection to create a SQLSelectBuilder . This builder helps you create SELECT statements and supports: * , columns, and expressions like functions FROM JOIN GROUP BY ORDER BY The select builder conforms to SQLPredicateBuilder for building WHERE predicates. It also conforms to SQLQueryFetcher for decoding Codable models from the result set. Let's take a look at an example SELECT query. Replace the Xcode placeholder with the name of the database you are using, i.e., SQLite . struct User : SQLTable , Codable { static let sqlTableIdentifierString = users let id : Int ? let name : String } let users = conn . select () . all (). from ( User . self ) . where ( \\ User . name == Vapor ) . all ( decoding : User . self ) print ( users ) // Future [User] The resulting SQL will look something like this: SELECT * FROM users WHERE users . name = ? As you can see, the Swift code reads similarly to actual SQL. Be sure to visit the API docs for the various builder protocols to see all available methods.","title":"Select"},{"location":"sql/overview/#api-docs","text":"Check out the API docs for more in-depth information about SQL's APIs.","title":"API Docs"},{"location":"sqlite/getting-started/","text":"SQLite SQLite ( vapor/sqlite ) is a wrapper around the libsqlite C-library. The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the SQLite package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. SQLite core is built on top of DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent SQLite , all of the features of SQLite core will be available to you. Getting Started Let's take a look at how you can get started using SQLite core. Package The first step to using SQLite core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd35 SQLite 3 wrapper for Swift. . package ( url : https://github.com/vapor/sqlite.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ SQLite , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode Config The next step is to configure the database in configure.swift . import SQLite /// Register providers first try services . register ( SQLiteProvider ()) Registering the provider will add all of the services required for SQLite to work properly. It also includes a default database config struct that uses an in-memory DB. Customizing Config You can of course override the default configuration provided by SQLiteProvider if you'd like. SQLite supports in-memory and file-based persistance. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a SQLite database let sqlite = try SQLiteDatabase ( storage : . file ( path : db.sqlite )) /// Register the configured SQLite database to the database config. var databases = DatabasesConfig () databases . add ( database : sqlite , as : . sqlite ) services . register ( databases ) See SQLiteDatabase and SQLiteStorage for more information. SQLite's default database identifier is .sqlite . You can create a custom identifier if you want by extending DatabaseIdentifier . Query Now that the database is configured, you can make your first query. struct SQLiteVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . sqlite ) { conn in return conn . select () . column ( function : sqlite_version , as : version ) . all ( decoding : SQLiteVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your SQLite version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Once we have a connection, we can use select() to create a SELECT query builder. Learn more about building queries in SQL Getting Started . Visit SQLite's API docs for detailed information about all available types and methods.","title":"Getting Started"},{"location":"sqlite/getting-started/#sqlite","text":"SQLite ( vapor/sqlite ) is a wrapper around the libsqlite C-library. The higher-level, Fluent ORM guide is located at Fluent Getting Started . Using just the SQLite package directly for your project may be a good idea if any of the following are true: You have an existing DB with non-standard structure. You rely heavily on custom or complex SQL queries. You just plain don't like ORMs. SQLite core is built on top of DatabaseKit which provides some conveniences like connection pooling and integrations with Vapor's Services architecture. Tip Even if you do choose to use Fluent SQLite , all of the features of SQLite core will be available to you.","title":"SQLite"},{"location":"sqlite/getting-started/#getting-started","text":"Let's take a look at how you can get started using SQLite core.","title":"Getting Started"},{"location":"sqlite/getting-started/#package","text":"The first step to using SQLite core is adding it as a dependency to your project in your SPM package manifest file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : MyApp , dependencies : [ /// Any other dependencies ... // \ud83d\udd35 SQLite 3 wrapper for Swift. . package ( url : https://github.com/vapor/sqlite.git , from : 3.0.0 ), ], targets : [ . target ( name : App , dependencies : [ SQLite , ...]), . target ( name : Run , dependencies : [ App ]), . testTarget ( name : AppTests , dependencies : [ App ]), ] ) Don't forget to add the module as a dependency in the targets array. Once you have added the dependency, regenerate your Xcode project with the following command: vapor xcode","title":"Package"},{"location":"sqlite/getting-started/#config","text":"The next step is to configure the database in configure.swift . import SQLite /// Register providers first try services . register ( SQLiteProvider ()) Registering the provider will add all of the services required for SQLite to work properly. It also includes a default database config struct that uses an in-memory DB.","title":"Config"},{"location":"sqlite/getting-started/#customizing-config","text":"You can of course override the default configuration provided by SQLiteProvider if you'd like. SQLite supports in-memory and file-based persistance. To configure your database manually, register a DatabasesConfig struct to your services. // Configure a SQLite database let sqlite = try SQLiteDatabase ( storage : . file ( path : db.sqlite )) /// Register the configured SQLite database to the database config. var databases = DatabasesConfig () databases . add ( database : sqlite , as : . sqlite ) services . register ( databases ) See SQLiteDatabase and SQLiteStorage for more information. SQLite's default database identifier is .sqlite . You can create a custom identifier if you want by extending DatabaseIdentifier .","title":"Customizing Config"},{"location":"sqlite/getting-started/#query","text":"Now that the database is configured, you can make your first query. struct SQLiteVersion : Codable { let version : String } router . get ( sql ) { req in return req . withPooledConnection ( to : . sqlite ) { conn in return conn . select () . column ( function : sqlite_version , as : version ) . all ( decoding : SQLiteVersion . self ) }. map { rows in return rows [ 0 ]. version } } Visiting this route should display your SQLite version. Here we are making use database connection pooling. You can learn more about creating connections in DatabaseKit Getting Started . Once we have a connection, we can use select() to create a SELECT query builder. Learn more about building queries in SQL Getting Started . Visit SQLite's API docs for detailed information about all available types and methods.","title":"Query"},{"location":"template-kit/getting-started/","text":"Getting Started with Template Kit Template Kit ( vapor/template-kit ) is a framework for implementing templating languages in Swift. It is currently used to power Leaf ( vapor/leaf ) and hopefully more languages in the future. Template Kit is designed to make implementing a templating language easy by defining a common template structure and handling the entire serialization step. Warning These docs are for developers interested in implementing a templating language using Template Kit. See Leaf Getting Started for information about using Leaf. Vapor This package is included with Vapor and exported by default. You will have access to all TemplateKit APIs when you import Vapor . import Vapor Standalone The Template Kit package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a templating framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/template-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ TemplateKit , ... ]) ] ) Use import TemplateKit to access the APIs. Overview Let's take a look at how Leaf uses Template Kit to render views. Assume we have a template greeting.leaf with the following contents: Hello, #capitalize ( name) ! This first step in rendering this view is to parse the syntax into an abstract syntax tree (AST). This is the part of view rendering that Leaf is responsible for, since Leaf has a unique syntax. Leaf does this by creating a LeafParser that conforms to TemplateParser . greeting.leaf - LeafParser - AST In code, this looks like: func parse ( scanner : TemplateByteScanner ) throws - [ TemplateSyntax ] The AST for our example greeting.leaf file would look something like this: [ . raw ( data : Hello. ), . tag ( name : capitalize , parameters : [. identifier ( name )] ), . raw ( data : ! ), ] Now that Leaf has created an AST, it's job is done! Template Kit will handle converting this AST into a rendered view. All it needs is a TemplateData to use for filling in any variables. let data = TemplateData . dictionary ([ name : vapor ]) The above data will be combined with the AST and used by the TemplateSerializer to create a rendered view. AST + Data - TemplateSerializer - View Our rendered view will look something like: Hello, Vapor! All of these steps are handled by LeafRenderer which conforms to TemplateRenderer . A template renderer is simply an object that contains both a parser and a serializer. When you implement one, you will get several helpful extensions from Template Kit for free that help load files and cache parsed ASTs. It's what the end user will use to render views. The entire pipeline looks like this: LeafRenderer | |----------------------------------------------------------------| greeting.leaf - LeafParser - AST - TemplateSerializer - View ^ / TemplateData In code, the method looks like this: public func render ( _ path : String , _ context : TemplateData ) - Future View Check out Template Kit's API docs for detailed information about all of the protocols, structs, and classes Template Kit offers.","title":"Getting Started"},{"location":"template-kit/getting-started/#getting-started-with-template-kit","text":"Template Kit ( vapor/template-kit ) is a framework for implementing templating languages in Swift. It is currently used to power Leaf ( vapor/leaf ) and hopefully more languages in the future. Template Kit is designed to make implementing a templating language easy by defining a common template structure and handling the entire serialization step. Warning These docs are for developers interested in implementing a templating language using Template Kit. See Leaf Getting Started for information about using Leaf.","title":"Getting Started with Template Kit"},{"location":"template-kit/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all TemplateKit APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"template-kit/getting-started/#standalone","text":"The Template Kit package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a templating framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/template-kit.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ TemplateKit , ... ]) ] ) Use import TemplateKit to access the APIs.","title":"Standalone"},{"location":"template-kit/getting-started/#overview","text":"Let's take a look at how Leaf uses Template Kit to render views. Assume we have a template greeting.leaf with the following contents: Hello, #capitalize ( name) ! This first step in rendering this view is to parse the syntax into an abstract syntax tree (AST). This is the part of view rendering that Leaf is responsible for, since Leaf has a unique syntax. Leaf does this by creating a LeafParser that conforms to TemplateParser . greeting.leaf - LeafParser - AST In code, this looks like: func parse ( scanner : TemplateByteScanner ) throws - [ TemplateSyntax ] The AST for our example greeting.leaf file would look something like this: [ . raw ( data : Hello. ), . tag ( name : capitalize , parameters : [. identifier ( name )] ), . raw ( data : ! ), ] Now that Leaf has created an AST, it's job is done! Template Kit will handle converting this AST into a rendered view. All it needs is a TemplateData to use for filling in any variables. let data = TemplateData . dictionary ([ name : vapor ]) The above data will be combined with the AST and used by the TemplateSerializer to create a rendered view. AST + Data - TemplateSerializer - View Our rendered view will look something like: Hello, Vapor! All of these steps are handled by LeafRenderer which conforms to TemplateRenderer . A template renderer is simply an object that contains both a parser and a serializer. When you implement one, you will get several helpful extensions from Template Kit for free that help load files and cache parsed ASTs. It's what the end user will use to render views. The entire pipeline looks like this: LeafRenderer | |----------------------------------------------------------------| greeting.leaf - LeafParser - AST - TemplateSerializer - View ^ / TemplateData In code, the method looks like this: public func render ( _ path : String , _ context : TemplateData ) - Future View Check out Template Kit's API docs for detailed information about all of the protocols, structs, and classes Template Kit offers.","title":"Overview"},{"location":"testing/getting-started/","text":"Getting Started with Testing Coming soon.","title":"Getting Started"},{"location":"testing/getting-started/#getting-started-with-testing","text":"Coming soon.","title":"Getting Started with Testing"},{"location":"url-encoded-form/getting-started/","text":"Getting Started with URL-Encoded Form URL-Encoded Form ( vapor/url-encoded-form ) is a small package that helps you parse and serialize application/x-www-form-urlencoded data. URL-encoded forms are a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. The URL-Encoded Form package makes it easy to use this encoding by integrating directly with Codable . Vapor This package is included with Vapor and exported by default. You will have access to all URLEncodedForm APIs when you import Vapor . import Vapor Standalone The URL-Encoded Form package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with form-urlencoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/url-encoded-form.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ URLEncodedForm , ... ]) ] ) Use import URLEncodedForm to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the URL-Encoded Form package in general. Visit the API Docs for specific API info.","title":"Getting Started"},{"location":"url-encoded-form/getting-started/#getting-started-with-url-encoded-form","text":"URL-Encoded Form ( vapor/url-encoded-form ) is a small package that helps you parse and serialize application/x-www-form-urlencoded data. URL-encoded forms are a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. The URL-Encoded Form package makes it easy to use this encoding by integrating directly with Codable .","title":"Getting Started with URL-Encoded Form"},{"location":"url-encoded-form/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all URLEncodedForm APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"url-encoded-form/getting-started/#standalone","text":"The URL-Encoded Form package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with form-urlencoded data for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/url-encoded-form.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ URLEncodedForm , ... ]) ] ) Use import URLEncodedForm to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the URL-Encoded Form package in general. Visit the API Docs for specific API info.","title":"Standalone"},{"location":"url-encoded-form/overview/","text":"Using URL-Encoded Form URL-Encoded Form is a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. This encoding is also used to send structured data in URL query strings. It is a relatively efficient encoding for sending small amounts of data. However, all data must be percent-encoded making this encoding suboptimal for large amounts of data. See the Multipart encoding if you need to upload things like files. Tip URL-Encoded Form integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a application/x-www-form-urlencoded request. Decode Body Most often, you will be decoding form-urlencoded -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like. Request Here is an example form-urlencoded -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : application/x-www-form-urlencoded name=Vapor age=3 luckyNumbers[]=5 luckyNumbers[]=7 You can see the [] notation is used to encode arrays. Your web form will need to use this notation as well. Form There are many ways to create a form-urlencoded -encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users input type = text name = name input type = text name = age input type = text name = luckyNumbers[] input type = text name = luckyNumbers[] / form Since we are not specifying a special enctype attribute on the form , the browser will URL-encode the form by default. We are also providing two fields with the same name, luckyNumbers[] . This will let us send an array of values. Content Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var luckyNumbers : [ Int ] } Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . luckyNumbers ) // [5, 7] return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work! Encode Body APIs encode form-urlencoded data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a form-urlencoded -encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , luckyNumbers : [ 5 , 7 ]) res . content . encode ( user , as : . urlEncodedForm ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure. URL Query URL-Encoded Forms are also useful for sending structured data in the URL query string. This is widely used for sending data via GET requests where HTTP bodies are not allowed. Let's take a look at how we can decode some search parameters from the query string. GET /users?name=Vapor age=3 HTTP / 1.1 The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct UsersFilters : Content { var name : String ? var age : Int ? } Here we are making both name and age optional since the route can be called without any flags to return all users. Now that we have a Codable struct, we can decode the URL query string. The process is almost identical to decoding content, expect we use req.query instead of req.content . router . get ( users ) { req - Future [ User ] in let filters = try req . query . decode ( UsersFilters . self ) print ( filters . name ) // Vapor print ( filters . age ) // 3 return // fetch users with filters } Tip Decoding the URL query string is not asynchronous because, unlike HTTP bodies, Vapor can be sure it is available when calling the route closure.","title":"Overview"},{"location":"url-encoded-form/overview/#using-url-encoded-form","text":"URL-Encoded Form is a widely-supported encoding on the web. It's most often used for serializing web forms sent via POST requests. This encoding is also used to send structured data in URL query strings. It is a relatively efficient encoding for sending small amounts of data. However, all data must be percent-encoded making this encoding suboptimal for large amounts of data. See the Multipart encoding if you need to upload things like files. Tip URL-Encoded Form integrates with Content like all other encoding methods in Vapor. See Vapor Content for more information about the Content protocol. Let's take a look at how to decode a application/x-www-form-urlencoded request.","title":"Using URL-Encoded Form"},{"location":"url-encoded-form/overview/#decode-body","text":"Most often, you will be decoding form-urlencoded -encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like.","title":"Decode Body"},{"location":"url-encoded-form/overview/#request","text":"Here is an example form-urlencoded -encoded request for creating a new user. POST /users HTTP / 1.1 Content-Type : application/x-www-form-urlencoded name=Vapor age=3 luckyNumbers[]=5 luckyNumbers[]=7 You can see the [] notation is used to encode arrays. Your web form will need to use this notation as well.","title":"Request"},{"location":"url-encoded-form/overview/#form","text":"There are many ways to create a form-urlencoded -encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like. form method = POST action = /users input type = text name = name input type = text name = age input type = text name = luckyNumbers[] input type = text name = luckyNumbers[] / form Since we are not specifying a special enctype attribute on the form , the browser will URL-encode the form by default. We are also providing two fields with the same name, luckyNumbers[] . This will let us send an array of values.","title":"Form"},{"location":"url-encoded-form/overview/#content","text":"Now let's take a look at how we would handle this request in Vapor. The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct User : Content { var name : String var age : Int var luckyNumbers : [ Int ] } Now that we have our User struct, let's decode that request! We can use the ContentContainer to do this easily. router . post ( users ) { req - Future HTTPStatus in return try req . content . decode ( User . self ). map ( to : HTTPStatus . self ) { user in print ( user . name ) // Vapor print ( user . age ) // 3 print ( user . luckyNumbers ) // [5, 7] return . ok } } Now when you post the form to /users , you should see the information printed in the console. Nice work!","title":"Content"},{"location":"url-encoded-form/overview/#encode-body","text":"APIs encode form-urlencoded data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same User struct from the previous example, here is how we can encode a form-urlencoded -encoded response. router . get ( multipart ) { req - User in let res = req . makeResponse () let user = User ( name : Vapor , age : 3 , luckyNumbers : [ 5 , 7 ]) res . content . encode ( user , as : . urlEncodedForm ) return user } Tip If you set a default MediaType on your Content types, then you can return them directly in the route closure.","title":"Encode Body"},{"location":"url-encoded-form/overview/#url-query","text":"URL-Encoded Forms are also useful for sending structured data in the URL query string. This is widely used for sending data via GET requests where HTTP bodies are not allowed. Let's take a look at how we can decode some search parameters from the query string. GET /users?name=Vapor age=3 HTTP / 1.1 The first step (as always with Content ) is to create a Codable struct that represents the data structure. import Vapor struct UsersFilters : Content { var name : String ? var age : Int ? } Here we are making both name and age optional since the route can be called without any flags to return all users. Now that we have a Codable struct, we can decode the URL query string. The process is almost identical to decoding content, expect we use req.query instead of req.content . router . get ( users ) { req - Future [ User ] in let filters = try req . query . decode ( UsersFilters . self ) print ( filters . name ) // Vapor print ( filters . age ) // 3 return // fetch users with filters } Tip Decoding the URL query string is not asynchronous because, unlike HTTP bodies, Vapor can be sure it is available when calling the route closure.","title":"URL Query"},{"location":"validation/getting-started/","text":"Getting Started with Validation Validation ( vapor/validation ) is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators. The rest of this guide will show you how to add and import the Validation module. For more information on using this package, check out Validation Overview . Vapor This package is included with Vapor and exported by default. You will have access to all Validation APIs when you import Vapor . import Vapor Standalone The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a validation framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/validation.git , from : 2.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Validation , ... ]) ] ) Use import Validation to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Validation package in general. Visit the API Docs for Validation-specific API info.","title":"Getting Started"},{"location":"validation/getting-started/#getting-started-with-validation","text":"Validation ( vapor/validation ) is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators. The rest of this guide will show you how to add and import the Validation module. For more information on using this package, check out Validation Overview .","title":"Getting Started with Validation"},{"location":"validation/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all Validation APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"validation/getting-started/#standalone","text":"The Service package is lightweight, pure-Swift, and has very few dependencies. This means it can be used as a validation framework for any Swift project even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/validation.git , from : 2.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Validation , ... ]) ] ) Use import Validation to access the APIs. Warning Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Validation package in general. Visit the API Docs for Validation-specific API info.","title":"Standalone"},{"location":"validation/overview/","text":"Validation Overview Validation is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators. Swift Codable Swift's strong type system and Codable take care of most of the basic validation that web apps need to do. struct User : Codable { var id : UUID ? var name : String var age : Int var email : String ? var profilePictureURL : String ? } For example, when you decode the above User model, Swift will automatically ensure the following: id is a valid UUID or is nil . name is a valid String and is not nil . age is a valid Int and is not nil . email is a valid String or is nil . profilePictureURL is a valid String or is nil . This is a great first step, but there is still room for improvement here. Here are some examples of things Swift and Codable would not mind, but are not ideal: name is empty string \"\" name contains non-alphanumeric characters age is a negative number -42 email is not correctly formatted test@@vapor.codes profilePictureURL is not a URL without a scheme Luckily the Validation package can help. Validatable Let's take a look at how the Validation package can help you validate incoming data. We'll start by conforming our User model from the previous section to the Validatable protocol. Note This assumes User already conforms to Reflectable (added by default when using one of Fluent's Model protocols). If not, you will need to add conformance to Reflectable manually. extension User : Validatable { /// See `Validatable`. static func validations () - Validations User { // define validations } } let user = User (...) // since User conforms to Validatable, we get a new method validate() // that throws an error if any validations fail try user . validate () This is the basic structure of Validatable conformance. Let's take a look at how we can implement the static validations() method. Validations First let's start by verifying that the name is at least 3 characters long. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . count ( 3. ..)) return validations } } The count(...) validation accepts Swift Range notation and will validate that a collection's count is within that range. By only placing a value on the left side of ... , we only set a minimum range. Take a look at all of the available validators here . Operators Validating that the name is three or more characters is great, but we also want to make sure that the name is alphanumeric characters only. We can do this by combining multiple validators using . try validations . add ( \\ . name , . count ( 3. ..) . alphanumeric ) Now our name will only be considered valid if it is three or more characters and alphanumeric. Take a look at all of the available operators here . Nil You may want to run validations on optionals only if a value is present. The and || operators have special overloads that help you do this. try validations . add ( \\ . email , . email || . nil ) The nil validator checks if a T? optional value is nil . The email validator checks if a String is a valid email address. However, the property on our User is a String? . This means the email validator cannot be used directly with the property. We can combine these two operators using || to express the validation we want: validate the email is correctly formatted if it is not nil. Validate Let's finish up the rest of our validations using our new knowledge. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . alphanumeric . count ( 3. ..)) try validations . add ( \\ . age , . range ( 18. ..)) try validations . add ( \\ . email , . email || . nil ) try validations . add ( \\ . profilePictureURL , . url || . nil ) return validations } } Now let's try out validating our model. router . post ( User . self , at : users ) { req , user - User in try user . validate () return user } When you query that route, you should see that errors are thrown if the data does not meet your validations. If the data is correct, your user model is returned successfully. Congratulations on setting up your first Validatable model! Check out the API docs for more information and code samples.","title":"Overview"},{"location":"validation/overview/#validation-overview","text":"Validation is a framework for validating data sent to your application. It can help validate things like names, emails and more. It is also extensible, allowing you to easily create custom validators.","title":"Validation Overview"},{"location":"validation/overview/#swift-codable","text":"Swift's strong type system and Codable take care of most of the basic validation that web apps need to do. struct User : Codable { var id : UUID ? var name : String var age : Int var email : String ? var profilePictureURL : String ? } For example, when you decode the above User model, Swift will automatically ensure the following: id is a valid UUID or is nil . name is a valid String and is not nil . age is a valid Int and is not nil . email is a valid String or is nil . profilePictureURL is a valid String or is nil . This is a great first step, but there is still room for improvement here. Here are some examples of things Swift and Codable would not mind, but are not ideal: name is empty string \"\" name contains non-alphanumeric characters age is a negative number -42 email is not correctly formatted test@@vapor.codes profilePictureURL is not a URL without a scheme Luckily the Validation package can help.","title":"Swift & Codable"},{"location":"validation/overview/#validatable","text":"Let's take a look at how the Validation package can help you validate incoming data. We'll start by conforming our User model from the previous section to the Validatable protocol. Note This assumes User already conforms to Reflectable (added by default when using one of Fluent's Model protocols). If not, you will need to add conformance to Reflectable manually. extension User : Validatable { /// See `Validatable`. static func validations () - Validations User { // define validations } } let user = User (...) // since User conforms to Validatable, we get a new method validate() // that throws an error if any validations fail try user . validate () This is the basic structure of Validatable conformance. Let's take a look at how we can implement the static validations() method.","title":"Validatable"},{"location":"validation/overview/#validations","text":"First let's start by verifying that the name is at least 3 characters long. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . count ( 3. ..)) return validations } } The count(...) validation accepts Swift Range notation and will validate that a collection's count is within that range. By only placing a value on the left side of ... , we only set a minimum range. Take a look at all of the available validators here .","title":"Validations"},{"location":"validation/overview/#operators","text":"Validating that the name is three or more characters is great, but we also want to make sure that the name is alphanumeric characters only. We can do this by combining multiple validators using . try validations . add ( \\ . name , . count ( 3. ..) . alphanumeric ) Now our name will only be considered valid if it is three or more characters and alphanumeric. Take a look at all of the available operators here .","title":"Operators"},{"location":"validation/overview/#nil","text":"You may want to run validations on optionals only if a value is present. The and || operators have special overloads that help you do this. try validations . add ( \\ . email , . email || . nil ) The nil validator checks if a T? optional value is nil . The email validator checks if a String is a valid email address. However, the property on our User is a String? . This means the email validator cannot be used directly with the property. We can combine these two operators using || to express the validation we want: validate the email is correctly formatted if it is not nil.","title":"Nil"},{"location":"validation/overview/#validate","text":"Let's finish up the rest of our validations using our new knowledge. extension User : Validatable { /// See `Validatable`. static func validations () throws - Validations User { var validations = Validations ( User . self ) try validations . add ( \\ . name , . alphanumeric . count ( 3. ..)) try validations . add ( \\ . age , . range ( 18. ..)) try validations . add ( \\ . email , . email || . nil ) try validations . add ( \\ . profilePictureURL , . url || . nil ) return validations } } Now let's try out validating our model. router . post ( User . self , at : users ) { req , user - User in try user . validate () return user } When you query that route, you should see that errors are thrown if the data does not meet your validations. If the data is correct, your user model is returned successfully. Congratulations on setting up your first Validatable model! Check out the API docs for more information and code samples.","title":"Validate"},{"location":"vapor/client/","text":"Using Client Client is a convenience wrapper around the lower level HTTP Client . It automatically parses things like hostname and port from URIs and helps you encode and decode Content . let res = try req . client (). get ( http://vapor.codes ) print ( res ) // Future Response Container The first thing you will need is a service Container to create your client. If you are making this external API request as the result of an incoming request to your server, you should use the Request container to create a client. This is most often the case. If you need a client during boot, use the Application or if you are in a Command use the command context's container. Once you have a Container , use the client() method to create a Client . // Creates a generic Client let client = try container . client () Send Once you have a Client , you can use the send(...) method to send a Request . Note that the request URI must include a scheme and hostname. let req : Request ... let res = try client . send ( req ) print ( res ) // Future Response You can also use the convenience methods like get(...) , post(...) , etc. let user : User ... let res = try client . post ( http://api.vapor.codes/users ) { post in try post . content . encode ( user ) } print ( res ) // Future Response See Content for more information on encoding and decoding content to messages.","title":"Client"},{"location":"vapor/client/#using-client","text":"Client is a convenience wrapper around the lower level HTTP Client . It automatically parses things like hostname and port from URIs and helps you encode and decode Content . let res = try req . client (). get ( http://vapor.codes ) print ( res ) // Future Response","title":"Using Client"},{"location":"vapor/client/#container","text":"The first thing you will need is a service Container to create your client. If you are making this external API request as the result of an incoming request to your server, you should use the Request container to create a client. This is most often the case. If you need a client during boot, use the Application or if you are in a Command use the command context's container. Once you have a Container , use the client() method to create a Client . // Creates a generic Client let client = try container . client ()","title":"Container"},{"location":"vapor/client/#send","text":"Once you have a Client , you can use the send(...) method to send a Request . Note that the request URI must include a scheme and hostname. let req : Request ... let res = try client . send ( req ) print ( res ) // Future Response You can also use the convenience methods like get(...) , post(...) , etc. let user : User ... let res = try client . post ( http://api.vapor.codes/users ) { post in try post . content . encode ( user ) } print ( res ) // Future Response See Content for more information on encoding and decoding content to messages.","title":"Send"},{"location":"vapor/content/","text":"Using Content In Vapor 3, all content types (JSON, protobuf, URLEncodedForm , Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use mostly JSON as an example. But keep in mind the API is the same for any supported content type. Server This first section will go over decoding and encoding messages sent between your server and connected clients. See the client section for encoding and decoding content in messages sent to external APIs. Request Let's take a look at how you would parse the following HTTP request sent to your server. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Notice the key names exactly match the keys in the request data. The expected data types also match. Next conform this struct or class to Content . Decode Now we are ready to decode that HTTP request. Every Request has a ContentContainer that we can use to decode content from the message's body. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok } } We use .map(to:) here since decode(...) returns a future . Note Decoding content from requests is asynchronous because HTTP allows bodies to be split into multiple parts using chunked transfer encoding. Router To help make decoding content from incoming requests easier, Vapor offers a few extensions on Router to do this automatically. router . post ( LoginRequest . self , at : login ) { req , loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok } Detect Type Since the HTTP request in this example declared JSON as its content type, Vapor knows to use a JSON decoder automatically. This same method would work just as well for the following request. POST /login HTTP / 1.1 Content-Type : application/x-www-form-urlencoded email=user@vapor.codes don t+look! All HTTP requests must include a content type to be valid. Because of this, Vapor will automatically choose an appropriate decoder or error if it encounters an unknown media type. Tip You can configure the default encoders and decoders Vapor uses. Custom You can always override Vapor's default decoder and pass in a custom one if you want. let user = try req . content . decode ( User . self , using : JSONDecoder ()) print ( user ) // Future User Response Let's take a look at how you would create the following HTTP response from your server. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content . Encode Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } This will create a default Response with 200 OK status code and minimal headers. You can customize the response using a convenience encode(...) method. router . get ( user ) { req - Future Response in return User ( name : Vapor User , email : user@vapor.codes ) . encode ( status : . created ) } Override Type Content will automatically encode as JSON by default. You can always override which content type is used using the as: parameter. try res . content . encode ( user , as : . urlEncodedForm ) You can also change the default media type for any class or struct. struct User : Content { /// See `Content`. static let defaultContentType : MediaType = . urlEncodedForm ... } Client Encoding content to HTTP requests sent by Client s is similar to encoding HTTP responses returned by your server. Request Let's take a look at how we can encode the following request. POST /login HTTP / 1.1 Host : api.vapor.codes Content-Type : application/json { email : user@vapor.codes , password : don t look! } Encode First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Now we are ready to make our request. Let's assume we are making this request inside of a route closure, so we will use the incoming request as our container. let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) let res = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // encode the loginRequest before sending try loginReq . content . encode ( loginRequest ) } print ( res ) // Future Response Response Continuing from our example in the encode section, let's see how we would decode content from the client's response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } First of course we must create a struct or class to represent the data. import Vapor struct User : Content { var name : String var email : String } Decode Now we are ready to decode the client response. let res : Future Response // from the Client let user = res . flatMap { try $0 . content . decode ( User . self ) } print ( user ) // Future User Example Let's now take a look at our complete Client request that both encodes and decodes content. // Create the LoginRequest data let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) // POST /login let user = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // Encode Content before Request is sent return try loginReq . content . encode ( loginRequest ) }. flatMap { loginRes in // Decode Content after Response is received return try loginRes . content . decode ( User . self ) } print ( user ) // Future User Query String URL-Encoded Form data can be encoded and decoded from an HTTP request's URI query string just like content. All you need is a class or struct that conforms to Content . In these examples, we will be using the following struct. struct Flags : Content { var search : String ? var isAdmin : Bool ? } Decode All Request s have a QueryContainer that you can use to decode the query string. let flags = try req . query . decode ( Flags . self ) print ( flags ) // Flags Encode You can also encode content. This is useful for encoding query strings when using Client . let flags : Flags ... try req . query . encode ( flags ) Dynamic Properties One of the most frequently asked questions regarding Content is: How do I add a property to just this response? The way Vapor 3 handles Content is based entirely on Codable . At no point (that is publically accessible) is your data in an arbitrary data structure like [String: Any] that you can mutate at will. Because of this, all data structures that your app accepts and returns must be statically defined. Let's take a look at a common scenario to better understand this. Very often when you are creating a user, there are a couple different data formats required: create: password should be supplied twice to check values match internal: you should store a hash not the plaintext password public: when listing users, the password hash should not be included To do this, you should create three types. // Data required to create a user struct UserCreate : Content { var email : String var password : String var passwordCheck : String } // Our internal User representation struct User : Model { var id : Int ? var email : String var passwordHash : Data } // Public user representation struct PublicUser : Content { var id : Int var email : String } // Create a router for POST /users router . post ( UserCreate . self , at : users ) { req , userCreate - PublicUser in guard userCreate . password == passwordCheck else { /* some error */ } let hasher = try req . make ( /* some hasher */ ) let user = try User ( email : userCreate . email , passwordHash : hasher . hash ( userCreate . password ) ) // save user return try PublicUser ( id : user . requireID (), email : user . email ) } For other methods such as PATCH and PUT , you may want to create additional types to supports the unique semantics. Benefits This method may seem a bit verbose at first when compared to dynamic solutions, but it has a number of key advantages: Statically Typed : Very little validation is needed on top of what Swift and Codable do automatically. Readability : No need for Strings and optional chaining when working with Swift types. Maintainable : Large projects will appreciate having this information separated and clearly stated. Shareable : Types defining what content your routes accept and return can be used to conform to specifications like OpenAPI or even be shared directly with clients written in Swift. Performance : Working with native Swift types is much more performant than mutating [String: Any] dictionaries. JSON JSON is a very popular encoding format for APIs and the way in which dates, data, floats, etc are encoded is non-standard. Because of this, Vapor makes it easy to use custom JSONDecoder s when you interact with other APIs. // Conforms to Encodable let user : User ... // Encode JSON using custom date encoding strategy try req . content . encode ( json : user , using : . custom ( dates : . millisecondsSince1970 )) You can also use this method for decoding. // Decode JSON using custom date encoding strategy let user = try req . content . decode ( json : User . self , using : . custom ( dates : . millisecondsSince1970 )) If you would like to set a custom JSON encoder or decoder globally, you can do so using configuration . Configure Use ContentConfig to register custom encoder/decoders for your application. These custom coders will be used anywhere you do content.encode / content.decode . /// Create default content config var contentConfig = ContentConfig . default () /// Create custom JSON encoder var jsonEncoder = JSONEncoder () jsonEncoder . dateEncodingStrategy = . millisecondsSince1970 /// Register JSON encoder and content config contentConfig . use ( encoder : jsonEncoder , for : . json ) services . register ( contentConfig )","title":"Content"},{"location":"vapor/content/#using-content","text":"In Vapor 3, all content types (JSON, protobuf, URLEncodedForm , Multipart , etc) are treated the same. All you need to parse and serialize content is a Codable class or struct. For this introduction, we will use mostly JSON as an example. But keep in mind the API is the same for any supported content type.","title":"Using Content"},{"location":"vapor/content/#server","text":"This first section will go over decoding and encoding messages sent between your server and connected clients. See the client section for encoding and decoding content in messages sent to external APIs.","title":"Server"},{"location":"vapor/content/#request","text":"Let's take a look at how you would parse the following HTTP request sent to your server. POST /login HTTP / 1.1 Content-Type : application/json { email : user@vapor.codes , password : don t look! } First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Notice the key names exactly match the keys in the request data. The expected data types also match. Next conform this struct or class to Content .","title":"Request"},{"location":"vapor/content/#decode","text":"Now we are ready to decode that HTTP request. Every Request has a ContentContainer that we can use to decode content from the message's body. router . post ( login ) { req - Future HTTPStatus in return req . content . decode ( LoginRequest . self ). map { loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok } } We use .map(to:) here since decode(...) returns a future . Note Decoding content from requests is asynchronous because HTTP allows bodies to be split into multiple parts using chunked transfer encoding.","title":"Decode"},{"location":"vapor/content/#router","text":"To help make decoding content from incoming requests easier, Vapor offers a few extensions on Router to do this automatically. router . post ( LoginRequest . self , at : login ) { req , loginRequest in print ( loginRequest . email ) // user@vapor.codes print ( loginRequest . password ) // don t look! return HTTPStatus . ok }","title":"Router"},{"location":"vapor/content/#detect-type","text":"Since the HTTP request in this example declared JSON as its content type, Vapor knows to use a JSON decoder automatically. This same method would work just as well for the following request. POST /login HTTP / 1.1 Content-Type : application/x-www-form-urlencoded email=user@vapor.codes don t+look! All HTTP requests must include a content type to be valid. Because of this, Vapor will automatically choose an appropriate decoder or error if it encounters an unknown media type. Tip You can configure the default encoders and decoders Vapor uses.","title":"Detect Type"},{"location":"vapor/content/#custom","text":"You can always override Vapor's default decoder and pass in a custom one if you want. let user = try req . content . decode ( User . self , using : JSONDecoder ()) print ( user ) // Future User","title":"Custom"},{"location":"vapor/content/#response","text":"Let's take a look at how you would create the following HTTP response from your server. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } Just like decoding, first create a struct or class that represents the data that you are expecting. import Vapor struct User : Content { var name : String var email : String } Then just conform this struct or class to Content .","title":"Response"},{"location":"vapor/content/#encode","text":"Now we are ready to encode that HTTP response. router . get ( user ) { req - User in return User ( name : Vapor User , email : user@vapor.codes ) } This will create a default Response with 200 OK status code and minimal headers. You can customize the response using a convenience encode(...) method. router . get ( user ) { req - Future Response in return User ( name : Vapor User , email : user@vapor.codes ) . encode ( status : . created ) }","title":"Encode"},{"location":"vapor/content/#override-type","text":"Content will automatically encode as JSON by default. You can always override which content type is used using the as: parameter. try res . content . encode ( user , as : . urlEncodedForm ) You can also change the default media type for any class or struct. struct User : Content { /// See `Content`. static let defaultContentType : MediaType = . urlEncodedForm ... }","title":"Override Type"},{"location":"vapor/content/#client","text":"Encoding content to HTTP requests sent by Client s is similar to encoding HTTP responses returned by your server.","title":"Client"},{"location":"vapor/content/#request_1","text":"Let's take a look at how we can encode the following request. POST /login HTTP / 1.1 Host : api.vapor.codes Content-Type : application/json { email : user@vapor.codes , password : don t look! }","title":"Request"},{"location":"vapor/content/#encode_1","text":"First, create a struct or class that represents the data you expect. import Vapor struct LoginRequest : Content { var email : String var password : String } Now we are ready to make our request. Let's assume we are making this request inside of a route closure, so we will use the incoming request as our container. let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) let res = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // encode the loginRequest before sending try loginReq . content . encode ( loginRequest ) } print ( res ) // Future Response","title":"Encode"},{"location":"vapor/content/#response_1","text":"Continuing from our example in the encode section, let's see how we would decode content from the client's response. HTTP / 1.1 200 OK Content-Type : application/json { name : Vapor User , email : user@vapor.codes } First of course we must create a struct or class to represent the data. import Vapor struct User : Content { var name : String var email : String }","title":"Response"},{"location":"vapor/content/#decode_1","text":"Now we are ready to decode the client response. let res : Future Response // from the Client let user = res . flatMap { try $0 . content . decode ( User . self ) } print ( user ) // Future User","title":"Decode"},{"location":"vapor/content/#example","text":"Let's now take a look at our complete Client request that both encodes and decodes content. // Create the LoginRequest data let loginRequest = LoginRequest ( email : user@vapor.codes , password : don t look! ) // POST /login let user = try req . client (). post ( https://api.vapor.codes/login ) { loginReq in // Encode Content before Request is sent return try loginReq . content . encode ( loginRequest ) }. flatMap { loginRes in // Decode Content after Response is received return try loginRes . content . decode ( User . self ) } print ( user ) // Future User","title":"Example"},{"location":"vapor/content/#query-string","text":"URL-Encoded Form data can be encoded and decoded from an HTTP request's URI query string just like content. All you need is a class or struct that conforms to Content . In these examples, we will be using the following struct. struct Flags : Content { var search : String ? var isAdmin : Bool ? }","title":"Query String"},{"location":"vapor/content/#decode_2","text":"All Request s have a QueryContainer that you can use to decode the query string. let flags = try req . query . decode ( Flags . self ) print ( flags ) // Flags","title":"Decode"},{"location":"vapor/content/#encode_2","text":"You can also encode content. This is useful for encoding query strings when using Client . let flags : Flags ... try req . query . encode ( flags )","title":"Encode"},{"location":"vapor/content/#dynamic-properties","text":"One of the most frequently asked questions regarding Content is: How do I add a property to just this response? The way Vapor 3 handles Content is based entirely on Codable . At no point (that is publically accessible) is your data in an arbitrary data structure like [String: Any] that you can mutate at will. Because of this, all data structures that your app accepts and returns must be statically defined. Let's take a look at a common scenario to better understand this. Very often when you are creating a user, there are a couple different data formats required: create: password should be supplied twice to check values match internal: you should store a hash not the plaintext password public: when listing users, the password hash should not be included To do this, you should create three types. // Data required to create a user struct UserCreate : Content { var email : String var password : String var passwordCheck : String } // Our internal User representation struct User : Model { var id : Int ? var email : String var passwordHash : Data } // Public user representation struct PublicUser : Content { var id : Int var email : String } // Create a router for POST /users router . post ( UserCreate . self , at : users ) { req , userCreate - PublicUser in guard userCreate . password == passwordCheck else { /* some error */ } let hasher = try req . make ( /* some hasher */ ) let user = try User ( email : userCreate . email , passwordHash : hasher . hash ( userCreate . password ) ) // save user return try PublicUser ( id : user . requireID (), email : user . email ) } For other methods such as PATCH and PUT , you may want to create additional types to supports the unique semantics.","title":"Dynamic Properties"},{"location":"vapor/content/#benefits","text":"This method may seem a bit verbose at first when compared to dynamic solutions, but it has a number of key advantages: Statically Typed : Very little validation is needed on top of what Swift and Codable do automatically. Readability : No need for Strings and optional chaining when working with Swift types. Maintainable : Large projects will appreciate having this information separated and clearly stated. Shareable : Types defining what content your routes accept and return can be used to conform to specifications like OpenAPI or even be shared directly with clients written in Swift. Performance : Working with native Swift types is much more performant than mutating [String: Any] dictionaries.","title":"Benefits"},{"location":"vapor/content/#json","text":"JSON is a very popular encoding format for APIs and the way in which dates, data, floats, etc are encoded is non-standard. Because of this, Vapor makes it easy to use custom JSONDecoder s when you interact with other APIs. // Conforms to Encodable let user : User ... // Encode JSON using custom date encoding strategy try req . content . encode ( json : user , using : . custom ( dates : . millisecondsSince1970 )) You can also use this method for decoding. // Decode JSON using custom date encoding strategy let user = try req . content . decode ( json : User . self , using : . custom ( dates : . millisecondsSince1970 )) If you would like to set a custom JSON encoder or decoder globally, you can do so using configuration .","title":"JSON"},{"location":"vapor/content/#configure","text":"Use ContentConfig to register custom encoder/decoders for your application. These custom coders will be used anywhere you do content.encode / content.decode . /// Create default content config var contentConfig = ContentConfig . default () /// Create custom JSON encoder var jsonEncoder = JSONEncoder () jsonEncoder . dateEncodingStrategy = . millisecondsSince1970 /// Register JSON encoder and content config contentConfig . use ( encoder : jsonEncoder , for : . json ) services . register ( contentConfig )","title":"Configure"},{"location":"vapor/getting-started/","text":"Getting Started with Vapor Check out the main Getting Started guide which covers Vapor specifically. This page is here mostly for consistency with the rest of the packages. More in-depth information on the APIs included in Vapor, see the sub-sections to the left. Package If you don't want to use one of Vapor's templates to get started, you can always include the framework manually. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Vapor , ... ]) ] ) Use import Vapor to access the APIs. API Docs The rest of this guide will give you an overview of what is available in the Vapor package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"vapor/getting-started/#getting-started-with-vapor","text":"Check out the main Getting Started guide which covers Vapor specifically. This page is here mostly for consistency with the rest of the packages. More in-depth information on the APIs included in Vapor, see the sub-sections to the left.","title":"Getting Started with Vapor"},{"location":"vapor/getting-started/#package","text":"If you don't want to use one of Vapor's templates to get started, you can always include the framework manually. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/vapor.git , from : 3.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ Vapor , ... ]) ] ) Use import Vapor to access the APIs.","title":"Package"},{"location":"vapor/getting-started/#api-docs","text":"The rest of this guide will give you an overview of what is available in the Vapor package. As always, feel free to visit the API docs for more in-depth information.","title":"API Docs"},{"location":"vapor/middleware/","text":"Middleware Middleware is a logic chain between the client and a Vapor route handler. It allows you to make operations on incoming requests before they get to the route handler, and on outgoing responses before they go to the client. Configuration, and ErrorMiddleware Middleware is registered in your config.swift file. ErrorMiddleware is a very common example; it will take a thrown error in your software and convert it to a legible HTTP response code. var middlewares = MiddlewareConfig () middlewares . use ( ErrorMiddleware . self ) middlewares . use ( FileMiddleware . self ) // etc. services . register ( middlewares ) You will often run several middlewares in a single project. These middlewares are stacked up, and then registered together. The order in which middleware are listed can sometimes matter (see CORSMiddleware below). FileMiddleware FileMiddleware enables the serving of assets from the Public folder of your project to the client. You might include static files like stylesheets or bitmap images here. var middlewares = MiddlewareConfig () middlewares . use ( FileMiddleware . self ) services . register ( middlewares ) Now that the FileMiddleware is registered, a file like \u201cPublic/images/logo.png\u201d can be linked from a Leaf template as img src=\"/images/logo.png\"/ . CORSMiddleware Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. REST APIs built in Vapor will require a CORS policy in order to safely return requests to modern web browsers. An example configuration could look something like this: var middlewares = MiddlewareConfig () let corsConfiguration = CORSMiddleware . Configuration ( allowedOrigin : . all , allowedMethods : [. GET , . POST , . PUT , . OPTIONS , . DELETE , . PATCH ], allowedHeaders : [. accept , . authorization , . contentType , . origin , . xRequestedWith , . userAgent , . accessControlAllowOrigin ] ) let corsMiddleware = CORSMiddleware ( configuration : corsConfiguration ) middlewares . use ( corsMiddleware ) middlewares . use ( ErrorMiddleware . self ) services . register ( middlewares ) Given that thrown errors are immediately returned to the client, the CORSMiddleware must be listed before the ErrorMiddleware ; otherwise the HTTP error response will be returned without CORS headers, and cannot be read by the browser. Authentication and Sessions Middleware The Vapor Auth package has middlewares that can do basic user validation, token validation, and manage sessions. See the Auth documentation for an outline of the AuthMiddleware . Middleware API Information on how middleware works and authoring custom middleware can be found in the Vapor API Documentation .","title":"Middleware"},{"location":"vapor/middleware/#middleware","text":"Middleware is a logic chain between the client and a Vapor route handler. It allows you to make operations on incoming requests before they get to the route handler, and on outgoing responses before they go to the client.","title":"Middleware"},{"location":"vapor/middleware/#configuration-and-errormiddleware","text":"Middleware is registered in your config.swift file. ErrorMiddleware is a very common example; it will take a thrown error in your software and convert it to a legible HTTP response code. var middlewares = MiddlewareConfig () middlewares . use ( ErrorMiddleware . self ) middlewares . use ( FileMiddleware . self ) // etc. services . register ( middlewares ) You will often run several middlewares in a single project. These middlewares are stacked up, and then registered together. The order in which middleware are listed can sometimes matter (see CORSMiddleware below).","title":"Configuration, and ErrorMiddleware"},{"location":"vapor/middleware/#filemiddleware","text":"FileMiddleware enables the serving of assets from the Public folder of your project to the client. You might include static files like stylesheets or bitmap images here. var middlewares = MiddlewareConfig () middlewares . use ( FileMiddleware . self ) services . register ( middlewares ) Now that the FileMiddleware is registered, a file like \u201cPublic/images/logo.png\u201d can be linked from a Leaf template as img src=\"/images/logo.png\"/ .","title":"FileMiddleware"},{"location":"vapor/middleware/#corsmiddleware","text":"Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. REST APIs built in Vapor will require a CORS policy in order to safely return requests to modern web browsers. An example configuration could look something like this: var middlewares = MiddlewareConfig () let corsConfiguration = CORSMiddleware . Configuration ( allowedOrigin : . all , allowedMethods : [. GET , . POST , . PUT , . OPTIONS , . DELETE , . PATCH ], allowedHeaders : [. accept , . authorization , . contentType , . origin , . xRequestedWith , . userAgent , . accessControlAllowOrigin ] ) let corsMiddleware = CORSMiddleware ( configuration : corsConfiguration ) middlewares . use ( corsMiddleware ) middlewares . use ( ErrorMiddleware . self ) services . register ( middlewares ) Given that thrown errors are immediately returned to the client, the CORSMiddleware must be listed before the ErrorMiddleware ; otherwise the HTTP error response will be returned without CORS headers, and cannot be read by the browser.","title":"CORSMiddleware"},{"location":"vapor/middleware/#authentication-and-sessions-middleware","text":"The Vapor Auth package has middlewares that can do basic user validation, token validation, and manage sessions. See the Auth documentation for an outline of the AuthMiddleware .","title":"Authentication and Sessions Middleware"},{"location":"vapor/middleware/#middleware-api","text":"Information on how middleware works and authoring custom middleware can be found in the Vapor API Documentation .","title":"Middleware API"},{"location":"vapor/sessions/","text":"Using Sessions This guide will show you how to use sessions in Vapor to maintain state for a connected client. Sessions work by creating unique identifiers for each new client and asking the client to supply this identifier with each request. When the next request is received, Vapor uses this unique identifier to restore the session data. This identifier could be transmitted in any format, but it is almost always done with cookies and that is how Vapor's sessions work. When a new client connects and session data is set, Vapor will return a Set-Cookie header. The client is then expected to re-supply the value with each request in a Cookie header. All browsers do this automatically. If your ever decide to invalidate the session, Vapor will delete any related data and notify the client that their cookie is no longer valid. Middleware The first step to using sessions is enabling SessionsMiddleware . This can be done globally for the entire application or on a per-route basis. Globally To globally enable sessions, add the middleware to your MiddlewareConfig . var middlewares = MiddlewareConfig . default () middlewares . use ( SessionsMiddleware . self ) services . register ( middlewares ) This is usually done in configure.swift . Per Route To enable sessions for a group of routes, use the grouped(...) methods on Router . // create a grouped router at /sessions w/ sessions enabled let sessions = router . grouped ( sessions ). grouped ( SessionsMiddleware . self ) // create a route at GET /sessions/foo sessions . get ( foo ) { req in // use sessions } Sessions When SessionsMiddleware boots it will attempt to make a Sessions and a SessionsConfig . Vapor will use an in-memory session by default. You can override both of these services by registering them in configure.swift . You can use Fluent databases (like MySQL, PostgreSQL, etc) or caches like Redis to store your sessions. See the respective guides for more information. Session Once you have SessionsMiddleware enabled, you can use req.session() to access the session. Here is a simple example that does simple CRUD operations on a \"name\" value in the session. // create a route at GET /sessions/get sessions . get ( get ) { req - String in // access name from session or return n/a return try req . session ()[ name ] ?? n/a } // create a route at GET /sessions/set/:name sessions . get ( set , String . parameter ) { req - String in // get router param let name = try req . parameters . next ( String . self ) // set name to session at key name try req . session ()[ name ] = name // return the newly set name return name } // create a route at GET /sessions/del sessions . get ( del ) { req - String in // destroy the session try req . destroySession () // signal success return done } That's it, congratulations on getting sessions working!","title":"Sessions"},{"location":"vapor/sessions/#using-sessions","text":"This guide will show you how to use sessions in Vapor to maintain state for a connected client. Sessions work by creating unique identifiers for each new client and asking the client to supply this identifier with each request. When the next request is received, Vapor uses this unique identifier to restore the session data. This identifier could be transmitted in any format, but it is almost always done with cookies and that is how Vapor's sessions work. When a new client connects and session data is set, Vapor will return a Set-Cookie header. The client is then expected to re-supply the value with each request in a Cookie header. All browsers do this automatically. If your ever decide to invalidate the session, Vapor will delete any related data and notify the client that their cookie is no longer valid.","title":"Using Sessions"},{"location":"vapor/sessions/#middleware","text":"The first step to using sessions is enabling SessionsMiddleware . This can be done globally for the entire application or on a per-route basis.","title":"Middleware"},{"location":"vapor/sessions/#globally","text":"To globally enable sessions, add the middleware to your MiddlewareConfig . var middlewares = MiddlewareConfig . default () middlewares . use ( SessionsMiddleware . self ) services . register ( middlewares ) This is usually done in configure.swift .","title":"Globally"},{"location":"vapor/sessions/#per-route","text":"To enable sessions for a group of routes, use the grouped(...) methods on Router . // create a grouped router at /sessions w/ sessions enabled let sessions = router . grouped ( sessions ). grouped ( SessionsMiddleware . self ) // create a route at GET /sessions/foo sessions . get ( foo ) { req in // use sessions }","title":"Per Route"},{"location":"vapor/sessions/#sessions","text":"When SessionsMiddleware boots it will attempt to make a Sessions and a SessionsConfig . Vapor will use an in-memory session by default. You can override both of these services by registering them in configure.swift . You can use Fluent databases (like MySQL, PostgreSQL, etc) or caches like Redis to store your sessions. See the respective guides for more information.","title":"Sessions"},{"location":"vapor/sessions/#session","text":"Once you have SessionsMiddleware enabled, you can use req.session() to access the session. Here is a simple example that does simple CRUD operations on a \"name\" value in the session. // create a route at GET /sessions/get sessions . get ( get ) { req - String in // access name from session or return n/a return try req . session ()[ name ] ?? n/a } // create a route at GET /sessions/set/:name sessions . get ( set , String . parameter ) { req - String in // get router param let name = try req . parameters . next ( String . self ) // set name to session at key name try req . session ()[ name ] = name // return the newly set name return name } // create a route at GET /sessions/del sessions . get ( del ) { req - String in // destroy the session try req . destroySession () // signal success return done } That's it, congratulations on getting sessions working!","title":"Session"},{"location":"vapor/websocket/","text":"Using WebSockets Vapor includes convenience methods for working with the lower level WebSocket client and server . Server Vapor's WebSocket server includes the ability to route incoming requests just like its HTTP server. When Vapor's main HTTP Server boots it will attempt to create a WebSocketServer . If one is registered, it will be added as an HTTP upgrade handler to the server. So to create a WebSocket server, all you need to do is register one in configure.swift . // Create a new NIO websocket server let wss = NIOWebSocketServer . default () // Add WebSocket upgrade support to GET /echo wss . get ( echo ) { ws , req in // Add a new on text callback ws . onText { ws , text in // Simply echo any received text ws . send ( text ) } } // Register our server services . register ( wss , as : WebSocketServer . self ) That's it. Next time you boot your server, you will be able to perform a WebSocket upgrade at GET /echo . You can test this using a simple command line tool called wsta available for macOS and Linux. $ wsta ws://localhost:8080/echo Connected to ws://localhost:8080/echo hello, world! hello, world! Parameters Like Vapor's HTTP router, you can also use routing parameters with your WebSocket server. // Add WebSocket upgrade support to GET /chat/:name wss . get ( chat , String . parameter ) { ws , req in let name = try req . parameters . next ( String . self ) ws . send ( Welcome, \\( name ) ! ) // ... } Now let's test this new route: $ wsta ws://localhost:8080/chat/Vapor Connected to ws://localhost:8080/chat/Vapor Welcome, Vapor! Client Vapor also supports connecting to WebSocket servers as a client. The easiest way to connect to a WebSocket server is through the webSocket(...) method on Client . For this example, we will assume our application connects to a WebSocket server in boot.swift // connect to echo.websocket.org let done = try app . client (). webSocket ( ws://echo.websocket.org ). flatMap { ws - Future Void in // setup an on text callback that will print the echo ws . onText { ws , text in print ( rec: \\( text ) ) // close the websocket connection after we recv the echo ws . close () } // when the websocket first connects, send message ws . send ( hello, world! ) // return a future that will complete when the websocket closes return ws . onClose } print ( done ) // Future Void // wait for the websocket to close try done . wait ()","title":"WebSocket"},{"location":"vapor/websocket/#using-websockets","text":"Vapor includes convenience methods for working with the lower level WebSocket client and server .","title":"Using WebSockets"},{"location":"vapor/websocket/#server","text":"Vapor's WebSocket server includes the ability to route incoming requests just like its HTTP server. When Vapor's main HTTP Server boots it will attempt to create a WebSocketServer . If one is registered, it will be added as an HTTP upgrade handler to the server. So to create a WebSocket server, all you need to do is register one in configure.swift . // Create a new NIO websocket server let wss = NIOWebSocketServer . default () // Add WebSocket upgrade support to GET /echo wss . get ( echo ) { ws , req in // Add a new on text callback ws . onText { ws , text in // Simply echo any received text ws . send ( text ) } } // Register our server services . register ( wss , as : WebSocketServer . self ) That's it. Next time you boot your server, you will be able to perform a WebSocket upgrade at GET /echo . You can test this using a simple command line tool called wsta available for macOS and Linux. $ wsta ws://localhost:8080/echo Connected to ws://localhost:8080/echo hello, world! hello, world!","title":"Server"},{"location":"vapor/websocket/#parameters","text":"Like Vapor's HTTP router, you can also use routing parameters with your WebSocket server. // Add WebSocket upgrade support to GET /chat/:name wss . get ( chat , String . parameter ) { ws , req in let name = try req . parameters . next ( String . self ) ws . send ( Welcome, \\( name ) ! ) // ... } Now let's test this new route: $ wsta ws://localhost:8080/chat/Vapor Connected to ws://localhost:8080/chat/Vapor Welcome, Vapor!","title":"Parameters"},{"location":"vapor/websocket/#client","text":"Vapor also supports connecting to WebSocket servers as a client. The easiest way to connect to a WebSocket server is through the webSocket(...) method on Client . For this example, we will assume our application connects to a WebSocket server in boot.swift // connect to echo.websocket.org let done = try app . client (). webSocket ( ws://echo.websocket.org ). flatMap { ws - Future Void in // setup an on text callback that will print the echo ws . onText { ws , text in print ( rec: \\( text ) ) // close the websocket connection after we recv the echo ws . close () } // when the websocket first connects, send message ws . send ( hello, world! ) // return a future that will complete when the websocket closes return ws . onClose } print ( done ) // Future Void // wait for the websocket to close try done . wait ()","title":"Client"},{"location":"version/1_5/","text":"Redirecting...","title":"1.5"},{"location":"version/1_5/#redirecting","text":"","title":"Redirecting..."},{"location":"version/2_0/","text":"Redirecting...","title":"2.0"},{"location":"version/2_0/#redirecting","text":"","title":"Redirecting..."},{"location":"version/3_0/","text":"Redirecting...","title":"3.0"},{"location":"version/3_0/#redirecting","text":"","title":"Redirecting..."},{"location":"version/support/","text":"Version Support Vapor 3.0 is currently active. Vapor 2.4 is being maintained until November 2018. Vapor 1.5 is no longer maintained (ended November 2017). Core All packages in the Vapor GitHub are maintained according to the following rules. Active While a version is active, reported security issues and bugs are fixed. Additionally, new features and optimizations may be added. If new API is added, the minor version number will be incremented. At no point can existing API be removed or broken during an active version. Semver is strictly followed and tested. Maintenance When a new version of Vapor is released, the previous version will enter a maintenance phase which lasts for six months. During this phase, critical security issues and bugs will be fixed. No new features will be added. Note Only the latest minor version will be maintained. Unstable The master branch is the latest development version of Vapor and is constantly changing. Before a new version of Vapor is released, there may be unstable alpha and beta phases in which you are welcome to test and provide feedback on the changes. Community All packages in the Vapor Community GitHub are maintained in strict accordance of semver. Violations of semver should be reported as issues to the offending package's GitHub page.","title":"Support"},{"location":"version/support/#version-support","text":"Vapor 3.0 is currently active. Vapor 2.4 is being maintained until November 2018. Vapor 1.5 is no longer maintained (ended November 2017).","title":"Version Support"},{"location":"version/support/#core","text":"All packages in the Vapor GitHub are maintained according to the following rules.","title":"Core"},{"location":"version/support/#active","text":"While a version is active, reported security issues and bugs are fixed. Additionally, new features and optimizations may be added. If new API is added, the minor version number will be incremented. At no point can existing API be removed or broken during an active version. Semver is strictly followed and tested.","title":"Active"},{"location":"version/support/#maintenance","text":"When a new version of Vapor is released, the previous version will enter a maintenance phase which lasts for six months. During this phase, critical security issues and bugs will be fixed. No new features will be added. Note Only the latest minor version will be maintained.","title":"Maintenance"},{"location":"version/support/#unstable","text":"The master branch is the latest development version of Vapor and is constantly changing. Before a new version of Vapor is released, there may be unstable alpha and beta phases in which you are welcome to test and provide feedback on the changes.","title":"Unstable"},{"location":"version/support/#community","text":"All packages in the Vapor Community GitHub are maintained in strict accordance of semver. Violations of semver should be reported as issues to the offending package's GitHub page.","title":"Community"},{"location":"version/upgrading/","text":"Upgrading Versions This document provides information about changes between version and tips for migrating your projects. 2.4 to 3.0 Vapor 3 has been rewritten from the ground up to be async and event-driven. This release contains the most changes of any previous release (and most likely any future release). Because of this, it is recommended that to migrate your projects you start by creating a new, empty template and migrate by copy / pasting code over to the new project. We recommend reading the Getting Started Hello, world! section for Vapor 3 to familiarize yourself with the new APIs. Async The biggest change in Vapor 3 is that the framework is now completely asynchronous. When you call methods that need to perform slow work like network requests or disk access instead of blocking they will now return a Future T . Futures are values that may not exist yet, so you cannot interact with them directly. Instead, you must use map / flatMap to access the values. // vapor 2 let res = try drop . client . get ( http://vapor.codes ) print ( res . status ) // HTTPStatus return res . status // vapor 3 let f = try req . client (). get ( http://vapor.codes ). map { res in print ( res . http . status ) // HTTPStatus return res . http . status } print ( f ) // Future HTTPStatus See Async Getting Started to learn more. Application Services Droplet has been renamed to Application and is now a service-container. In Vapor 2, the Droplet had stored properties for things you would need during development (like views, hashers, etc). In Vapor 3, this is all done via services. While the Application is a service-container, you should not use it from your route closures. This is to prevent race conditions since Vapor runs on multiple threads (event loops). Instead, use the Request that is supplied to your route closure. This has a copy of all of the application's services for you to use. // vapor 2 return try drop . view . make ( myView ) // vapor 3 return try req . make ( ViewRenderer . self ). render ( myView ) // shorthand return try req . view (). render ( myView ) See Service Getting Started to learn more. Database Connections In Vapor 3, database connections are no longer statically accessible. This makes doing things like transactions and connection pooling much more predictable and performant. In order to create a QueryBuilder in Fluent 3, you will need access to something DatabaseConnectable . Most often you can just use the incoming Request , but you can also create connections manually if you need. // vapor 2 User . makeQuery (). all () // vapor 3 User . query ( on : req ). all () See DatabaseKit Getting Started to learn more. Migrating SQL Database When migrating from Fluent 2 to 3 you may need to update your fluent table to support the new format. In Fluent 3, the migration log table has the following changes: id is now a UUID . createdAt and updatedAt must now be camelCase . Depending on how your Fluent database was configured, your tables may already be in the correct format. If not, you can run the following queries to transfer the table data. Use this query if your column names were already set to camelCase . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , createdAt , updatedAt from fluent_old ); Use this query if your column names were snake_case . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , created_at as createdAt , updated_at as updatedAt from fluent_old ); After you have verified the table was transferred properly, you can drop the old fluent table. DROP TABLE fluent_old ; Work in progress This migration guide is a work in progress. Please feel free to add any migration tips here by submitting a PR. Join the #upgrading-to-3 in Vapor's team chat to ask questions and get help in real time. Also check out Getting started with Vapor 3 , an in-depth article about the differences between Vapor 2 and 3. This article was written by two developers from an app development company using Vapor.","title":"Upgrading"},{"location":"version/upgrading/#upgrading-versions","text":"This document provides information about changes between version and tips for migrating your projects.","title":"Upgrading Versions"},{"location":"version/upgrading/#24-to-30","text":"Vapor 3 has been rewritten from the ground up to be async and event-driven. This release contains the most changes of any previous release (and most likely any future release). Because of this, it is recommended that to migrate your projects you start by creating a new, empty template and migrate by copy / pasting code over to the new project. We recommend reading the Getting Started Hello, world! section for Vapor 3 to familiarize yourself with the new APIs.","title":"2.4 to 3.0"},{"location":"version/upgrading/#async","text":"The biggest change in Vapor 3 is that the framework is now completely asynchronous. When you call methods that need to perform slow work like network requests or disk access instead of blocking they will now return a Future T . Futures are values that may not exist yet, so you cannot interact with them directly. Instead, you must use map / flatMap to access the values. // vapor 2 let res = try drop . client . get ( http://vapor.codes ) print ( res . status ) // HTTPStatus return res . status // vapor 3 let f = try req . client (). get ( http://vapor.codes ). map { res in print ( res . http . status ) // HTTPStatus return res . http . status } print ( f ) // Future HTTPStatus See Async Getting Started to learn more.","title":"Async"},{"location":"version/upgrading/#application-services","text":"Droplet has been renamed to Application and is now a service-container. In Vapor 2, the Droplet had stored properties for things you would need during development (like views, hashers, etc). In Vapor 3, this is all done via services. While the Application is a service-container, you should not use it from your route closures. This is to prevent race conditions since Vapor runs on multiple threads (event loops). Instead, use the Request that is supplied to your route closure. This has a copy of all of the application's services for you to use. // vapor 2 return try drop . view . make ( myView ) // vapor 3 return try req . make ( ViewRenderer . self ). render ( myView ) // shorthand return try req . view (). render ( myView ) See Service Getting Started to learn more.","title":"Application & Services"},{"location":"version/upgrading/#database-connections","text":"In Vapor 3, database connections are no longer statically accessible. This makes doing things like transactions and connection pooling much more predictable and performant. In order to create a QueryBuilder in Fluent 3, you will need access to something DatabaseConnectable . Most often you can just use the incoming Request , but you can also create connections manually if you need. // vapor 2 User . makeQuery (). all () // vapor 3 User . query ( on : req ). all () See DatabaseKit Getting Started to learn more.","title":"Database Connections"},{"location":"version/upgrading/#migrating-sql-database","text":"When migrating from Fluent 2 to 3 you may need to update your fluent table to support the new format. In Fluent 3, the migration log table has the following changes: id is now a UUID . createdAt and updatedAt must now be camelCase . Depending on how your Fluent database was configured, your tables may already be in the correct format. If not, you can run the following queries to transfer the table data. Use this query if your column names were already set to camelCase . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , createdAt , updatedAt from fluent_old ); Use this query if your column names were snake_case . ALTER TABLE fluent RENAME TO fluent_old ; CREATE TABLE fluent AS ( SELECT UUID () as id , name , batch , created_at as createdAt , updated_at as updatedAt from fluent_old ); After you have verified the table was transferred properly, you can drop the old fluent table. DROP TABLE fluent_old ;","title":"Migrating SQL Database"},{"location":"version/upgrading/#work-in-progress","text":"This migration guide is a work in progress. Please feel free to add any migration tips here by submitting a PR. Join the #upgrading-to-3 in Vapor's team chat to ask questions and get help in real time. Also check out Getting started with Vapor 3 , an in-depth article about the differences between Vapor 2 and 3. This article was written by two developers from an app development company using Vapor.","title":"Work in progress"},{"location":"websocket/getting-started/","text":"Getting Started with WebSocket WebSocket ( vapor/websocket ) is a non-blocking, event-driven WebSocket library built on SwiftNIO. It makes working with SwiftNIO's WebSocket handlers easy and provides integration with HTTP clients and servers. Creating a WebSocket echo server takes just a few lines of code. Tip If you use Vapor, most of WebSocket's APIs will be wrapped by more convenient methods. Vapor This package is included with Vapor and exported by default. You will have access to all WebSocket APIs when you import Vapor . import Vapor Standalone The WebSocket package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as a WebSocket framework any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/websocket.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ WebSocket , ... ]) ] ) Use import WebSocket to access the APIs. The rest of this guide will give you an overview of what is available in the WebSocket package. As always, feel free to visit the API docs for more in-depth information.","title":"Getting Started"},{"location":"websocket/getting-started/#getting-started-with-websocket","text":"WebSocket ( vapor/websocket ) is a non-blocking, event-driven WebSocket library built on SwiftNIO. It makes working with SwiftNIO's WebSocket handlers easy and provides integration with HTTP clients and servers. Creating a WebSocket echo server takes just a few lines of code. Tip If you use Vapor, most of WebSocket's APIs will be wrapped by more convenient methods.","title":"Getting Started with WebSocket"},{"location":"websocket/getting-started/#vapor","text":"This package is included with Vapor and exported by default. You will have access to all WebSocket APIs when you import Vapor . import Vapor","title":"Vapor"},{"location":"websocket/getting-started/#standalone","text":"The WebSocket package is lightweight, pure Swift, and only depends on SwiftNIO. This means it can be used as a WebSocket framework any Swift project\u2014even one not using Vapor. To include it in your package, add the following to your Package.swift file. // swift-tools-version:4.0 import PackageDescription let package = Package ( name : Project , dependencies : [ ... . package ( url : https://github.com/vapor/websocket.git , from : 1.0.0 ), ], targets : [ . target ( name : Project , dependencies : [ WebSocket , ... ]) ] ) Use import WebSocket to access the APIs. The rest of this guide will give you an overview of what is available in the WebSocket package. As always, feel free to visit the API docs for more in-depth information.","title":"Standalone"},{"location":"websocket/overview/","text":"Using WebSockets Unlike HTTP, WebSockets allow you to communicate between client and server in an open, interactive way. You can send messages (called frames) in either text or binary format. Both the client and the server can send as many messages as they want at a time, without having to wait for responses. Although WebSocket is its own protocol, it still uses HTTP to get setup. Every WebSocket connection will start with an HTTP request with special headers followed by an HTTP response with status 101 Switching Protocols . After this initial handshake, the connection is a WebSocket connection. WebSocket The WebSocket class represents a connected WebSocket client. You can use this to set callbacks for receiving data and to send data. let ws : WebSocket = ... // Send an initial message to this WebSocket ws . send ( Hello! ) // Set a new callback for receiving text formatted data ws . onText { ws , string in // Echo the text back, reversed. ws . send ( string . reversed ()) } Tip All callbacks will receive a reference to the WebSocket . Use these if you need to send data to avoid creating a reference cycle. The WebSocket has an onClose future that will be completed when the connection closes. You can use close() to close the connection yourself. Server WebSocket servers connect to one or more WebSocket clients at a time. As mentioned previously, WebSocket connections must start via an HTTP request and response handshake. Because of this, WebSocket servers are built on top of HTTP servers using the HTTP upgrade mechanism. // First, create an HTTPProtocolUpgrader let ws = HTTPServer . webSocketUpgrader ( shouldUpgrade : { req in // Returning nil in this closure will reject upgrade if req . url . path == /deny { return nil } // Return any additional headers you like, or just empty return [:] }, onUpgrade : { ws , req in // This closure will be called with each new WebSocket client ws . send ( Connected ) ws . onText { ws , string in ws . send ( string . reversed ()) } }) // Next, create your server, adding the WebSocket upgrader let server = try HTTPServer . start ( ... upgraders : [ ws ], ... ). wait () // Run the server. try server . onClose . wait () Seealso Visit HTTP \u2192 Server for more information on setting up an HTTP server. The WebSocket protocol upgrader consists of two callbacks. The first callback shouldUpgrade receives the incoming HTTP request that is requesting upgrade. This callback decides whether or not to complete the upgrade based on the contents of the request. If nil is returned in this closure, the upgrade will be rejected. The second callback onUpgrade is called each time a new WebSocket client connects. This is where you configure your callbacks and send any initial data. Warning The upgrade closures may be called on any event loop. Be careful to avoid race conditions if you must access external variables. Client You can also use the WebSocket package to connect to a WebSocket server. Just like the WebSocket server used an HTTP server, the WebSocket client uses HTTP client. // Create a new WebSocket connected to echo.websocket.org let ws = try HTTPClient . webSocket ( hostname : echo.websocket.org , on : ...). wait () // Set a new callback for receiving text formatted data. ws . onText { ws , text in print ( Server echo: \\( text ) ) } // Send a message. ws . send ( Hello, world! ) // Wait for the Websocket to close. try ws . onClose . wait () Seealso Visit HTTP \u2192 Client for more information on setting up an HTTP client. API Docs Check out the API docs for more in-depth information about all of the methods.","title":"Overview"},{"location":"websocket/overview/#using-websockets","text":"Unlike HTTP, WebSockets allow you to communicate between client and server in an open, interactive way. You can send messages (called frames) in either text or binary format. Both the client and the server can send as many messages as they want at a time, without having to wait for responses. Although WebSocket is its own protocol, it still uses HTTP to get setup. Every WebSocket connection will start with an HTTP request with special headers followed by an HTTP response with status 101 Switching Protocols . After this initial handshake, the connection is a WebSocket connection.","title":"Using WebSockets"},{"location":"websocket/overview/#websocket","text":"The WebSocket class represents a connected WebSocket client. You can use this to set callbacks for receiving data and to send data. let ws : WebSocket = ... // Send an initial message to this WebSocket ws . send ( Hello! ) // Set a new callback for receiving text formatted data ws . onText { ws , string in // Echo the text back, reversed. ws . send ( string . reversed ()) } Tip All callbacks will receive a reference to the WebSocket . Use these if you need to send data to avoid creating a reference cycle. The WebSocket has an onClose future that will be completed when the connection closes. You can use close() to close the connection yourself.","title":"WebSocket"},{"location":"websocket/overview/#server","text":"WebSocket servers connect to one or more WebSocket clients at a time. As mentioned previously, WebSocket connections must start via an HTTP request and response handshake. Because of this, WebSocket servers are built on top of HTTP servers using the HTTP upgrade mechanism. // First, create an HTTPProtocolUpgrader let ws = HTTPServer . webSocketUpgrader ( shouldUpgrade : { req in // Returning nil in this closure will reject upgrade if req . url . path == /deny { return nil } // Return any additional headers you like, or just empty return [:] }, onUpgrade : { ws , req in // This closure will be called with each new WebSocket client ws . send ( Connected ) ws . onText { ws , string in ws . send ( string . reversed ()) } }) // Next, create your server, adding the WebSocket upgrader let server = try HTTPServer . start ( ... upgraders : [ ws ], ... ). wait () // Run the server. try server . onClose . wait () Seealso Visit HTTP \u2192 Server for more information on setting up an HTTP server. The WebSocket protocol upgrader consists of two callbacks. The first callback shouldUpgrade receives the incoming HTTP request that is requesting upgrade. This callback decides whether or not to complete the upgrade based on the contents of the request. If nil is returned in this closure, the upgrade will be rejected. The second callback onUpgrade is called each time a new WebSocket client connects. This is where you configure your callbacks and send any initial data. Warning The upgrade closures may be called on any event loop. Be careful to avoid race conditions if you must access external variables.","title":"Server"},{"location":"websocket/overview/#client","text":"You can also use the WebSocket package to connect to a WebSocket server. Just like the WebSocket server used an HTTP server, the WebSocket client uses HTTP client. // Create a new WebSocket connected to echo.websocket.org let ws = try HTTPClient . webSocket ( hostname : echo.websocket.org , on : ...). wait () // Set a new callback for receiving text formatted data. ws . onText { ws , text in print ( Server echo: \\( text ) ) } // Send a message. ws . send ( Hello, world! ) // Wait for the Websocket to close. try ws . onClose . wait () Seealso Visit HTTP \u2192 Client for more information on setting up an HTTP client.","title":"Client"},{"location":"websocket/overview/#api-docs","text":"Check out the API docs for more in-depth information about all of the methods.","title":"API Docs"}]}
\ No newline at end of file
diff --git a/build/3.0/service/getting-started/index.html b/build/3.0/service/getting-started/index.html
index bffc24e5..659e9be5 100644
--- a/build/3.0/service/getting-started/index.html
+++ b/build/3.0/service/getting-started/index.html
@@ -1797,6 +1797,18 @@
+
+
+
+
+
+
Middleware is a logic chain between the client and a Vapor route handler. It allows you to make operations on incoming requests before they get to the route handler, and on outgoing responses before they go to the client.
Middleware is registered in your config.swift file. ErrorMiddleware is a very common example; it will take a thrown error in your software and convert it to a legible HTTP response code.
+
varmiddlewares=MiddlewareConfig()
+middlewares.use(ErrorMiddleware.self)
+middlewares.use(FileMiddleware.self)
+// etc.
+services.register(middlewares)
+
+
+
+
You will often run several middlewares in a single project. These middlewares are stacked up, and then registered together. The order in which middleware are listed can sometimes matter (see CORSMiddleware below).
FileMiddleware enables the serving of assets from the Public folder of your project to the client. You might include static files like stylesheets or bitmap images here.
Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. REST APIs built in Vapor will require a CORS policy in order to safely return requests to modern web browsers.
+
An example configuration could look something like this:
Given that thrown errors are immediately returned to the client, the CORSMiddleware must be listed before the ErrorMiddleware; otherwise the HTTP error response will be returned without CORS headers, and cannot be read by the browser.
The Vapor Auth package has middlewares that can do basic user validation, token validation, and manage sessions. See the Auth documentation for an outline of the AuthMiddleware.