Skip to content

Commit 7235c28

Browse files
0xTimMaxDesiatov
andauthored
Add Vapor Getting Started guide (#229)
* Add Vapor Getting Started guide * Add link to Codable * Update getting-started/vapor-web-server/index.md Co-authored-by: Max Desiatov <[email protected]> * Code review comments --------- Co-authored-by: Max Desiatov <[email protected]>
1 parent 8f37260 commit 7235c28

File tree

2 files changed

+150
-2
lines changed

2 files changed

+150
-2
lines changed
442 KB
Loading
Lines changed: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,154 @@
11
---
22
layout: page
3-
title: Build a Web Server
3+
title: Build a Web Server with Vapor
44
---
55

6-
TODO
6+
{% include getting-started/_installing.md %}
7+
8+
## Installing Vapor
9+
10+
This guide uses the [Vapor](https://vapor.codes) web framework to build a server application. First, you need to install the Vapor toolbox. If you already have Homebrew installed on macOS, run
11+
12+
```bash
13+
brew install vapor
14+
```
15+
16+
If you're running on a different OS or want to install the toolbox from source, see [the Vapor docs](https://docs.vapor.codes/install/linux/#install-toolbox) for how to do so.
17+
18+
## Creating a Project
19+
20+
Then, in your terminal in a directory where you want to create the new project run:
21+
22+
```bash
23+
vapor new HelloVapor
24+
```
25+
26+
This pulls down a template and asks you a series of questions to create a simple project with everything you need to get started. This guide will create a simple REST API that you can send and receive JSON to and from. So answer no to all other questions. You'll see the project created successfully:
27+
28+
![A New Vapor Project]({{site.url}}/assets/images/getting-started-guides/vapor-web-server/new-project.png)
29+
30+
Navigate into the created directory and open the project in your IDE of choice. For instance, to use VSCode run:
31+
32+
```bash
33+
cd HelloVapor
34+
code .
35+
```
36+
37+
For Xcode, run:
38+
39+
```bash
40+
cd HelloVapor
41+
open Package.swift
42+
```
43+
44+
Vapor's template contains a number of files and functions already set up for you. **configure.swift** contains the code to configure your application and **routes.swift** contains route handler code.
45+
46+
## Creating Routes
47+
48+
First, open **routes.swift** and create a new route to say hello to anyone accessing your site by declaring a new route below `app.get("hello") { ... }`:
49+
50+
```swift
51+
// 1
52+
app.get("hello", ":name") { req async throws -> String in
53+
// 2
54+
let name = try req.parameters.require("name")
55+
// 3
56+
return "Hello, \(name.capitalized)!"
57+
}
58+
```
59+
60+
Here's what the code does:
61+
62+
1. Declare a new route handler registered as a **GET** request to `/hello/<NAME>`. The `:` denotes a dynamic path parameter in Vapor and will match any value and allow you to retrieve it in your route handler. `app.get(...)` takes a closure as the final parameter that can be asynchronous and must return a `Response` or something conforming to `ResponseEncodable`, such as `String`.
63+
2. Get the name from the parameters. By default, this returns a `String`. If you want to extract another type, such as `Int` or `UUID` you can write `req.parameters.require("id", as: UUID.self)` and Vapor will attempt to cast it to the type and automatically throw an error if it's unable to. This throws an error if the route hasn't been registered with the correct parameter name.
64+
3. Return the `Response`, in this case a `String`. Note that you don't need to set a status code, response body or any headers. Vapor handles this all for you, whilst allowing you to control the `Response` returned if needed.
65+
66+
Save the file and build and run the app. Send a **GET** request to `http://localhost:8080/hello/tim`. You'll get the response back:
67+
68+
```bash
69+
$ curl http://localhost:8080/hello/tim
70+
Hello, Tim!
71+
```
72+
73+
Try it with different names to see it change automatically!
74+
75+
## Returning JSON
76+
77+
Vapor uses [`Codable`](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types) under the hood to make it easy to send and receive JSON, using a wrapper protocol called `Content` to add a few extra features. Next, you'll return a JSON body with the message from the Hello! route. First, create a new type at the bottom of **routes.swift**:
78+
79+
```swift
80+
struct UserResponse: Content {
81+
let message: String
82+
}
83+
```
84+
85+
This defines a new type that conforms to `Content` that matches the JSON you want to return.
86+
87+
Create a new route below `app.get("hello", ":name") { ... }` to return this JSON:
88+
89+
```swift
90+
// 1
91+
app.get("json", ":name") { req async throws -> UserResponse in
92+
// 2
93+
let name = try req.parameters.require("name")
94+
let message = "Hello, \(name.capitalized)!"
95+
// 3
96+
return UserResponse(message: message)
97+
}
98+
```
99+
100+
Here's what this code does:
101+
102+
1. Define a new route handler that handles a **GET** request to `/json`. Importantly, the return type for the closure is `UserResponse`.
103+
2. Get the name as before and construct the message.
104+
3. Return the `UserResponse`.
105+
106+
Save and build and run the app again and send a GET request to `http://localhost:8080/json/tim`:
107+
108+
```bash
109+
$ curl http://localhost:8080/json/tim
110+
{"message":"Hello, Tim!"}
111+
```
112+
113+
This time, you get JSON back!
114+
115+
## Handling JSON
116+
117+
Finally, we'll cover how to receive JSON. At the bottom of **routes.swift**, create a new type to model JSON you'll send to the server app:
118+
119+
```swift
120+
struct UserInfo: Content {
121+
let name: String
122+
let age: Int
123+
}
124+
```
125+
126+
This contains two properties, a name and an age. Then, below the JSON route, create a new route to handle a POST request with this body:
127+
128+
```swift
129+
// 1
130+
app.post("user-info") { req async throws -> UserResponse in
131+
// 2
132+
let userInfo = try req.content.decode(UserInfo.self)
133+
// 3
134+
let message = "Hello, \(userInfo.name.capitalized)! You are \(userInfo.age) years old."
135+
return UserResponse(message: message)
136+
}
137+
```
138+
139+
The important differences in this new route handler are:
140+
141+
1. Use `app.post(...)` instead of `app.get(...)` as this route handler is a **POST** request.
142+
2. Decode the JSON from the request body.
143+
3. Use the data from the JSON body to create a new message.
144+
145+
Send a POST request with a valid JSON body and see your response:
146+
147+
```bash
148+
$ curl http://localhost:8080/user-info -X POST -d '{"name": "Tim", "age": 99}' -H "Content-Type: application/json"
149+
{"message":"Hello, Tim! You are 99 years old."}
150+
```
151+
152+
Congratulations! You've built your first web server in Swift!
153+
154+
Find the source code for this guide at [https://github.com/vapor/swift-getting-started-web-server](https://github.com/vapor/swift-getting-started-web-server)

0 commit comments

Comments
 (0)