# Content - Vapor Docs

Skip to content


# Using Content

In Vapor 3, all content types (JSON, protobuf, URLEncodedForm, Multipart, 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 mostly JSON as an example. But keep in mind the API is the same for any supported content type.

## Server

This first section will go over decoding and encoding messages sent between your server and connected clients. See the client section for encoding and decoding content in messages sent to external APIs.

### Request

Let's take a look at how you would parse the following HTTP request sent to your server.

    POST /login HTTP/1.1
    Content-Type: application/json

    {
        "email": "user@vapor.codes",
        "password": "don't look!"
    }

First, create a struct or class that represents the data you expect.

    import Vapor

    struct LoginRequest: Content {
        var email: String
        var password: String
    }

Notice the key names exactly match the keys in the request data. The expected data types also match. Next conform this struct or class to `Content`.

#### Decode

Now we are ready to decode that HTTP request. Every `Request` has a `ContentContainer` that we can use to decode content from the message's body.

    router.post("login") { req -> Future<HTTPStatus> in
        return req.content.decode(LoginRequest.self).map { loginRequest in
            print(loginRequest.email) // user@vapor.codes
            print(loginRequest.password) // don't look!
            return HTTPStatus.ok
        }
    }

We use `.map(to:)` here since `decode(...)` returns a future.

Note

Decoding content from requests is asynchronous because HTTP allows bodies to be split into multiple parts using chunked transfer encoding.

#### Router

To help make decoding content from incoming requests easier, Vapor offers a few extensions on `Router` to do this automatically.

    router.post(LoginRequest.self, at: "login") { req, loginRequest in
        print(loginRequest.email) // user@vapor.codes
        print(loginRequest.password) // don't look!
        return HTTPStatus.ok
    }

#### Detect Type

Since the HTTP request in this 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.

    POST /login HTTP/1.1
    Content-Type: application/x-www-form-urlencoded

    email=user@vapor.codes&don't+look!

All HTTP requests must include a content type to be valid. Because of this, Vapor will automatically choose an appropriate decoder or error if it encounters an unknown media type.

Tip

You can configure the default encoders and decoders Vapor uses.

#### Custom

You can always override Vapor's default decoder and pass in a custom one if you want.

    let user = try req.content.decode(User.self, using: JSONDecoder())
    print(user) // Future<User>

### Response

Let's take a look at how you would create the following HTTP response from your server.

    HTTP/1.1 200 OK
    Content-Type: application/json

    {
        "name": "Vapor User",
        "email": "user@vapor.codes"
    }

Just like decoding, first create a struct or class that represents the data that you are expecting.

    import Vapor

    struct User: Content {
        var name: String
        var email: String
    }

Then just conform this struct or class to `Content`.

#### Encode

Now we are ready to encode that HTTP response.

    router.get("user") { req -> User in
        return User(name: "Vapor User", email: "user@vapor.codes")
    }

This will create a default `Response` with `200 OK` status code and minimal headers. You can customize the response using a convenience `encode(...)` method.

    router.get("user") { req -> Future<Response> in
        return User(name: "Vapor User", email: "user@vapor.codes")
            .encode(status: .created)
    }

#### Override Type

Content will automatically encode as JSON by default. You can always override which content type is used using the `as:` parameter.

    try res.content.encode(user, as: .urlEncodedForm)

You can also change the default media type for any class or struct.

    struct User: Content {
        /// See `Content`.
        static let defaultContentType: MediaType = .urlEncodedForm

        ...
    }

## Client

Encoding content to HTTP requests sent by `Client`s is similar to encoding HTTP responses returned by your server.

### Request

Let's take a look at how we can encode the following request.

    POST /login HTTP/1.1
    Host: api.vapor.codes
    Content-Type: application/json

    {
        "email": "user@vapor.codes",
        "password": "don't look!"
    }

#### Encode

First, create a struct or class that represents the data you expect.

    import Vapor

    struct LoginRequest: Content {
        var email: String
        var password: String
    }

Now we are ready to make our request. Let's assume we are making this request inside of a route closure, so we will use the incoming request as our container.

    let loginRequest = LoginRequest(email: "user@vapor.codes", password: "don't look!")
    let res = try req.client().post("https://api.vapor.codes/login") { loginReq in
        // encode the loginRequest before sending
        try loginReq.content.encode(loginRequest)
    }
    print(res) // Future<Response>

### Response

Continuing from our example in the encode section, let's see how we would decode content from the client's response.

    HTTP/1.1 200 OK
    Content-Type: application/json

    {
        "name": "Vapor User",
        "email": "user@vapor.codes"
    }

First of course we must create a struct or class to represent the data.

    import Vapor

    struct User: Content {
        var name: String
        var email: String
    }

#### Decode

Now we are ready to decode the client response.

    let res: Future<Response> // from the Client

    let user = res.flatMap { try $0.content.decode(User.self) }
    print(user) // Future<User>

### Example

Let's now take a look at our complete `Client` request that both encodes and decodes content.

    // Create the LoginRequest data
    let loginRequest = LoginRequest(email: "user@vapor.codes", password: "don't look!")
    // POST /login
    let user = try req.client().post("https://api.vapor.codes/login") { loginReq in
        // Encode Content before Request is sent
        return try loginReq.content.encode(loginRequest)
    }.flatMap { loginRes in
        // Decode Content after Response is received
        return try loginRes.content.decode(User.self)
    }
    print(user) // Future<User>

## Query String

URL-Encoded Form data can be encoded and decoded from an HTTP request's URI query string just like content. All you need is a class or struct that conforms to `Content`. In these examples, we will be using the following struct.

    struct Flags: Content {
         var search: String?
         var isAdmin: Bool?
    }

### Decode

All `Request`s have a `QueryContainer` that you can use to decode the query string.

    let flags = try req.query.decode(Flags.self)
    print(flags) // Flags

### Encode

You can also encode content. This is useful for encoding query strings when using `Client`.

    let flags: Flags ...
    try req.query.encode(flags)

## Dynamic Properties

One of the most frequently asked questions regarding `Content` is:

> How do I add a property to just this response?

The way Vapor 3 handles `Content` is based entirely on `Codable`. At no point (that is publically accessible) is your data in an arbitrary data structure like `[String: Any]` that you can mutate at will. Because of this, all data structures that your app accepts and returns must be statically defined.

Let's take a look at a common scenario to better understand this. Very often when you are creating a user, there are a couple different data formats required:

- create: password should be supplied twice to check values match
- internal: you should store a hash not the plaintext password
- public: when listing users, the password hash should not be included

To do this, you should create three types.

    // Data required to create a user
    struct UserCreate: Content {
        var email: String
        var password: String
        var passwordCheck: String
    }

    // Our internal User representation
    struct User: Model {
        var id: Int?
        var email: String
        var passwordHash: Data
    }

    // Public user representation
    struct PublicUser: Content {
        var id: Int
        var email: String
    }

    // Create a router for POST /users
    router.post(UserCreate.self, at: "users") { req, userCreate -> PublicUser in
        guard userCreate.password == passwordCheck else { /* some error */ }
        let hasher = try req.make(/* some hasher */)
        let user = try User(
            email: userCreate.email,
            passwordHash: hasher.hash(userCreate.password)
        )
        // save user
        return try PublicUser(id: user.requireID(), email: user.email)
    }

For other methods such as `PATCH` and `PUT`, you may want to create additional types to supports the unique semantics.

### Benefits

This method may seem a bit verbose at first when compared to dynamic solutions, but it has a number of key advantages:

- Statically Typed: Very little validation is needed on top of what Swift and Codable do automatically.
- Readability: No need for Strings and optional chaining when working with Swift types.
- Maintainable: Large projects will appreciate having this information separated and clearly stated.
- Shareable: Types defining what content your routes accept and return can be used to conform to specifications like OpenAPI or even be shared directly with clients written in Swift.
- Performance: Working with native Swift types is much more performant than mutating `[String: Any]` dictionaries.

## JSON

JSON is a very popular encoding format for APIs and the way in which dates, data, floats, etc are encoded is non-standard. Because of this, Vapor makes it easy to use custom `JSONDecoder`s when you interact with other APIs.

    // Conforms to Encodable
    let user: User ...
    // Encode JSON using custom date encoding strategy
    try req.content.encode(json: user, using: .custom(dates: .millisecondsSince1970))

You can also use this method for decoding.

    // Decode JSON using custom date encoding strategy
    let user = try req.content.decode(json: User.self, using: .custom(dates: .millisecondsSince1970))

If you would like to set a custom JSON encoder or decoder globally, you can do so using configuration.

## Configure

Use `ContentConfig` to register custom encoder/decoders for your application. These custom coders will be used anywhere you do `content.encode`/`content.decode`.

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