mirror of https://github.com/vapor/docs.git
folder structure, spm, + routing
This commit is contained in:
parent
d498dd5ff7
commit
c6d806cf0c
|
|
@ -0,0 +1,81 @@
|
|||
# Folder Structure
|
||||
|
||||
Now that you've created, built, and run your first Vapor app, let's take a moment to familiarize you with Vapor's folder structure. The structure is based on [SPM](spm.md)'s folder structure, so if you've worked with SPM before it should be familiar.
|
||||
|
||||
```
|
||||
.
|
||||
├── Public
|
||||
├── Sources
|
||||
│ ├── App
|
||||
│ │ ├── Controllers
|
||||
│ │ ├── Migrations
|
||||
│ │ ├── Models
|
||||
│ │ ├── app.swift
|
||||
│ │ ├── configure.swift
|
||||
│ │ └── routes.swift
|
||||
│ └── Run
|
||||
│ └── main.swift
|
||||
├── Tests
|
||||
│ └── AppTests
|
||||
└── Package.swift
|
||||
```
|
||||
|
||||
The sections below explain each part of the folder structure in more detail.
|
||||
|
||||
## Public
|
||||
|
||||
This folder contains any public files that will be served by your app if `FileMiddleware` is enabled. This is usually images, style sheets, and browser scripts. For example, a request to `localhost:8080/favicon.ico` will check to see if `Public/favicon.ico` exists and return it.
|
||||
|
||||
You will need to enable `FileMiddleware` in your `configure.swift` file before Vapor can serve public files.
|
||||
|
||||
```swift
|
||||
// Serves files from `Public/` directory
|
||||
middlewares.use(app.make(FileMiddleware.self))
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
This folder contains all of the Swift source files for your project.
|
||||
The top level folders, `App` and `Run`, reflect your package's modules,
|
||||
as declared in the [SPM](spm.md) manifest.
|
||||
|
||||
### App
|
||||
|
||||
This is where all of your application logic goes.
|
||||
|
||||
#### Controllers
|
||||
|
||||
Controllers are great way of grouping together application logic. Most controllers have many functions that accept a request and return some sort of response.
|
||||
|
||||
#### Migrations
|
||||
|
||||
The migrations folder is where your database migrations go if you are using Fluent.
|
||||
|
||||
#### Models
|
||||
|
||||
The models folder is a great place to store your `Content` structs or Fluent `Model`s.
|
||||
|
||||
#### app.swift
|
||||
|
||||
This file contains the `app(_:)` function which creates a configured instance of your Vapor `Application`. This method is used by the `Run` target's `main.swift` file to create and run your application. This method is also used in tests to create an instance of your application for testing.
|
||||
|
||||
#### configure.swift
|
||||
|
||||
This file contains the `configure(_:)` function. This method is called by `app(_:)` to configure the newly created `Application`. This is where you should register services like routes, databases, providers, and more.
|
||||
|
||||
#### routes.swift
|
||||
|
||||
This file contains the `routes(_:)` function. This method is called near the end of `configure(_:)` to register routes to your `Application`.
|
||||
|
||||
## Tests
|
||||
|
||||
Each non-executable module in your `Sources` folder can have a corresponding folder in `Tests`. This contains code built on the `XCTest` module for testing your package. Tests can be run using `swift test` on the command line or pressing ⌘+U in Xcode.
|
||||
|
||||
### AppTests
|
||||
|
||||
This folder contains the unit tests for code in your `App` module.
|
||||
|
||||
## Package.swift
|
||||
|
||||
Finally is [SPM](spm.md)'s package manifest.
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
# Swift Package Manager
|
||||
|
||||
The [Swift Package Manager](https://swift.org/package-manager/) (SPM) is used for building your project's source code and dependencies. Since Vapor relies heavily on SPM, it's a good idea to understand the basics of how it works.
|
||||
|
||||
SPM is similar to Cocoapods, Ruby gems, and NPM. You can use SPM from the command line with commands like `swift build` and `swift test` or with compatible IDEs. However, unlike some other package managers, there is no central package index for SPM packages. SPM instead leverages URLs to Git repositories and versions dependencies using [Git tags](https://git-scm.com/book/en/v2/Git-Basics-Tagging).
|
||||
|
||||
## Package Manifest
|
||||
|
||||
The first place SPM looks in your project is the package manifest. This should always be located in the root directory of your project and named `Package.swift`.
|
||||
|
||||
Take a look at this example Package manifest.
|
||||
|
||||
```swift
|
||||
// swift-tools-version:5.1
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "app",
|
||||
platforms: [
|
||||
.macOS(.v10_14)
|
||||
],
|
||||
products: [
|
||||
.executable(name: "Run", targets: ["Run"]),
|
||||
.library(name: "App", targets: ["App"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "App", dependencies: ["Fluent"]),
|
||||
.target(name: "Run", dependencies: ["App"]),
|
||||
.testTarget(name: "AppTests", dependencies: ["App"])
|
||||
]
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
Each part of the manifest is explained in the following sections.
|
||||
|
||||
### Tools Version
|
||||
|
||||
The very first line of a package manifest indicates the Swift tools version required. This specifies the minimum version of Swift that the package supports. The Package description API may also change between Swift versions, so this line ensures Swift will know how to parse your manifest.
|
||||
|
||||
### Package Name
|
||||
|
||||
The first argument to `Package` is the package's name. If the package is public, you should use the last segment of the Git repo's URL as the name.
|
||||
|
||||
### Platforms
|
||||
|
||||
The `platforms` array specifies which platforms this package supports. By specifying `.macOS(.v10_14)` this package requires macOS Mojave or greater. When Xcode loads this project, it will automatically set the minimum deployment version to 10.14 so that you can use all available APIs.
|
||||
|
||||
### Products
|
||||
|
||||
Products are targets that your package produces when built. In this package, there are two targets. A library and an executable.
|
||||
|
||||
### Dependencies
|
||||
|
||||
Dependencies are other SPM packages that your package relies on. All Vapor applications rely on the Vapor package, but you can add as many other dependencies as you want.
|
||||
|
||||
In the above example, you can see [vapor/vapor](https://github.com/vapor/vapor) version 4.0.0 or later is a dependency of this package. When you add a dependency to your package, you must next signal which [targets](#targets) depend on
|
||||
the newly available modules.
|
||||
|
||||
### Targets
|
||||
|
||||
Targets are all of the modules, executables, and tests that your package contains. Most Vapor apps will have three targets, although you can add as many as you like to organize your code. Each target declares which modules it depends on. You must add module names here in order to import them in your code. A target can depend on other targets in your project or any modules exposed by packages you've added to
|
||||
the [main dependencies](#dependencies) array.
|
||||
|
||||
!!! tip
|
||||
Executable targets (targets that contain a `main.swift` file) cannot be imported by other modules.
|
||||
This is why Vapor has both an `App` and a `Run` target.
|
||||
Any code you include in `App` can be tested in the `AppTests`.
|
||||
|
||||
## Folder Structure
|
||||
|
||||
Below is the typical folder structure for an SPM package.
|
||||
|
||||
```
|
||||
.
|
||||
├── Sources
|
||||
│ ├── App
|
||||
│ │ └── (Source code)
|
||||
│ └── Run
|
||||
│ └── main.swift
|
||||
├── Tests
|
||||
│ └── AppTests
|
||||
└── Package.swift
|
||||
```
|
||||
|
||||
Each `.target` corresponds to a folder in the `Sources` folder.
|
||||
Each `.testTarget` corresponds to a folder in the `Tests` folder.
|
||||
|
||||
## Package.resolved
|
||||
|
||||
The first time you build your project, SPM will create a `Package.resolved` file that stores the version of each dependency. The next time you build your project, these same versions will be used even if newer versions are available.
|
||||
|
||||
To update your depdencies, run `swift package update`.
|
||||
|
||||
## Xcode
|
||||
|
||||
If you are using Xcode 11 or greater, changes to dependencies, targets, products, etc will happen automatically whenever the `Package.swift` file is modified.
|
||||
|
||||
If you want to update to the latest dependencies, use File → Swift Packages → Update To Latest Swift Package Versions.
|
||||
|
||||
You may also want to add the `.swiftpm` file to your `.gitignore`. This is where Xcode will store your Xcode project configuration.
|
||||
|
|
@ -27,7 +27,7 @@ Vapor 4 requires Swift 5.1 or greater.
|
|||
|
||||
## Install Toolbox
|
||||
|
||||
Now that you have Swift installed, let's install the Vapor Toolbox. This CLI tool is not required to use Vapor but it includes helpful utilities like a new project creator.
|
||||
Now that you have Swift installed, let's install the [Vapor Toolbox](https://github.com/vapor/toolbox). This CLI tool is not required to use Vapor but it includes helpful utilities like a new project creator.
|
||||
|
||||
Toolbox is distributed via Homebrew. If you don't have Homebrew yet, visit <a href="https://brew.sh" target="_blank">brew.sh</a> for install instructions.
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ You can also use Swift's official Docker images which come with the compiler pre
|
|||
|
||||
## Install Toolbox
|
||||
|
||||
Now that you have Swift installed, let's install the [Vapor Toolbox](../getting-started/toolbox.md). This CLI tool is not required to use Vapor, but it includes helpful utilities.
|
||||
Now that you have Swift installed, let's install the [Vapor Toolbox](https://github.com/vapor/toolbox). This CLI tool is not required to use Vapor, but it includes helpful utilities.
|
||||
|
||||
On Linux, you will need to build the toolbox from source. View the toolbox's <a href="https://github.com/vapor/toolbox/releases" target="_blank">releases</a> on GitHub to find the latest version.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
# Routing
|
||||
|
||||
Routing is the process of finding the appropriate request handler for an incoming request. At the core of Vapor's routing is a high-performance, trie-node router from [RoutingKit](https://github.com/vapor/routing-kit).
|
||||
|
||||
To understand how routing works in Vapor, you must first understand the basics of an HTTP request. Take a look at the following example request.
|
||||
|
||||
```http
|
||||
GET /hello/vapor HTTP/1.1
|
||||
host: vapor.codes
|
||||
content-length: 0
|
||||
```
|
||||
|
||||
This is a simple `GET` HTTP request to the URL `/hello/vapor`. This is the kind of HTTP request your browser would make if you pointed it to the following URL.
|
||||
|
||||
```
|
||||
http://vapor.codes/hello/vapor
|
||||
```
|
||||
|
||||
## HTTP Verb
|
||||
|
||||
The first part of the request is the HTTP verb. `GET` is the most common HTTP verb, but there are several you will use often. These HTTP verbs are often associated with [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) semantics.
|
||||
|
||||
|verb|crud|
|
||||
|-|-|
|
||||
|`GET`|Read|
|
||||
|`POST`|Create|
|
||||
|`PUT`|Replace|
|
||||
|`PATCH`|Update|
|
||||
|`DELETE`|Delete|
|
||||
|
||||
## Request Path
|
||||
|
||||
Right after the HTTP verb is the request's URI. This consists of a path starting with `/` and an optional query string after `?`. The HTTP verb and path are what Vapor uses to route requests.
|
||||
|
||||
After the HTTP verb and URI is the HTTP version followed by zero or more headers and finally a body. Since this is a `GET` request, it does not have a body.
|
||||
|
||||
## Router Methods
|
||||
|
||||
Let's take a look at how this request could be handled in Vapor.
|
||||
|
||||
```swift
|
||||
app.get("hello", "vapor") { req in
|
||||
return "Hello, vapor!"
|
||||
}
|
||||
```
|
||||
|
||||
All of the common HTTP verbs are available as methods on `Application`. They accept one or more string arguments that represent the request's path separated by `/`.
|
||||
|
||||
Note that you could also write this using `on` followed by the verb.
|
||||
|
||||
```swift
|
||||
app.on(.GET, "hello", "vapor") { ... }
|
||||
```
|
||||
|
||||
With this route registered, the example HTTP request from above will result in the following HTTP response.
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
content-length: 13
|
||||
content-type: text/plain; charset=utf-8
|
||||
|
||||
Hello, vapor!
|
||||
```
|
||||
|
||||
## Route Parameters
|
||||
|
||||
Now that we've successfully routed a request based on the HTTP verb and path, let's try making the path dynamic. Notice that the name "vapor" is hardcoded in both the path and the response. Let's make this dynamic so that you can visit `/hello/<any name>` and get a response.
|
||||
|
||||
```swift
|
||||
app.get("hello", ":name") { req -> String in
|
||||
let name = req.parameters.get("name")!
|
||||
return "Hello, \(name)!"
|
||||
}
|
||||
```
|
||||
|
||||
By using a path component prefixed with `:`, we indicate to the router that this is a dynamic component. Any string supplied here will now match this route. We can then use `req.parameters` to access the value of the string.
|
||||
|
||||
!!! tip
|
||||
We can be sure that `req.parameters.get` will never return `nil` here since our route path includes `:name`. However, if you are accessing route parameters in middleware or in code triggered by multiple routes, you will want to handle the possibility of `nil`.
|
||||
|
||||
If you run the example request again, you'll still get a response that says hello to vapor. However, you can now include any name after `/hello/` and see it included in the response. Let's try `/hello/bob`.
|
||||
|
||||
```http
|
||||
GET /hello/bob HTTP/1.1
|
||||
content-length: 0
|
||||
```
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
content-length: 13
|
||||
content-type: text/plain; charset=utf-8
|
||||
|
||||
Hello, bob!
|
||||
```
|
||||
|
||||
Now that you understand the basics, check out each section to learn more about parameters, groups, and more.
|
||||
|
|
@ -31,6 +31,10 @@ nav:
|
|||
- 'Ubuntu': 'install/ubuntu.md'
|
||||
- 'Getting Started':
|
||||
- 'Hello, world': 'getting-started/hello-world.md'
|
||||
- 'Folder Structure': 'getting-started/folder-structure.md'
|
||||
- 'SPM': 'getting-started/spm.md'
|
||||
- 'Routing':
|
||||
'Overview': 'routing/overview.md'
|
||||
- 'Version (4.0)':
|
||||
- '1.5': 'version/1_5.md'
|
||||
- '2.0': 'version/2_0.md'
|
||||
|
|
|
|||
Loading…
Reference in New Issue