diff --git a/2.0/docs/advanced/modules.md b/2.0/docs/advanced/modules.md deleted file mode 100644 index e69de29b..00000000 diff --git a/2.0/docs/bits/overview.md b/2.0/docs/bits/overview.md index 515ef06d..e2088d8a 100644 --- a/2.0/docs/bits/overview.md +++ b/2.0/docs/bits/overview.md @@ -2,9 +2,6 @@ The bits package is included in Vapor by default and provides a convenient API for working with bytes. -!!! note - Use `import Bits` to use this package. - ## Typealias The bits package provides two type-aliases for bytes. diff --git a/2.0/docs/settings/config.md b/2.0/docs/configs/config.md similarity index 68% rename from 2.0/docs/settings/config.md rename to 2.0/docs/configs/config.md index 514f4540..a202247f 100644 --- a/2.0/docs/settings/config.md +++ b/2.0/docs/configs/config.md @@ -1,6 +1,3 @@ -!!! warning - This section may contain outdated information. - # Config An application's configuration settings. Cloud applications generally require complex configurations that can adjust based on their environment. Vapor intends to provide a flexible configuration interaction that can be customized for a given user. @@ -12,47 +9,45 @@ For Vapor applications, configuration files are expected to be nested under a to ```bash ./ ├── Config/ -│ ├── servers.json +│ ├── server.json ``` And an example of how this might look: ```JSON { - "http": { "host": "0.0.0.0", - "port": 8080 - } + "port": 8080, + "securityLayer": "none" } ``` -What that's saying, is that our application should start a single server named 'http' serving port `8080` on host `0.0.0.0`. This represents the following url: `http://localhost:8080`. +What that's saying, is that our application should start a server on port `8080` and host `0.0.0.0`. This represents the following url: `http://localhost:8080`. ### Custom Keys -Let's add a custom key to the `servers.json` file: +Let's add a custom key to the `server.json` file: ```JSON { - "http": { "host": "0.0.0.0", "port": 8080, + "securityLayer": "none", "custom-key": "custom value" - } } ``` This can be accessed from your application's config using the following. ```swift -let customValue = drop.config["servers", "http", "custom-key"]?.string ?? "default" +let customValue = drop.config["server", "custom-key"]?.string ?? "default" ``` That's it, feel free to add and utilize keys as necessary to make your application configuration easier. ## Config Syntax -You can access your config directory with the following syntax. `app.config[<#file-name#>, <#path#>, <#to#>, <#file#>]`. For example, let's hypothesize that in addition to the `servers.json` file we mentioned earlier, there is also a `keys.json` that looks like this: +You can access your config directory with the following syntax. `app.config[fileName, path, to, key]`. For example, let's hypothesize that in addition to the `server.json` file we mentioned earlier, there is also a `keys.json` that looks like this: ```JSON { @@ -110,7 +105,7 @@ Config files will be accessed in the following priority. 3. Config/name-of-environment/ 4. Config/ -What this means is that if a user calls `app.config["servers", "host"]`, the key will be searched in the CLI first, then the `secrets/` directory, then the top level default configs. +What this means is that if a user calls `app.config["server", "host"]`, the key will be searched in the CLI first, then the `secrets/` directory, then the top level default configs. > `secrets/` directory should very likely be added to the gitignore. @@ -118,59 +113,39 @@ What this means is that if a user calls `app.config["servers", "host"]`, the key Let's start with the following JSON files. -#### `servers.json` +#### `server.json` ```JSON { - "http": { "host": "0.0.0.0", "port": 9000 - } } ``` -#### `production/servers.json` +#### `production/server.json` ```JSON { - "http": { "host": "127.0.0.1", "port": "$PORT" - } } ``` > The `"$NAME"` syntax is available for all values to access environment variables. -Please notice that `servers.json`, and `production/servers.json` both declare the same keys: `host`, and `port`. In our application, we'll call: +Please notice that `server.json`, and `production/server.json` both declare the same keys: `host`, and `port`. In our application, we'll call: ```swift // will load 0.0.0.0 or 127.0.0.1 based on above config -let host = drop.config["servers", "http", "host"]?.string ?? "0.0.0.0" +let host = drop.config["server" "host"]?.string ?? "0.0.0.0" // will load 9000, or environment variable port. -let port = drop.config["servers", "http", "port"]?.int ?? 9000 +let port = drop.config["server", "port"]?.int ?? 9000 ``` ## COMMAND LINE In addition to json files nested within the `Config/` directory, we can also use the command line to pass arguments into our config. By default, these values will be set as the "cli" file, but more complex options are also available. -#### 1. `--KEY=VALUE` - -Arguments set through the command line can be accessed through config's cli file. For example, the following CLI command: - -```bash ---mongo-password=$MONGO_PASSWORD -``` - -would be accessible within your application by using the following: - -```swift -let mongoPassword = drop.config["cli", "mongo-password"]?.string -``` - -#### 2. `--CONFIG:FILE-NAME.KEY=CUSTOM-VALUE` - If you want command line arguments set to a file besides "cli", you can use this more advanced specification. For example, the following CLI command: ```bash diff --git a/2.0/docs/core/overview.md b/2.0/docs/core/overview.md index ab7fb10f..550696b4 100644 --- a/2.0/docs/core/overview.md +++ b/2.0/docs/core/overview.md @@ -2,9 +2,6 @@ Core provides some conveniences for common tasks. -!!! note - Use `import Core` - ## Background Easily create a background thread using `background()` diff --git a/2.0/docs/deploy/nginx.md b/2.0/docs/deploy/nginx.md index a028e148..1fff8e10 100644 --- a/2.0/docs/deploy/nginx.md +++ b/2.0/docs/deploy/nginx.md @@ -1,11 +1,9 @@ -!!! warning - This section may contain outdated information. - # Deploying with Nginx Nginx is an extremely fast, battle tested, and easy-to-configure HTTP server and proxy. While Vapor supports directly serving HTTP requests with or without TLS, proxying behind Nginx can provide increased performance, security, and ease-of-use. -> Note: We recommend proxying Vapor HTTP servers behind Nginx. +!!! note + We recommend proxying Vapor HTTP servers behind Nginx. ## Overview @@ -19,7 +17,8 @@ An important feature of this middleman proxy is that it can alter or even redire The default port for receiving HTTP requests is port `80` (and `443` for HTTPS). When you bind a Vapor server to port `80`, it will directly receive and respond to the HTTP requests that come to your server. When adding a proxy like Nginx, you bind Vapor to an internal port, like port `8080`. -> Note: Ports greater than 1024 do not require `sudo` to bind. +!!! note + Ports greater than 1024 do not require `sudo` to bind. When Vapor is bound to a port besides `80` or `443`, it will not be accessible to the outside internet. You then bind Nginx to port `80` and configure it to route requests to your Vapor server bound at port `8080` (or whichever port you've chosen). @@ -30,6 +29,7 @@ And that's it. If Nginx is properly configured, you will see your Vapor app resp The first step is installing Nginx. One of the great parts of Nginx is the tremendous amount of community resources and documentation surrounding it. Because of this, we will not go into great detail here about installing Nginx as there is almost definitely a tutorial for your specific platform, OS, and provider. Tutorials: + - [How To Install Nginx on Ubuntu 14.04 LTS](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-14-04-lts) - [How To Install Nginx on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04) - [How to Deploy Nginx on Heroku](https://blog.codeship.com/how-to-deploy-nginx-on-heroku/) diff --git a/2.0/docs/deploy/supervisor.md b/2.0/docs/deploy/supervisor.md index fe9287ba..b343d555 100644 --- a/2.0/docs/deploy/supervisor.md +++ b/2.0/docs/deploy/supervisor.md @@ -1,6 +1,3 @@ -!!! warning - This section may contain outdated information. - # Supervisor [Supervisor](http://supervisord.org) is a process control system that makes it easy to start, stop, and restart your Vapor app. @@ -18,7 +15,7 @@ Each Vapor app on your server should have its own configuration file. For an exa ```sh [program:hello] -command=/home/vapor/hello/.build/release/App serve --env=production +command=/home/vapor/hello/.build/release/Run serve --env=production directory=/home/vapor/hello/ user=www-data stdout_logfile=/var/log/supervisor/%(program_name)-stdout.log @@ -42,9 +39,7 @@ Exported variables can be used in Vapor's configuration files with the `$` prefi `Config/production/servers.json ` ```json { - "my-server": { - "port": "$PORT" - } + "port": "$PORT" } ``` @@ -60,4 +55,5 @@ supervisorctl add hello supervisorctl start hello ``` -> Note: The `add` command may have already started your app. +!!! note + The `add` command may have already started your app. diff --git a/2.0/docs/getting-started/hello-world.md b/2.0/docs/getting-started/hello-world.md index 03b85cfd..0db31c51 100644 --- a/2.0/docs/getting-started/hello-world.md +++ b/2.0/docs/getting-started/hello-world.md @@ -126,24 +126,17 @@ Boot up the server by running the following command. vapor run serve ``` -You should see a message `Server starting...`. You can now visit `http://localhost:8080/plaintext` in your browser. +You should see a message `Server starting...`. + +You can now visit `localhost:8080/plaintext` in your browser or run + +```sh +curl localhost:8080/plaintext +``` !!! note Certain port numbers require super user access to bind. Simply run `sudo vapor run` to allow access. If you decide to run on a port besides `80`, make sure to direct your browser accordingly. -#### Production - -Serving your application in the production environment increases its security and performance. - -```sh -vapor run serve --env=production -``` - -Debug errors will be silenced while in the production environment, so make sure to check your logs for errors. - -!!! warning - If you compiled your application with `--release`, make sure to add that flag to the `vapor run` command as well. e.g., `vapor run serve --env=production --release`. - ### Hello, World You should see the following output in your browser window. @@ -157,3 +150,19 @@ Hello, world! + +#### Production + +Serving your application in the production environment increases its security and performance. + +```sh +vapor run serve --env=production +``` + +Some debug messages will be silenced while in the production environment, so make sure to check your logs for errors. + +!!! warning + If you compiled your application with `--release`, make sure to add that flag to the `vapor run` command as well. e.g., `vapor run serve --env=production --release`. + +For more information on deploying your code, check out the [deploy section](http://127.0.0.1:8000/deploy/nginx/). + diff --git a/2.0/docs/getting-started/install-on-macos.md b/2.0/docs/getting-started/install-on-macos.md index d7275735..8da60ad7 100644 --- a/2.0/docs/getting-started/install-on-macos.md +++ b/2.0/docs/getting-started/install-on-macos.md @@ -17,7 +17,7 @@ After Xcode 8 has been downloaded, you must open it to finish the installation. Double check the installation was successful by running: ```sh -eval "$(curl -sL check2.vapor.sh)" +eval "$(curl -sL check.vapor.sh)" ``` ## Install Vapor diff --git a/2.0/docs/getting-started/install-on-ubuntu.md b/2.0/docs/getting-started/install-on-ubuntu.md index 9f375a6e..b7db2af6 100644 --- a/2.0/docs/getting-started/install-on-ubuntu.md +++ b/2.0/docs/getting-started/install-on-ubuntu.md @@ -2,6 +2,16 @@ 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 system packages. @@ -14,6 +24,9 @@ Easily add Vapor's APT repo with this handy script. eval "$(curl -sL https://apt.vapor.sh)" ``` +!!! note + This command requires `curl` which can be installed using `sudo apt-get install curl` + ### Manual Or add the repo manually. @@ -37,7 +50,7 @@ sudo apt-get install swift vapor Double check the installation was successful by running: ```sh -eval "$(curl -sL check2.vapor.sh)" +eval "$(curl -sL check.vapor.sh)" ``` ## Next diff --git a/2.0/docs/getting-started/manual.md b/2.0/docs/getting-started/manual.md index d9aab94c..d4472ee8 100644 --- a/2.0/docs/getting-started/manual.md +++ b/2.0/docs/getting-started/manual.md @@ -1,6 +1,6 @@ # Manual Quickstart -Learn how to create a Vapor project _without_ the Toolbox using just Swift 3 and the Swift Package Manager (SPM). +Learn how to create a Vapor project _without_ the Toolbox using just Swift 3.1 and the Swift Package Manager (SPM). This document assumes that you have Swift 3.1 installed, if not please refer to [Swift.org](https://swift.org/getting-started/#installing-swift) before you can continue. diff --git a/2.0/docs/getting-started/toolbox.md b/2.0/docs/getting-started/toolbox.md index 1f0dfabe..1b470ae9 100644 --- a/2.0/docs/getting-started/toolbox.md +++ b/2.0/docs/getting-started/toolbox.md @@ -29,8 +29,8 @@ brew upgrade vapor ### APT ``` -apt-get update -apt-get install vapor +sudo apt-get update +sudo apt-get install vapor ``` ## Templates @@ -38,9 +38,19 @@ apt-get install vapor The toolbox can create a project from the Vapor basic-template or any other git repo. ```sh -vapor new [--template=] +vapor new [--template] ``` +| Name | Flag | Description | +|------|----------------|-----------------------------------| +| API | --template=api | JSON API with Fluent database. | +| Web | --template=web | HTML website with Leaf templates. | + + +!!! note + If you do not specify a template option, the API template will be used. + This may change in the future. + ### Options The toolbox will build an absolute URL based on what you pass as the template option. @@ -48,6 +58,5 @@ The toolbox will build an absolute URL based on what you pass as the template op - `--template=web` clones `http://github.com/vapor/web-template` - `--template=user/repo` clones `http://github.com/user/repo`. - `--template=http://example.com/repo-path` clones the full url given. +- `--branch=foo` can be used to specify a branch besides `master`. -!!! note - If you do not specify a template option, the project will be built from Vapor's [API template](https://github.com/vapor/api-template). diff --git a/2.0/docs/http/body.md b/2.0/docs/http/body.md index ace31ee0..a4ce792c 100644 --- a/2.0/docs/http/body.md +++ b/2.0/docs/http/body.md @@ -1,8 +1,3 @@ -!!! warning - This section may contain outdated information. - -> Module: `import HTTP` - # Body The `HTTP.Body` represents the payload of an `HTTP.Message`, and is used to pass the underlying data. Some examples of this in practice would be `JSON`, `HTML` text, or the bytes of an image. Let's look at the implementation: diff --git a/2.0/docs/http/client.md b/2.0/docs/http/client.md index 71d33407..b007730a 100644 --- a/2.0/docs/http/client.md +++ b/2.0/docs/http/client.md @@ -1,8 +1,3 @@ -!!! warning - This section may contain outdated information. - -> Module: `import HTTP` - # Client The client provided by `HTTP` is used to make outgoing requests to remote servers. Let's look at a simple outgoing request. @@ -12,9 +7,9 @@ The client provided by `HTTP` is used to make outgoing requests to remote server Let's jump right in to make a simple HTTP Request. Here's a basic `GET` request using your Vapor `Droplet`. ```swift -let query = ... -let spotifyResponse = try drop.client.get("https://api.spotify.com/v1/search?type=artist&q=\(query)") -print(spotifyR) +let query = "..." +let res = try drop.client.get("https://api.spotify.com/v1/search?type=artist&q=\(query)") +print(res) ``` ### Clean Up @@ -22,138 +17,78 @@ print(spotifyR) The url above can be a little tricky to read, so let's use the query parameter to clean it up a little bit: ```swift -try drop.client.get("https://api.spotify.com/v1/search", query: ["type": "artist", "q": query]) +let res = try drop.client.get("https://api.spotify.com/v1/search", query: [ + "type": "artist", + "q": query +]) ``` ### Continued In addition to `GET` requests, Vapor's client provides support for most common HTTP functions. `GET`, `POST`, `PUT`, `PATCH`, `DELETE` -### POST as json -```swift -try drop.client.post("http://some-endpoint/json", headers: ["Content-Type": "application/json"], body: myJSON.makeBody()) -``` +### Headers -### POST as x-www-form-urlencoded -```swift -try drop.client.post("http://some-endpoint", headers: [ - "Content-Type": "application/x-www-form-urlencoded" -], body: Body.data( Node(node: [ - "email": "mymail@vapor.codes" -]).formURLEncoded())) -``` - -### Full Request - -To access additional functionality or custom methods, use the underlying `request` function directly. +You can also add additional headers to the request. ```swift -public static func get(_ method: Method, - _ uri: String, - headers: [HeaderKey: String] = [:], - query: [String: CustomStringConvertible] = [:], - body: Body = []) throws -> Response +try drop.client.get("http://some-endpoint/json", headers: [ + "API-Key": "vapor123" +]) ``` -For example: +### Custom Request + +You can ask the client to respond to any `Request` that you create. +This is useful if you need to add JSON or FormURLEncoded data to the request. ```swift -try drop.client.request(.other(method: "CUSTOM"), "http://some-domain", headers: ["My": "Header"], query: ["key": "value"], body: []) +let req = Request(method: .post, uri: "http://some-endpoint") +req.formURLEncoded = Node(node: [ + "email": "mymail@vapor.codes" +]) + +try drop.client.response(to: req) ``` -## Config +## Re-usable Connection -The `Config/clients.json` file can be used to modify the client's settings. +Up to this point, we've been using `drop.client` which is a `ClientFactory`. This creates a new client and TCP connection for each request. -### TLS - -Host and certificate verification can be disabled. - -> Note: Use extreme caution when modifying these settings. - -```json -{ - "tls": { - "verifyHost": false, - "verifyCertificates": false - } -} -``` - -### Mozilla - -The Mozilla certificates are included by default to make fetching content from secure sites easy. - -```json -{ - "tls": { - "certificates": "mozilla" - } -} -``` - -## Advanced - -In addition to our Droplet, we can also use and interact with the `Client` manually. Here's how our default implementation in Vapor looks: +For more better performance, you can create an re-use a single client. ```swift -let response = try Client.get("http://some-endpoint/mine") -``` +let pokemonClient = try drop.client.makeClient( + scheme: "http", + host: "pokeapi.co", + securityLayer: .none +) -The first thing we likely noticed is `TCPClientStream` being used as a Generic value. This will be the underlying connection that the `HTTP.Client` can use when performing the request. By conforming to the underlying `ClientStream`, an `HTTP.Client` can accept custom stream implementations seamlessly. - -## Save Connection - -Up to this point, we've been interacting with the Client via `class` or `static` level functions. This allows us to end the connection upon a completed request and is the recommended interaction for most use cases. For some advanced situations, we may want to reuse a connection. For these, we can initialize our client and perform multiple requests like this. - -```swift -let pokemonClient = try drop?.client.make(scheme: "http", host: "pokeapi.co") for i in 0...1 { - let response = try pokemonClient?.get(path: "/api/v2/pokemon/", query: ["limit": 20, "offset": i]) + let response = try pokemonClient.get("/api/v2/pokemon/", query: [ + "limit": 20, + "offset": i + ]) print("response: \(response)") } ``` -## ClientProtocol +!!! note + Clients created using `.makeClient` can not connect to a different server after initialization. (Proxy servers are an exception) -Up to this point, we've focused on the built in `HTTP.Client`, but users can also include their own customized clients by conforming to `HTTP.ClientProtocol`. Let's look at the implementation: +## Proxy -```swift -public protocol Responder { - func respond(to request: Request) throws -> Response -} +The `drop.client` can be configured to use a proxy by default. -public protocol Program { - var host: String { get } - var port: Int { get } - var securityLayer: SecurityLayer { get } - // default implemented - init(host: String, port: Int, securityLayer: SecurityLayer) throws -} - -public protocol ClientProtocol: Program, Responder { - var scheme: String { get } - var stream: Stream { get } - init(scheme: String, host: String, port: Int, securityLayer: SecurityLayer) throws +`Config/client.json` +```json +{ + "proxy": { + "hostname": "google.com", + "port": 80, + "securityLayer": "none" + } } ``` -By conforming to these underlying functions, we immediately gain access to the public `ClientProtocol` apis we viewed above. - -## Customize Droplet - -If we've introduced a custom conformance to `HTTP.ClientProtocol`, we can pass this into our droplet without changing the underlying behavior in our application. - -For example: - -```swift -let drop = Droplet() - -drop.client = MyCustomClient.self -``` - -Going forward, all of your calls to `drop.client` will use `MyCustomClient.self`: - -```swift -drop.client.get(... // uses `MyCustomClient` -``` +For the above example, all requests sent to `drop.client.get(...)` would be proxied through google.com. diff --git a/2.0/docs/http/cors.md b/2.0/docs/http/cors.md index 7c3445df..09aa0e5a 100644 --- a/2.0/docs/http/cors.md +++ b/2.0/docs/http/cors.md @@ -1,6 +1,3 @@ -!!! warning - This section may contain outdated information. - # CORS Vapor by default provides a middleware for implementing proper support for Cross-Origin Resource Sharing (CORS) named `CORSMiddleware`. @@ -16,10 +13,37 @@ To learn more about middlewares, please visit the Middleware section of the docu First of all, add the CORS middleware into your droplet middlewares array. -```swift -# Insert CORS before any other middlewares -drop.middleware.insert(CORSMiddleware(), at: 0) -``` +`Config/droplet.json` +```json +{ + ..., + "middleware": [ + ..., + "cors", + ..., + ], + ..., +} +``` + +Next time you boot your application, you will be prompted to add a `Config/cors.json` file. + + +`Config/cors.json` +```json +{ + "allowedOrigin": "*", + "allowedMethods": ["GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"], + "allowedHeaders": [ + "Accept", + "Authorization", + "Content-Type", + "Origin", + "X-Requested-With" + ] +} +``` + > Note: Make sure you insert CORS middleware before any other throwing middlewares, like the AbortMiddleware or similar. Otherwise the proper headers might not be added to the response. @@ -43,51 +67,32 @@ See below for how to set up both and what are the options. The `CORSConfiguration` struct is used to configure the `CORSMiddleware`. You can instanitate one like this: ```swift -let configuration = CORSConfiguration(allowedOrigin: .custom("https://vapor.codes"), - allowedMethods: [.get, .post, .options], - allowedHeaders: ["Accept", "Authorization"], - allowCredentials: false, - cacheExpiration: 600, - exposedHeaders: ["Cache-Control", "Content-Language"]) +let config = try Config() +config.addConfigurable(middleware: { config in + return CORSConfiguration( + allowedOrigin: .custom("https://vapor.codes"), + allowedMethods: [.get, .post, .options], + allowedHeaders: ["Accept", "Authorization"], + allowCredentials: false, + cacheExpiration: 600, + exposedHeaders: ["Cache-Control", "Content-Language"] + ) +}, name: "custom-cors") ``` -After creating a configuration you can add the CORS middleware. +Then set the `custom-cors` in your Droplet's middleware array. -```swift -drop.middleware.insert(CORSMiddleware(configuration: configuration), at: 0) +`Config/droplet.json` +```json +{ + ..., + "middleware": [ + ..., + "custom-cors", + ..., + ], + ..., +} ``` > Note: Please consult the documentation in the source code of the `CORSConfiguration` for more information about available values for the settings. - - -### JSON Config - -Optionally, `CORSMiddleware` can be configured using the Vapor's `Config` which is created out of the json files contained in your Config folder. You will need to create a file called `cors.json` or `CORS.json` in your Config folder in your project and add the required keys. - -Example of how such a file could look as follows: - -```swift -{ - "allowedOrigin": "origin", - "allowedMethods": "GET,POST,PUT,OPTIONS,DELETE,PATCH", - "allowedHeaders": ["Accept", "Authorization", "Content-Type", "Origin", "X-Requested-With"] -} - -``` - -> Note: Following keys are required: `allowedOrigin`, `allowedMethods`, `allowedHeaders`. If they are not present an error will be thrown while instantiating the middleware. -> -> Optionally you can also specify the keys `allowCredentials` (Bool), `cacheExpiration` (Int) and `exposedHeaders` ([String]). - -Afterwards you can add the middleware using the a throwing overload of the initialiser that accepts Vapor's `Config`. - -```swift -let drop = Droplet() - -do { - drop.middleware.insert(try CORSMiddleware(configuration: drop.config), at: 0) -} catch { - fatalError("Error creating CORSMiddleware, please check that you've setup cors.json correctly.") -} -``` - diff --git a/2.0/docs/http/middleware.md b/2.0/docs/http/middleware.md index 104ffca8..d8dc2264 100644 --- a/2.0/docs/http/middleware.md +++ b/2.0/docs/http/middleware.md @@ -147,7 +147,7 @@ Anything added to the `authed` group must pass through `AuthMiddleware`. Because Appending middleware to the `drop.middleware` array is the simplest way to add middleware--it will be used every time the application starts. -You can also use the [configuration](../settings/config.md) files to enabled or disable middleware for more control. This is especially useful if you have middleware that should, for example, run only in production. +You can also use the [configuration](../configs/config.md) files to enabled or disable middleware for more control. This is especially useful if you have middleware that should, for example, run only in production. Appending configurable middleware looks like the following: diff --git a/2.0/docs/http/package.md b/2.0/docs/http/package.md new file mode 100644 index 00000000..22058f85 --- /dev/null +++ b/2.0/docs/http/package.md @@ -0,0 +1,28 @@ +# Using HTTP + +## With Vapor + +This package is included with Vapor by default, just add: + +```Swift +import HTTP +``` + +## Without Vapor + +HTTP provides everything you need to create an HTTP-based application for any server-side Swift project. To include it in your package, add the following to your `Package.swift` file. + +```Swift +import PackageDescription + +let package = Package( + name: "Project", + dependencies: [ + ... + .Package(url: "https://github.com/vapor/engine.git", majorVersion: 2) + ], + exclude: [ ... ] +) +``` + +Use `import HTTP` to access HTTP's APIs diff --git a/2.0/docs/http/request.md b/2.0/docs/http/request.md index 4fc8cc1a..f6ed9bdf 100644 --- a/2.0/docs/http/request.md +++ b/2.0/docs/http/request.md @@ -1,8 +1,3 @@ -!!! warning - This section may contain outdated information. - -> Module: `import HTTP` - # Request The most common part of the `HTTP` library we'll be interacting with is the `Request` type. Here's a look at some of the most commonly used attributes in this type. diff --git a/2.0/docs/http/responder.md b/2.0/docs/http/responder.md index 94b978e5..0ee2902b 100644 --- a/2.0/docs/http/responder.md +++ b/2.0/docs/http/responder.md @@ -1,8 +1,3 @@ -!!! warning - This section may contain outdated information. - -> Module: `import HTTP` - # Responder The `Responder` is a simple protocol defining the behavior of objects that can accept a `Request` and return a `Response`. Most notably in Vapor, it is the core API endpoint that connects the `Droplet` to the `Server`. Let's look at the definition: diff --git a/2.0/docs/http/response-representable.md b/2.0/docs/http/response-representable.md index 302d9f47..5e17a700 100644 --- a/2.0/docs/http/response-representable.md +++ b/2.0/docs/http/response-representable.md @@ -1,8 +1,3 @@ -!!! warning - This section may contain outdated information. - -> Module: `import HTTP` - # ResponseRepresentable Traditionally HTTP servers take a `Request` and return a `Response`. Vapor is no different, but we can take advantage of Swift's powerful protocols to be a bit more flexible to the user facing API. @@ -23,7 +18,7 @@ Because string conforms to `ResponseRepresentable`, we can return it directly in ```swift drop.get("hello") { request in - return "Hello, World!" + return "Hello, World!" } ``` @@ -33,15 +28,10 @@ drop.get("hello") { request in ```swift drop.get("hello") { request in - return try JSON(node: [ - "hello": "world", - "some-numbers": [ - 1, - 2, - 3 - ] - ] - ) + var json = JSON() + try json.set("hello", "world") + try json.set("some-numbers", [1, 2, 3]) + return json } ``` @@ -51,7 +41,11 @@ Of course, we can also return Responses for anything not covered: ```swift drop.get("hello") { request in - return Response(status: .ok, headers: ["Content-Type": "text/plain"], body: "Hello, World!") + return Response( + status: .ok, + headers: ["Content-Type": "text/plain"], + body: "Hello, World!" + ) } ``` @@ -73,31 +67,27 @@ And now, let's conform it to response representable. ```swift import HTTP -import Foundation extension BlogPost: ResponseRepresentable { - func makeResponse() throws -> Response { - let json = try JSON(node: - [ - "id": id, - "content": content, - "created-at": createdAt.timeIntervalSince1970 - ] - ) - return try json.makeResponse() - } + func makeResponse() throws -> Response { + var json = JSON() + try json.set("id", id) + try json.set("content", content) + try json.set("created-at", createdAt.timeIntervalSince1970) + return try json.makeResponse() + } } ``` -> Don't forget to import HTTP. - Now that we've modeled our BlogPost, we can return it directly in route handlers. ```swift drop.post("post") { req in - guard let content = request.data["content"] else { throw Error.missingContent } - let post = Post(content: content) - try post.save(to: database) - return post + guard let content = request.data["content"] else { + throw Error.missingContent + } + let post = Post(content: content) + try post.save(to: database) + return post } ``` diff --git a/2.0/docs/http/response.md b/2.0/docs/http/response.md index 83557d1d..04a46579 100644 --- a/2.0/docs/http/response.md +++ b/2.0/docs/http/response.md @@ -1,8 +1,3 @@ -!!! warning - This section may contain outdated information. - -> Module: `import HTTP` - # Response When building endpoints, we'll often be returning responses for requests. If we're making outgoing requests, we'll be receiving them. diff --git a/2.0/docs/http/server.md b/2.0/docs/http/server.md index a70fdf94..a886acfb 100644 --- a/2.0/docs/http/server.md +++ b/2.0/docs/http/server.md @@ -1,6 +1,3 @@ -!!! warning - This section may contain outdated information. - # Server The server is responsible for accepting connections from clients, parsing their requests, and delivering them a response. @@ -12,51 +9,25 @@ Starting your Droplet with a default server is simple. ```swift import Vapor -let drop = Droplet() - -drop.run() +let drop = try Droplet() +try drop.run() ``` The default server will bind to host `0.0.0.0` at port `8080`. ## Config -If you are using a `Config/servers.json` file, this is where you can easily change your host and port or even boot multiple servers. +If you are using a `Config/server.json` file, this is where you can easily change your host and port. ```json { - "default": { - "port": "$PORT:8080", - "host": "0.0.0.0", - "securityLayer": "none" - } + "port": "$PORT:8080", + "host": "0.0.0.0", + "securityLayer": "none" } ``` -The default `servers.json` is above. The port with try to resolve the environment variable `$PORT` or fallback to `8080`. - -### Multiple - -You can start multiple servers in the same application. This is especially useful if you want to boot an `HTTP` and `HTTPS` server side by side. - -```json -{ - "plaintext": { - "port": "80", - "host": "vapor.codes", - "securityLayer": "none" - }, - "secure": { - "port": "443", - "host": "vapor.codes", - "securityLayer": "tls", - "tls": { - "certificates": "none", - "signature": "selfSigned" - } - }, -} -``` +The default `server.json` is above. The port with try to resolve the environment variable `$PORT` or fallback to `8080`. ## TLS @@ -70,8 +41,8 @@ Verificiation of hosts and certificates can be disabled. They are enabled by def ```json "tls": { - "verifyHost": false, - "verifyCertificates": false + "verifyHost": false, + "verifyCertificates": false } ``` @@ -142,68 +113,23 @@ Verificiation of hosts and certificates can be disabled. They are enabled by def ## Example -Here is an example `servers.json` file using certificate files with a self signed signature and host verification redundantly set to `true`. +Here is an example `server.json` file using certificate files with a self signed signature and host verification redundantly set to `true`. ```json { - "secure": { - "port": "8443", - "host": "0.0.0.0", - "securityLayer": "tls", - "tls": { - "verifyHost": true, - "certificates": "files", - "certificateFile": "/vapor/certs/cert.pem", - "privateKeyFile": "/vapor/certs/key.pem", - "signature": "selfSigned" - } + "port": "8443", + "host": "0.0.0.0", + "securityLayer": "tls", + "tls": { + "verifyHost": true, + "certificates": "files", + "certificateFile": "/vapor/certs/cert.pem", + "privateKeyFile": "/vapor/certs/key.pem", + "signature": "selfSigned" } } ``` -## Manual +## Nginx -Servers can also be configured manually, without configuration files. - -> Note: If servers are configured programatically, they override any config settings. - -### Simple - -The `run` method on the Droplet takes a dictionary of server configuration objects. The key is the name of the server. - -```swift -import Vapor - -let drop = Droplet() - -drop.run(servers: [ - "default": (host: "vapor.codes", port: 8080, securityLayer: .none) -] -``` - -### TLS - -TLS can also be configured manually, and works similarly to the `servers.json` config files described above. - -```swift -import Vapor -import TLS - -let drop = Droplet() - -let config = try TLS.Config( - mode: .server, - certificates: .files( - certificateFile: "/Users/tanner/Desktop/certs/cert.pem", - privateKeyFile: "/Users/tanner/Desktop/certs/key.pem", - signature: .selfSigned - ), - verifyHost: true, - verifyCertificates: true -) - -drop.run(servers: [ - "plaintext": ("vapor.codes", 8080, .none), - "secure": ("vapor.codes", 8443, .tls(config)), -]) -```` \ No newline at end of file +It is highly recommended that you serve your Vapor project behind Nginx in production. Read more in the [deploy Nginx](../deploy/nginx.md) section. \ No newline at end of file diff --git a/2.0/docs/json/overview.md b/2.0/docs/json/overview.md index c21a7b41..97473244 100644 --- a/2.0/docs/json/overview.md +++ b/2.0/docs/json/overview.md @@ -1,6 +1,6 @@ # JSON -JSON is an integral part of Vapor. It powers Vapor's [Config](../settings/config.md) and is easy to use in both requests and responses. +JSON is an integral part of Vapor. It powers Vapor's [Config](../configs/config.md) and is easy to use in both requests and responses. ## Request diff --git a/2.0/docs/json/package.md b/2.0/docs/json/package.md index de482997..17710ac0 100644 --- a/2.0/docs/json/package.md +++ b/2.0/docs/json/package.md @@ -1,7 +1,28 @@ # Using JSON -This package is included with the Vapor dependency, use +## With Vapor + +This package is included with Vapor by default, just add: ```Swift import JSON ``` + +## Without Vapor + +JSON provides easy-to-use JSON support for any server-side, or client side Swift project. To include it in your package, add the following to your `Package.swift` file. + +```Swift +import PackageDescription + +let package = Package( + name: "Project", + dependencies: [ + ... + .Package(url: "https://github.com/vapor/json.git", majorVersion: 2) + ], + exclude: [ ... ] +) +``` + +Use `import JSON` to access JSON's APIs diff --git a/2.0/docs/leaf/provider.md b/2.0/docs/leaf/provider.md index 8bfeba40..f590c426 100644 --- a/2.0/docs/leaf/provider.md +++ b/2.0/docs/leaf/provider.md @@ -33,7 +33,7 @@ Once the provider is added to your Droplet, you can configure your Droplet to us ``` !!! seealso - Learn more about configuration files in the [Settings guide](../settings/config.md). + Learn more about configuration files in the [Settings guide](../configs/config.md). ## Manual diff --git a/2.0/docs/mysql/provider.md b/2.0/docs/mysql/provider.md index abe74975..6ccd55b3 100644 --- a/2.0/docs/mysql/provider.md +++ b/2.0/docs/mysql/provider.md @@ -31,7 +31,7 @@ Once the provider is added to your Droplet, you can configure Fluent to use the ``` !!! seealso - Learn more about configuration files in the [Settings guide](../settings/config.md). + Learn more about configuration files in the [Settings guide](../configs/config.md). ## Configure MySQL diff --git a/2.0/docs/redis/provider.md b/2.0/docs/redis/provider.md index e451fbd9..4c730193 100644 --- a/2.0/docs/redis/provider.md +++ b/2.0/docs/redis/provider.md @@ -31,7 +31,7 @@ Once the provider is added to your Droplet, you can configure Vapor to use Redis ``` !!! seealso - Learn more about configuration files in the [Settings guide](../settings/config.md). + Learn more about configuration files in the [Settings guide](../configs/config.md). ## Configure Redis diff --git a/2.0/docs/sessions/package.md b/2.0/docs/sessions/package.md new file mode 100644 index 00000000..67e2e210 --- /dev/null +++ b/2.0/docs/sessions/package.md @@ -0,0 +1,7 @@ +# Using Sessions + +This module is a part of Vapor, just add: + +```Swift +import Sessions +``` diff --git a/2.0/docs/sessions/sessions.md b/2.0/docs/sessions/sessions.md index d9140e19..a1bb06e2 100644 --- a/2.0/docs/sessions/sessions.md +++ b/2.0/docs/sessions/sessions.md @@ -1,36 +1,45 @@ -!!! warning - This section may contain outdated information. - # Sessions Sessions help you store information about a user between requests. As long as the client supports cookies, sessions are easy to create. ## Middleware -Enable sessions on your `Droplet` by adding an instance of `SessionMiddleware`. +Enable sessions on your `Droplet` by adding `"sessions"` to your middleware array. + +`Config/droplet.json` +```json +{ + ..., + "middleware": [ + ..., + "sessions", + ..., + ], + ..., +} +``` + +By default, the memory sessions driver will be used. You can change this with the `droplet.sessions` key. + + +`Config/droplet.json` +```json +{ + ..., + "sessions": "memory", + ..., +} +``` + +## Request + +After `SessionMiddleware` has been enabled, you can access the `req.assertSession()` method to get access to session. ```swift import Sessions -let memory = MemorySessions() -let sessions = SessionsMiddleware(sessions: memory) -``` - -Then add to the `Droplet`. - -``` -let drop = Droplet() -drop.middleware.append(sessions) -``` - -> Note: If you'd like to enable or disable the middleware based on config files, check out [middleware](../http/middleware.md). - -## Request - -After `SessionMiddleware` has been enabled, you can access the `req.sessions()` method to get access to session data. - -```swift -let data = try req.session().data +let session = try req.assertSession() +print(session.data) ``` ## Example @@ -42,10 +51,11 @@ Let's create an example that remembers the user's name. ```swift drop.post("remember") { req in guard let name = req.data["name"]?.string else { - throw Abort.badRequest + throw Abort(.badRequest) } - try req.session().data["name"] = Node.string(name) + let session = try req.assertSession() + try session.data.set("name", name) return "Remebered name." } @@ -59,8 +69,10 @@ On `GET /remember`, fetch the `name` from the session data and return it. ```swift drop.get("remember") { req in - guard let name = try req.session().data["name"]?.string else { - return throw Abort.custom(status: .badRequest, message: "Please POST the name first.") + let session = try req.assertSession() + + guard let name = session.data["name"]?.string else { + return throw Abort(.badRequest, reason: "Please POST the name first.") } return name @@ -70,7 +82,3 @@ drop.get("remember") { req in ## Cookie The session will be stored using the `vapor-session` cookie. - - - - diff --git a/2.0/docs/vapor/commands.md b/2.0/docs/vapor/commands.md index d287dfb3..16ec1703 100644 --- a/2.0/docs/vapor/commands.md +++ b/2.0/docs/vapor/commands.md @@ -1,8 +1,7 @@ -!!! warning - This section may contain outdated information. +In addition to the commands provided by Vapor (like `serve`, and `routes`) you can build your own custom commands. -# Commands -Custom console commands on Vapor are a breeze. +!!! note + Commands are a great way to script your application with CRON jobs. ## Example To make a custom console command we must first create a new `.swift` file, import `Vapor` and `Console`, and implement the `Command` protocol. @@ -12,7 +11,7 @@ import Vapor import Console final class MyCustomCommand: Command { - public let id = "command" + public let id = "my-command" public let help = ["This command does things, like foo, and bar."] public let console: ConsoleProtocol @@ -26,19 +25,51 @@ final class MyCustomCommand: Command { } ``` - - The **id** property is the string you will type in the console to access the command. `.build/debug/App command` will run the Custom Command. - - The **help** property is the help message that will give your custom command's users some idea of how to access it. - - The **console** property is the object passed to your custom command that adheres to the console protocol, allowing manipulation of the console. - - The **run** method is where you put the logic relating to your command. +- The **id** property is the string you will type in the console to access the command. `.build/debug/App command` will run the Custom Command. +- The **help** property is the help message that will give your custom command's users some idea of how to access it. +- The **console** property is the object passed to your custom command that adheres to the console protocol, allowing manipulation of the console. +- The **run** method is where you put the logic relating to your command. + +## Config Initializable + +To make our command configurable, conform it to `ConfigInitializable` -After we work our magic in the Custom Command file, we switch over to our `main.swift` file and add the custom command to the droplet like so. ```swift -drop.commands.append(MyCustomCommand(console: drop.console)) +extension MyCustomCommand: ConfigInitializable { + ... +} ``` + +## Add to Droplet + +After we work our magic in the Custom Command file, we switch over to our `main.swift` file and add the custom command to the Droplet like so. + +```swift +import Vapor + +let config = try Config() +try config.addConfigurable(command: MyCustomCommand.init, name: "my-command") + +let drop = try Droplet(config) +``` + This allows Vapor access to our custom command and lets it know to display it in the `--help` section of the program. +### Configure + +Now that you've made the command configurable, just add it to the `commands` array in your `Config/droplet.json` file. + +`Config/droplet.json` +```json +{ + ..., + "commands": ["my-command"], + ..., +} +``` + After compiling the application we can run our custom command like so. ``` -.build/debug/App command +vapor run my-command ``` diff --git a/2.0/docs/vapor/controllers.md b/2.0/docs/vapor/controllers.md index 73d52182..e81da692 100644 --- a/2.0/docs/vapor/controllers.md +++ b/2.0/docs/vapor/controllers.md @@ -45,20 +45,24 @@ You can also use controller methods with type-safe routing. final class HelloController { ... - func sayHelloAlternate(_ req: Request, _ name: String) -> ResponseRepresentable { + func sayHelloAlternate(_ req: Request) -> ResponseRepresentable { + let name: String = try req.parameters.next(String.self) return "Hello, \(name)" } } ``` -We add a new method called `sayHelloAlternate` to the `HelloController` that accepts a second parameter `name: String`. +We add a new method called `sayHelloAlternate` to the `HelloController` that fetches a `String` from the request's parameters. ```swift let hc = HelloController() -drop.get("hello", String.self, handler: hc.sayHelloAlternate) +drop.get("hello", String.parameter, handler: hc.sayHelloAlternate) ``` -Since this type-safe `drop.get` accepts a signature `(Request, String) throws -> ResponseRepresentable`, our method can now be used as the closure for this route. +Since `drop.get` accepts a signature `(Request) throws -> ResponseRepresentable`, our method can now be used as the closure for this route. + +!!! note + Read more about type safe routing in the [Routing Parameters](https://docs.vapor.codes/2.0/routing/parameters/#type-safe) section. ## Resources @@ -139,4 +143,4 @@ drop.resource("users", users) Controllers can go anywhere in your application, but they are most often stored in the `App/Controllers/` directory. !!! tip - If you are building a large application, you may want to create your controllers in a separate module. This will allow you to perform unit tests on your controllers. For more information on creating modules, see the [modules](../advanced/modules.md) section in Advanced. + If you are building a large application, you may want to create your controllers in a separate module. This will allow you to perform unit tests on your controllers. diff --git a/2.0/docs/vapor/droplet.md b/2.0/docs/vapor/droplet.md index e2deb268..5a84d151 100644 --- a/2.0/docs/vapor/droplet.md +++ b/2.0/docs/vapor/droplet.md @@ -22,7 +22,7 @@ try drop.run() Creation of the `Droplet` normally happens in the `main.swift` file. !!! note - For the sake of simplicity, most of the documentations sample code uses just the `main.swift` file. See the [modules](../advanced/modules.md) section in Advanced to learn more about using multiple modules. + For the sake of simplicity, most of the documentations sample code uses just the `main.swift` file. You can read more about packages and modules in the Swift Package Manager [conceptual overview](https://swift.org/package-manager/). ## Environment @@ -34,7 +34,7 @@ if drop.environment == .production { } ``` -The environment affects [Config](../settings/config.md) and [Logging](log.md). The environment is `development` by default. To change it, pass the `--env=` flag as an argument. +The environment affects [Config](../configs/config.md) and [Logging](log.md). The environment is `development` by default. To change it, pass the `--env=` flag as an argument. ```sh vapor run serve --env=production @@ -45,7 +45,7 @@ If you are in Xcode, you can pass arguments through the scheme editor. !!! warning Debug logs can reduce the number of requests your application can handle per second. Enable production mode to silence non-critical logs. -## Working Directory +## Config Directory The `workDir` property contains a path to the current working directory of the application. Vapor uses this property to find the folders related to your project, such as `Resources`, `Public`, and `Config`. diff --git a/2.0/docs/vapor/folder-structure.md b/2.0/docs/vapor/folder-structure.md index 6d933e7d..591c0ad1 100644 --- a/2.0/docs/vapor/folder-structure.md +++ b/2.0/docs/vapor/folder-structure.md @@ -80,6 +80,6 @@ Vapor has a sophisticated configuration system that involves a hierarchy of conf └── app.json // overrides app.json in all environments, ignored by git ``` -`.json` files are structured in the `Config` folder as shown above. The configuration will be applied dependant on where the `.json` file exists in the hierarchy. Learn more in [Config](../settings/config.md). +`.json` files are structured in the `Config` folder as shown above. The configuration will be applied dependant on where the `.json` file exists in the hierarchy. Learn more in [Config](../configs/config.md). Learn about changing environments (the `--env=` flag) in the [Droplet](droplet.md) section. diff --git a/2.0/docs/vapor/log.md b/2.0/docs/vapor/log.md index 7c79cda6..20828adb 100644 --- a/2.0/docs/vapor/log.md +++ b/2.0/docs/vapor/log.md @@ -4,15 +4,34 @@ Log information using `drop.log`. drop.log.info("Informational log") ``` -Log types supported are: +## Types -- info -- warning -- verbose -- debug -- error -- fatal +Below are the following methods you can call on the log protocol. Only `error` and `fatal` will be shown in `production` mode. + +| Method | Production | +|---------|------------| +| info | No | +| warning | No | +| verbose | No | +| debug | No | +| error | Yes | +| fatal | Yes | ## Protocol Create your own logger by conforming to `LogProtocol`. + +```swift +/// Logger protocol. Custom loggers must conform +/// to this protocol +public protocol LogProtocol: class { + /// Enabled log levels. Only levels in this + /// array should be logged. + var enabled: [LogLevel] { get set } + + /// Log the given message at the passed filter level. + /// file, function and line of the logging call + /// are automatically injected in the convenience function. + func log(_ level: LogLevel, message: String, file: String, function: String, line: Int) +} +``` \ No newline at end of file diff --git a/2.0/docs/vapor/provider.md b/2.0/docs/vapor/provider.md index 245831c5..245d383b 100644 --- a/2.0/docs/vapor/provider.md +++ b/2.0/docs/vapor/provider.md @@ -33,7 +33,7 @@ Here is what importing the MySQL provider looks like: ```swift import Vapor -import VaporMySQL +import MySQLProvider ``` ### Add to Droplet @@ -42,7 +42,7 @@ Every provider comes with a class named `Provider`. Add this class to your Dropl ```swift let config = try Config() -try config.addProvider(VaporMySQL.Provider.self) +try config.addProvider(MySQLProvider.Provider.self) let drop = try Droplet(config) @@ -53,7 +53,7 @@ drop.run() ### Configuration -Some drivers may require a configuration file. For example, `VaporMySQL` requires a `Config/mysql.json` file like the following: +Some drivers may require a configuration file. For example, `MySQLProvider` requires a `Config/mysql.json` file like the following: ```json { diff --git a/2.0/mkdocs.yml b/2.0/mkdocs.yml index c33c4b38..dd0763e0 100644 --- a/2.0/mkdocs.yml +++ b/2.0/mkdocs.yml @@ -19,8 +19,8 @@ pages: - 'Hash': 'vapor/hash.md' - 'Log': 'vapor/log.md' - 'Commands': 'vapor/commands.md' -- Settings: - - 'Config': 'settings/config.md' +- Configs: + - 'Config': 'configs/config.md' - JSON: - 'Package': 'json/package.md' - 'Overview': 'json/overview.md' @@ -56,8 +56,10 @@ pages: - 'Password': 'auth/password.md' - 'Persist': 'auth/persist.md' - Sessions: + - 'Package': 'sessions/package.md' - 'Sessions': 'sessions/sessions.md' - HTTP: + - 'Package': 'http/package.md' - 'Request': 'http/request.md' - 'Response': 'http/response.md' - 'Middleware': 'http/middleware.md' @@ -84,8 +86,9 @@ pages: - Debugging: - 'Package': 'debugging/package.md' - 'Overview': 'debugging/overview.md' -- Advanced: - - 'Modules': 'advanced/modules.md' +- Deploy: + - 'Nginx': 'deploy/nginx.md' + - 'Supervisor': 'deploy/supervisor.md' - Version (2.0): - '1.5': 'version/1_5.md' - '2.0': 'version/2_0.md'