Merge pull request #157 from vapor/two

old docs update
This commit is contained in:
Tanner 2017-05-19 16:36:13 +01:00 committed by GitHub
commit 491551d250
35 changed files with 414 additions and 461 deletions

View File

@ -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.

View File

@ -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

View File

@ -2,9 +2,6 @@
Core provides some conveniences for common tasks.
!!! note
Use `import Core`
## Background
Easily create a background thread using `background()`

View File

@ -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/)

View File

@ -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.

View File

@ -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!
<iframe src="https://ghbtns.com/github-btn.html?user=vapor&repo=vapor&type=star&count=true&size=large" frameborder="0" scrolling="0" width="160px" height="30px"></iframe>
#### 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/).

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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 <name> [--template=<repo-url-or-github-path>]
vapor new <name> [--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).

View File

@ -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:

View File

@ -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<TCPClientStream>.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.

View File

@ -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.")
}
```

View File

@ -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:

28
2.0/docs/http/package.md Normal file
View File

@ -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

View File

@ -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.

View File

@ -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:

View File

@ -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
}
```

View File

@ -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.

View File

@ -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)),
])
````
It is highly recommended that you serve your Vapor project behind Nginx in production. Read more in the [deploy Nginx](../deploy/nginx.md) section.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,7 @@
# Using Sessions
This module is a part of Vapor, just add:
```Swift
import Sessions
```

View File

@ -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.

View File

@ -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
```

View File

@ -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.

View File

@ -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`.

View File

@ -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.

View File

@ -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)
}
```

View File

@ -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
{

View File

@ -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'