mirror of https://github.com/vapor/docs.git
update routing
This commit is contained in:
parent
fe27e04af4
commit
67ee447ae1
|
|
@ -29,6 +29,12 @@ menu:
|
|||
guide:
|
||||
name: Guide
|
||||
items:
|
||||
guide-droplet:
|
||||
text: Droplet
|
||||
relativeUrl: guide/droplet.html
|
||||
guide-folder-structure:
|
||||
text: Folder Structure
|
||||
relativeUrl: guide/folder-structure.html
|
||||
guide-routing:
|
||||
text: Routing
|
||||
relativeUrl: guide/routing.html
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export PATH="$SWIFTENV_ROOT/bin:$PATH"
|
|||
eval "$(swiftenv init -)"
|
||||
```
|
||||
|
||||
Note: macOS uses `~/.bash_profile` and Ubuntu uses `~/.bashrc`
|
||||
> Note: macOS uses `~/.bash_profile` and Ubuntu uses `~/.bashrc`
|
||||
|
||||
### Verify
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Run the following script to install the [Toolbox](https://github.com/qutheory/to
|
|||
curl -sL toolbox.qutheory.io | bash
|
||||
```
|
||||
|
||||
Note: You must have the correct version of Swift 3 installed.
|
||||
> Note: You must have the correct version of Swift 3 installed.
|
||||
|
||||
## Verify
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
currentMenu: guide-droplet
|
||||
---
|
||||
|
||||
# Droplet
|
||||
|
||||
The `Droplet` is a service container that gives you access to many of Vapor's facilities. It is responsible for registering routes, starting the server, appending middleware, and more.
|
||||
|
||||
## Initialization
|
||||
|
||||
As you have probably already seen, the only thing required to create an instance of `Droplet` is to import Vapor.
|
||||
|
||||
```swift
|
||||
import Vapor
|
||||
|
||||
let drop = Droplet()
|
||||
|
||||
// your magic here
|
||||
|
||||
drop.start()
|
||||
```
|
||||
|
||||
Creation of the `Droplet` normally happens in the `main.swift` file.
|
||||
|
||||
## Environment
|
||||
|
||||
The `environment` property contains the current environment your application is running in. Usually development, testing, or production.
|
||||
|
||||
```swift
|
||||
if drop.config.environment == .production {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The environment affects [Config](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
|
||||
```
|
||||
|
||||
If you are in Xcode, you can pass arguments through the scheme editor.
|
||||
|
||||
> Note: Debug logs can reduce the number of requests your application can handle per second. Enabling the production environment can improve performance.
|
||||
|
||||
## Working Directory
|
||||
|
||||
The `workDir` property contains a path to the current working directory of the application relative to where it was started. By default, this property assumes you started the Droplet from its root directory.
|
||||
|
||||
```swift
|
||||
drop.workDir // "/var/www/my-project/"
|
||||
```
|
||||
|
||||
You can override the working directory through the `Droplet`'s initializer, or by passing the `--workdir` argument.
|
||||
|
||||
```sh
|
||||
vapor run serve --workdir="/var/www/my-project"
|
||||
```
|
||||
|
||||
## Initialization
|
||||
|
||||
The `Droplet` has several customizable properties.
|
||||
|
||||
Most plugins for Vapor come with a [Provider](providers.md), these take care of configuration details for you.
|
||||
|
||||
```swift
|
||||
Droplet(
|
||||
arguments: [String]?,
|
||||
workDir workDirProvided: String?,
|
||||
config configProvided: Config?,
|
||||
localization localizationProvided: Localization?,
|
||||
server: ServerProtocol.Type?,
|
||||
sessions: Sessions?,
|
||||
hash: Hash?,
|
||||
console: ConsoleProtocol?,
|
||||
log: Log?,
|
||||
client: ClientProtocol.Type?,
|
||||
database: Database?,
|
||||
preparations: [Preparation.Type],
|
||||
providers: [Provider.Type],
|
||||
initializedProviders: [Provider]
|
||||
)
|
||||
```
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
currentMenu: guide-folder-structure
|
||||
---
|
||||
|
||||
# Folder Structure
|
||||
|
||||
The first step to creating an awesome application is knowing where things are. If you created your project using the [Toolbox](../getting-started/toolbox.md) or from a template, you will already have the folder structure created.
|
||||
|
||||
If you are making a Vapor application from scratch, this will show you exactly how to set it up.
|
||||
|
||||
## Minimum Folder Structure
|
||||
|
||||
We recommend putting all of your Swift code inside of the `App/` folder. This will allow you to create subfolders in `App/` to organize your models and resources.
|
||||
|
||||
This works best with the Swift package manager's restrictions on how packages should be structured.
|
||||
|
||||
```
|
||||
.
|
||||
├── App
|
||||
│ └── main.swift
|
||||
├── Public
|
||||
└── Package.swift
|
||||
```
|
||||
|
||||
The `Public` folder is where all publicly accessible files should go. This folder will be automatically checked every time a URL is requested that is not found in your routes.
|
||||
|
||||
> Note: The `FileMiddleware` is responsible for accessing files from the `Public` folder.
|
||||
|
||||
## Models
|
||||
|
||||
The `Models` folder is a recommendation of where you can put your database and other models, following the MVC pattern.
|
||||
|
||||
```
|
||||
.
|
||||
├── App
|
||||
. └── Models
|
||||
. └── User.swift
|
||||
```
|
||||
|
||||
## Controllers
|
||||
|
||||
The `Controllers` folder is a recommendation of where you can put your route controllers, following the MVC pattern.
|
||||
|
||||
```
|
||||
.
|
||||
├── App
|
||||
. └── Controllers
|
||||
. └── UserController.swift
|
||||
```
|
||||
|
||||
## Views
|
||||
|
||||
The `Views` folder in `Resources` is where Vapor will look when you render views.
|
||||
|
||||
```
|
||||
.
|
||||
├── App
|
||||
└── Resources
|
||||
└── Views
|
||||
└── user.html
|
||||
```
|
||||
|
||||
The following code would load the `user.html` file.
|
||||
|
||||
```swift
|
||||
drop.view("user.html")
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
Vapor has a sophisticated configuration system that involves a hierarchy of configuration importance.
|
||||
|
||||
```
|
||||
.
|
||||
├── App
|
||||
└── Config
|
||||
└── app.json // default app.json
|
||||
└── development
|
||||
└── app.json // overrides app.json when in development environment
|
||||
└── production
|
||||
└── app.json // overrides app.json when in production environment
|
||||
└── secrets
|
||||
└── 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](config.md).
|
||||
|
||||
Learn about changing environments (the `--env=` flag) in the [Droplet](droplet.md) section.
|
||||
161
guide/routing.md
161
guide/routing.md
|
|
@ -4,8 +4,163 @@ currentMenu: guide-routing
|
|||
|
||||
# Routing
|
||||
|
||||
This is how routing works.
|
||||
Routes in Vapor can be defined in any file that has access to your instance of `Droplet`. This is usually in the `main.swift` file.
|
||||
|
||||
## Basic
|
||||
|
||||
The most basic route includes a method, path, and closure.
|
||||
|
||||
```swift
|
||||
let drop = Droplet()
|
||||
```
|
||||
drop.get("welcome") { request in
|
||||
return "Hello"
|
||||
}
|
||||
```
|
||||
|
||||
The standard HTTP methods are available including `get`, `post`, `put`, `patch`, `delete`, and `options`.
|
||||
|
||||
You can also use `any` to match all methods.
|
||||
|
||||
## Request
|
||||
|
||||
The first parameter passed into your route closure is an instance of [Request](request.md). This contains the method, URI, body, and more.
|
||||
|
||||
```swift
|
||||
let method = request.method
|
||||
```
|
||||
|
||||
When you add a parameter type, like `String.self`, the closure will be required to contain another input variable. This variable will be the same type. In this case, `String`.
|
||||
|
||||
## JSON
|
||||
|
||||
To respond with JSON, simply wrap your data structure with `JSON(node: )`
|
||||
|
||||
```swift
|
||||
drop.get("version") { request in
|
||||
return try JSON(node: ["version": "1.0"])
|
||||
}
|
||||
```
|
||||
|
||||
## Response Representable
|
||||
|
||||
All routing closures can return a [ResponseRepresentable](response.md) data structure. By default, Strings and JSON conform to this protocol, but you can add your own.
|
||||
|
||||
```swift
|
||||
public protocol ResponseRepresentable {
|
||||
func makeResponse() throws -> Response
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
Parameters are described by passing the type of data you would like to receive.
|
||||
|
||||
```swift
|
||||
drop.get("hello", String.self) { request, name in
|
||||
return "Hello \(name)"
|
||||
}
|
||||
```
|
||||
|
||||
## String Initializable
|
||||
|
||||
Any type that conforms to `StringInitializable` can be used as a parameter. By default, `String` and `Int` conform to this protocol, but you can add your own.
|
||||
|
||||
```swift
|
||||
struct User: StringInitializable {
|
||||
...
|
||||
}
|
||||
|
||||
app.get("users", User.self) { request, user in
|
||||
return "Hello \(user.name)"
|
||||
}
|
||||
```
|
||||
|
||||
Using Swift extensions, you can extend your existing types to support this behavior.
|
||||
|
||||
```swift
|
||||
extension User: StringInitializable {
|
||||
init?(from string: String) throws {
|
||||
guard let int = Int(string) else {
|
||||
return nil //Will Abort.InvalidRequest
|
||||
}
|
||||
|
||||
guard let user = User.find(int) else {
|
||||
throw UserError.NotFound
|
||||
}
|
||||
|
||||
self = user
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can throw your own errors or return `nil` to throw the default error.
|
||||
|
||||
## Groups
|
||||
|
||||
Prefix a group of routes with a common string, host, or middleware using `group` and `grouped`.
|
||||
|
||||
### Group
|
||||
|
||||
Group (without the "ed" at the end) takes a closure that is passed a `GroupBuilder`.
|
||||
|
||||
```swift
|
||||
drop.group("v1") { v1 in
|
||||
v1.get("users") { request in
|
||||
// get the users
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Grouped
|
||||
|
||||
Grouped returns a `GroupBuilder` that you can pass around.
|
||||
|
||||
```swift
|
||||
let v1 = drop.grouped("v1")
|
||||
v1.get("users") { request in
|
||||
// get the users
|
||||
}
|
||||
```
|
||||
|
||||
### Middleware
|
||||
|
||||
You can add middleware to a group of routes. This is especially useful for authentication.
|
||||
|
||||
```swift
|
||||
drop.group(AuthMiddleware()) { authorized in
|
||||
authorized.get("token") { request in
|
||||
// has been authorized
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Host
|
||||
|
||||
You can limit the host for a group of routes.
|
||||
|
||||
```
|
||||
drop.group(host: "qutheory.io") { qt
|
||||
qt.get { request in
|
||||
// only responds to requests to qutheory.io
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Chaining
|
||||
|
||||
Groups can be chained together.
|
||||
|
||||
```swift
|
||||
drop.grouped(host: "qutheory.io").grouped(AuthMiddleware()).group("v1") { authedSecureV1 in
|
||||
// add routes here
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Routing
|
||||
|
||||
Vapor still supports traditional routing for custom use-cases or long URLs.
|
||||
|
||||
```swift
|
||||
drop.get("users/:user_id") { request in
|
||||
request.parameters["user_id"] // String?
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
</nav>
|
||||
|
||||
<main>
|
||||
<a href="https://github.com/qutheory/documentation/blob/master/CONTRIBUTING.md" class="edit">✏️ Edit</a>
|
||||
<a href="https://github.com/qutheory/documentation/blob/master/CONTRIBUTING.md" class="edit">✎ Edit on GitHub</a>
|
||||
{{ content | raw }}
|
||||
</main>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ a:hover {
|
|||
}
|
||||
|
||||
h1 {
|
||||
font-size: 48px;
|
||||
font-size: 42px;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ nav {
|
|||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 200px;
|
||||
width: 216px;
|
||||
|
||||
z-index: 8;
|
||||
padding-top: 96px;
|
||||
|
|
@ -127,6 +127,7 @@ nav a {
|
|||
font-size: 14px;
|
||||
display: block;
|
||||
color: #777;
|
||||
font-size: 12px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
|
|
@ -141,9 +142,9 @@ nav .active a {
|
|||
|
||||
nav h3 {
|
||||
text-transform: uppercase;
|
||||
color: #999;
|
||||
color: #bbb;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +155,7 @@ nav ul, nav ul li {
|
|||
}
|
||||
|
||||
nav ul {
|
||||
margin-bottom: 24px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
div.scroll {
|
||||
|
|
@ -169,7 +170,7 @@ main {
|
|||
font-weight: 200;
|
||||
padding: 22px;
|
||||
padding-top: 110px;
|
||||
padding-left: 222px;
|
||||
padding-left: 240px;
|
||||
|
||||
position: absolute;
|
||||
position: relative;
|
||||
|
|
@ -191,15 +192,39 @@ main a.edit {
|
|||
border-bottom: none;
|
||||
}
|
||||
|
||||
main h1 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
main h2 {
|
||||
margin-top: 24px;
|
||||
border-bottom: 1px dotted rgba(0, 0, 0, 0.10);
|
||||
margin-bottom: 12px;
|
||||
border-bottom: 1px dotted rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
|
||||
main h3 {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
main p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 12px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
main blockquote {
|
||||
background: rgba(247, 202, 201, 0.2);
|
||||
margin-top: 18px;
|
||||
margin-bottom: 18px;
|
||||
margin-left: 0;
|
||||
padding: 6px;
|
||||
padding-left: 12px;
|
||||
border-left: 5px solid #f6cfcf;
|
||||
}
|
||||
|
||||
main blockquote p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
|
|
@ -209,10 +234,11 @@ pre, code {
|
|||
|
||||
p code {
|
||||
background: #fbfbfb;
|
||||
border-radius: 10px;
|
||||
border-radius: 5px;
|
||||
padding: 3px;
|
||||
display: inline-block;
|
||||
color: #92a0b9;
|
||||
box-shadow: 0 1px 0px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
pre {
|
||||
|
|
|
|||
Loading…
Reference in New Issue