add multipart docs

This commit is contained in:
tanner0101 2018-04-12 22:31:15 -04:00
parent 024665e0e7
commit eecba2ad88
8 changed files with 326 additions and 61 deletions

View File

@ -1,3 +0,0 @@
# Getting Started with Deployments
Coming soon.

View File

@ -21,5 +21,4 @@ For a detailed guide, visit [Vapor Cloud → Quick Start](https://docs.vapor.
## Other Options
Vapor can be deployed anywhere that supports Ubuntu (basically everywhere). To learn more about
deploying your code, checkout [Deploy → Getting Started](../deploy/getting-started.md)
Vapor can be deployed anywhere that supports Ubuntu (basically everywhere). Guides on deploying to other systems are coming soon (contributions welcome)!

View File

@ -1,6 +1,6 @@
# Content
In Vapor 3, all content types (JSON, protobuf, FormURLEncoded, Multipart, etc) are treated the same. All you need to parse and serialize content is a `Codable` class or struct.
In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, [Multipart](../multipart/getting-started.md), etc) are treated the same. All you need to parse and serialize content is a `Codable` class or struct.
For this introduction, we will use JSON as an example. But keep in mind the API is the same for any supported content type.
@ -18,12 +18,9 @@ Content-Type: application/json
}
```
### Decode Request
First, create a struct or class that represents the data you expect.
```swift
import Foundation
import Vapor
struct LoginRequest: Content {
@ -47,20 +44,6 @@ router.post("login") { req -> Future<HTTPStatus> in
We use `.map(to:)` here since `req.content.decode(_:)` returns a [future](async.md).
### Other Request Types
Since the request in the previous example declared JSON as its content type, Vapor knows to use a JSON decoder automatically. This same method would work just as well for the following request.
```http
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
email=user@vapor.codes&don't+look!
```
!!! tip
You can configure which encoders/decoders Vapor uses. Read on to learn more.
## Response
Let's take a look at how you would create the following HTTP response.
@ -75,12 +58,9 @@ Content-Type: application/json
}
```
### Encode Response
Just like decoding, first create a struct or class that represents the data that you are expecting.
```swift
import Foundation
import Vapor
struct User: Content {
@ -100,39 +80,10 @@ router.get("user") { req -> User in
}
```
### Other Response Types
Great job! Now you know how to encode and decode data in Vapor.
Content will automatically encode as JSON by default. You can always override which content type is used
using the `as:` parameter.
!!! tip
See [Vapor &rarr; Content](../vapor/content.md) for more in-depth information.
```swift
try res.content.encode(user, as: .formURLEncoded)
```
The next section in this guide is [Async](async.md).
You can also change the default media type for any class or struct.
```swift
struct User: Content {
/// See Content.defaultMediaType
static let defaultMediaType: MediaType = .formURLEncoded
...
}
```
## Configuring Content
Use `ContentConfig` to register custom encoder/decoders for your application. These custom coders will be used anywhere you do `content.encode`/`content.decode`.
```swift
/// Create default content config
var contentConfig = ContentConfig.default()
/// Create custom JSON encoder
var jsonEncoder = JSONEncoder()
jsonEncoder.dateEncodingStrategy = .millisecondsSince1970
/// Register JSON encoder and content config
contentConfig.use(encoder: jsonEncoder, for: .json)
services.register(contentConfig)
```

View File

@ -0,0 +1,42 @@
# Getting Started with Multipart
Multipart ([vapor/multipart](https://github.com/vapor/multipart)) is a small package that helps you parse and serialize `multipart` encoded data. Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images.
The Multipart package makes it easy to use this encoding by integrating directly with `Codable`.
## Vapor
This package is included with Vapor and exported by default. You will have access to all `Multipart` APIs when you import `Vapor`.
```swift
import Vapor
```
## Standalone
The Multipart package is lightweight, pure-Swift, and has very few dependencies. This means it can be used to work with multipart-encoded data for any Swift project&mdash;even one not using Vapor.
To include it in your package, add the following to your `Package.swift` file.
```swift
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "Project",
dependencies: [
...
.package(url: "https://github.com/vapor/multipart.git", from: "3.0.0"),
],
targets: [
.target(name: "Project", dependencies: ["Multipart", ... ])
]
)
```
Use `import Multipart` to access the APIs.
!!! warning
Some of this guide may contain Vapor-specific APIs, however most of it should be applicable to the Multipart package in general.
Visit the [API Docs](https://api.vapor.codes/multipart/latest/Multipart/index.html) for Multipart-specific API info.

View File

@ -0,0 +1,106 @@
# Using Multipart
Multipart is a widely-supported encoding on the web. It's most often used for serializing web forms, especially ones that contain rich media like images. It allows for arbitrary data to be encoded in each part thanks to a unique delimiter _boundary_ that is defined separately. This boundary is guaranteed by the client to not appear anywhere in the data.
Multipart is a powerful encoding, however it is rarely used in its base format. Most commonly, `multipart/form-data` is used. This encoding adds a `"name"` property to each part of the multipart data. This is required for serializing web forms. For the rest of this guide, assume we are talking about `multipart/form-data` unless otherwise specified.
!!! tip
Multipart integrates with [`Content`](https://api.vapor.codes/vapor/latest/Vapor/Protocols/Content.html) like all other encoding methods in Vapor. See [Vapor &rarr; Content](../vapor/content.md) for more information about the [`Content`](https://api.vapor.codes/vapor/latest/Vapor/Protocols/Content.html) protocol.
Let's take a look at how to decode a `multipart/form-data`-encoded request.
## Decode
Most often, you will be decoding `multipart/form-data`-encoded requests from a web form. Let's take a look at what one of these requests might look like. After that, we will take a look at what the HTML form for that request would look like.
### Request
Here is an example `multipart/form-data`-encoded request for creating a new user.
```http
POST /users HTTP/1.1
Content-Type: multipart/form-data; boundary=123
--123
Content-Disposition: form-data; name="name"
Vapor
--123
Content-Disposition: form-data; name="age"
3
--123
Content-Disposition: form-data; name="image"; filename="droplet.png"
<contents of image>
--123--
```
You can see the multipart data uses a _boundary_ (in this case it is `"123"`) to separate the data. This will usually be a longer string. The client sending a multipart-encoded request must ensure that the boundary it supplies does not appear anywhere in the content it is sending you. That's what allows this encoding to be used to send things like files.
### Form
There are many ways to create a multipart-encoded request, but the most common is an HTML web form. Here is what the HTML form for this request might have looked like.
```html
<form method="POST" action="/users" enctype="multipart/form-data">
<input type="text" name="name">
<input type="text" name="age">
<input type="file" name="image">
</form>
```
Take note of the `enctype` attribute on the `<form>` as well as the `file` type input. This is what allows us to send files via the web form.
### Content
Now let's take a look at how we would handle this request in Vapor. The first step (as always with [`Content`](https://api.vapor.codes/vapor/latest/Vapor/Protocols/Content.html)) is to create a `Codable` struct that represents the data structure.
```swift
import Vapor
struct User: Content {
var name: String
var age: Int
var image: Data
}
```
!!! tip
You can use [`File`](https://api.vapor.codes/core/latest/Core/Structs/File.html) instead of `Data` if you would also like to access the filename.
Now that we have our `User` struct, let's decode that request! We can use the [`ContentContainer`](https://api.vapor.codes/vapor/latest/Vapor/Structs/ContentContainer.html) to do this easily.
```swift
router.post("users") { req -> Future<HTTPStatus> in
return try req.content.decode(User.self).map(to: HTTPStatus.self) { user in
print(user.name) // "Vapor"
print(user.age) // 3
print(user.image) // Raw image data
return .ok
}
}
```
Now when you post the form to `/users`, you should see the information printed in the console. Nice work!
## Encode
APIs encode multipart data much less often than they decode it. However, encoding is just as easy with Vapor. Using our same `User` struct from the previous example, here is how we can encode a multipart-encoded response.
```swift
router.get("multipart") { req -> User in
let res = req.makeResponse()
let user = User(name: "Vapor", age: 3, image: Data(...))
res.content.encode(user, as: .formData)
return user
}
```
!!! tip
If you set a default `MediaType` on your `Content` types, then you can return them directly in the route closure.
## Parsing & Serializing
The Multipart package also offers APIs for parsing and serializing `multipart/form-data` data without using `Codable`. Check out the [API Docs](https://api.vapor.codes/multipart/latest/Multipart/index.html) for more information on using those APIs.

138
3.0/docs/vapor/content.md Normal file
View File

@ -0,0 +1,138 @@
# Using Content
In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, [Multipart](../multipart/getting-started.md), etc) are treated the same. All you need to parse and serialize content is a `Codable` class or struct.
For this introduction, we will use JSON as an example. But keep in mind the API is the same for any supported content type.
## Request
Let's take a look at how you would parse the following HTTP request.
```http
POST /login HTTP/1.1
Content-Type: application/json
{
"email": "user@vapor.codes",
"password": "don't look!"
}
```
### Decode Request
First, create a struct or class that represents the data you expect.
```swift
import Foundation
import Vapor
struct LoginRequest: Content {
var email: String
var password: String
}
```
Then simply conform this struct or class to `Content`.
Now we are ready to decode that HTTP request.
```swift
router.post("login") { req -> Future in
return req.content.decode(LoginRequest.self).map(to: HTTPStatus.self) { loginRequest in
print(loginRequest.email) // user@vapor.codes
print(loginRequest.password) // don't look!
return .ok
}
}
```
We use `.map(to:)` here since `req.content.decode(_:)` returns a [future](../async/getting-started.md).
### Other Request Types
Since the request in the previous example declared JSON as its content type, Vapor knows to use a JSON decoder automatically. This same method would work just as well for the following request.
```http
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
email=user@vapor.codes&don't+look!
```
!!! tip
You can configure which encoders/decoders Vapor uses. Read on to learn more.
## Response
Let's take a look at how you would create the following HTTP response.
```http
HTTP/1.1 200 OK
Content-Type: application/json
{
"name": "Vapor User",
"email": "user@vapor.codes"
}
```
### Encode Response
Just like decoding, first create a struct or class that represents the data that you are expecting.
```swift
import Foundation
import Vapor
struct User: Content {
var name: String
var email: String
}
```
Then just conform this struct or class to `Content`. Now we are ready to encode that HTTP response.
```swift
router.get("user") { req -> User in
return User(
name: "Vapor User",
email: "user@vapor.codes"
)
}
```
### Other Response Types
Content will automatically encode as JSON by default. You can always override which content type is used
using the `as:` parameter.
```swift
try res.content.encode(user, as: .formURLEncoded)
```
You can also change the default media type for any class or struct.
```swift
struct User: Content {
/// See Content.defaultMediaType
static let defaultMediaType: MediaType = .formURLEncoded
...
}
```
## Configuring Content
Use `ContentConfig` to register custom encoder/decoders for your application. These custom coders will be used anywhere you do `content.encode`/`content.decode`.
```swift
/// Create default content config
var contentConfig = ContentConfig.default()
/// Create custom JSON encoder
var jsonEncoder = JSONEncoder()
jsonEncoder.dateEncodingStrategy = .millisecondsSince1970
/// Register JSON encoder and content config
contentConfig.use(encoder: jsonEncoder, for: .json)
services.register(contentConfig)
```

View File

@ -0,0 +1,28 @@
# Getting Started with Vapor
Check out the main [Getting Started](../getting-started/hello-world.md) guide which covers Vapor specifically. This page is here mostly for consistency with the rest of the packages.
More in-depth information on the APIs included in Vapor, see the sub-sections to the left.
## Package
If you don't want to use one of Vapor's templates to get started, you can always include the framework manually.
```swift
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "Project",
dependencies: [
...
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
],
targets: [
.target(name: "Project", dependencies: ["Vapor", ... ])
]
)
```
Use `import Vapor` to access the APIs.

View File

@ -37,8 +37,6 @@ pages:
- 'Ciphers': 'crypto/ciphers.md'
- 'Asymmetric': 'crypto/asymmetric.md'
- 'Random': 'crypto/random.md'
- 'Deploy':
- 'Getting Started': 'deploy/getting-started.md'
- 'Fluent':
- 'Getting Started': 'fluent/getting-started.md'
- 'Models': 'fluent/models.md'
@ -57,6 +55,9 @@ pages:
- 'Logging':
- 'Getting Started': 'logging/getting-started.md'
- 'Overview': 'logging/overview.md'
- 'Multipart':
- 'Getting Started': 'multipart/getting-started.md'
- 'Overview': 'multipart/overview.md'
- 'MySQL':
- 'Getting Started': 'mysql/getting-started.md'
- 'Fluent MySQL': 'mysql/fluent.md'
@ -91,6 +92,9 @@ pages:
- 'Validation':
- 'Getting Started': 'validation/getting-started.md'
- 'Overview': 'validation/overview.md'
- 'Vapor':
- 'Getting Started': 'vapor/getting-started.md'
- 'Content': 'vapor/content.md'
- 'WebSocket':
- 'Getting Started': 'websocket/websocket.md'
- 'Version (3.0-rc)':