# Content Vapor's content API allows you to easily encode / decode Codable structs to / from HTTP messages. [JSON](https://tools.ietf.org/html/rfc7159) encoding is used by default with out-of-the-box support for [URL-Encoded Form](https://en.wikipedia.org/wiki/Percent-encoding#The_application/x-www-form-urlencoded_type) and [Multipart](https://tools.ietf.org/html/rfc2388). The API is also configurable, allowing for you to add, modify, or replace encoding strategies for certain HTTP content types. ## Overview To understand how Vapor's content API works, you should first understand a few basics about HTTP messages. Take a look at the following example request. ```http POST /greeting HTTP/1.1 content-type: application/json content-length: 18 {"hello": "world"} ``` This request indicates that it contains JSON-encoded data using the `content-type` header and `application/json` media type. As promised, some JSON data follows after the headers in the body. ### Content Struct The first step to decoding this HTTP message is creating a Codable type that matches the expected structure. ```swift struct Greeting: Content { var hello: String } ``` Conforming the type to `Content` will automatically add conformance to `Codable` alongside additional utilities for working with the content API. Once you have the content structure, you can decode it from the incoming request using `req.content`. ```swift app.post("greeting") { req in let greeting = try req.content.decode(Greeting.self) print(greeting.hello) // "world" return HTTPStatus.ok } ``` The decode method uses the request's content type to find an appropriate decoder. If there is no decoder found, or the request does not contain the content type header, a `415` error will be thrown. That means that this route automatically accepts all of the other supported content types, such as url-encoded form: ```http POST /greeting HTTP/1.1 content-type: application/x-www-form-urlencoded content-length: 11 hello=world ``` ### Supported Media Types Below are the media types the content API supports by default. |name|header value|media type| |-|-|-| |JSON|application/json|`.json`| |Multipart|multipart/form-data|`.formData`| |URL-Encoded Form|application/x-www-form-urlencoded|`.urlEncodedForm`| |Plaintext|text/plain|`.plainText`| |HTML|text/html|`.html`| Not all media types support all Codable features. For example, JSON does not support top-level fragments and Plaintext does not support nested data. ## Query Vapor's Content APIs support handling URL encoded data in the URL's query string. ### Decoding To understand how decoding a URL query string works, take a look at the following example request. ```http GET /hello?name=Vapor HTTP/1.1 content-length: 0 ``` Just like the APIs for handling HTTP message body content, the first step for parsing URL query strings is to create a `struct` that matches the expected structure. ```swift struct Hello: Content { var name: String? } ``` Note that `name` is an optional `String` since URL query strings should always be optional. If you want to require a parameter, use a route parameter instead. Now that you have a `Content` struct for this route's expected query string, you can decode it. ```swift app.get("hello") { req -> String in let hello = try req.query.decode(Hello.self) return "Hello, \(hello.name ?? "Anonymous")" } ``` This route would result in the following response given the example request from above: ```http HTTP/1.1 200 OK content-length: 12 Hello, Vapor ``` If the query string were omitted, like in the following request, the name "Anonymous" would be used instead. ```http GET /hello HTTP/1.1 content-length: 0 ``` ### Single Value In addition to decoding to a `Content` struct, Vapor also supports fetching single values from the query string using subscripts. ```swift let name: String? = req.query["name"] ``` ## Override Defaults The default encoders and decoders used by Vapor's Content APIs can be configured. ### Global `ContentConfiguration.global` lets you change the encoders and decoders Vapor uses by default. This is useful for changing how your entire application parses and serializes data. ```swift // create a new JSON encoder that uses unix-timestamp dates let encoder = JSONEncoder() encoder.dateEncodingStrategy = .secondsSince1970 // override the global encoder used for the `.json` media type ContentConfiguration.global.use(encoder: encoder, for: .json) ``` Mutating `ContentConfiguration` is usually done in `configure.swift`. ### One-Off Calls to encoding and decoding methods like `req.content.decode` support passing in custom coders for one-off usages. ```swift // create a new JSON decoder that uses unix-timestamp dates let decoder = JSONDecoder() decoder.dateDecodingStrategy = .secondsSince1970 // decodes Hello struct using custom decoder let hello = try req.content.decode(Hello.self, using: decoder) ``` ## Custom Coders Applications and third-party packages can add support for media types that Vapor does not support by default by creating custom coders. ### Content Vapor specifies two protocols for coders capable of handling content in HTTP message bodies: `ContentDecoder` and `ContentEncoder`. ```swift public protocol ContentEncoder { func encode(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders) throws where E: Encodable } public protocol ContentDecoder { func decode(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders) throws -> D where D: Decodable } ``` Conforming to these protocols allows your custom coders to be registered to `ContentConfiguration` as specified above. ### URL Query Vapor specifies two protocols for coders capable of handling content in URL query strings: `URLQueryDecoder` and `URLQueryEncoder`. ```swift public protocol URLQueryDecoder { func decode(_ decodable: D.Type, from url: URI) throws -> D where D: Decodable } public protocol URLQueryEncoder { func encode(_ encodable: E, to url: inout URI) throws where E: Encodable } ``` Conforming to these protocols allows your custom coders to be registered to `ContentConfiguration` for handling URL query strings using the `use(urlEncoder:)` and `use(urlDecoder:)` methods.