Body Parser
Prism can parse request bodies in four formats out of the box: JSON, URL-encoded forms, XML, and multipart. The PrismBodyParserMiddleware auto-detects the content type, and request extensions give you direct access to parsed data.
Auto-Detection Middleware
let server = PrismHTTPServer(port: 8080)
await server.use(PrismBodyParserMiddleware())
The middleware reads Content-Type and tags the request in userInfo["parsedBodyType"]:
| Content-Type | Tag |
|---|
application/json | "json" |
application/x-www-form-urlencoded | "form" |
multipart/form-data | "multipart" |
application/xml, text/xml | "xml" |
JSON Bodies
The most common format. Use decodeJSON() for typed decoding:
struct CreateUser: Decodable {
let name: String
let email: String
}
await server.post("/users") { request in
let input: CreateUser = try request.decodeJSON()
return .json(["name": input.name, "email": input.email], status: .created)
}
Standard HTML form submissions use application/x-www-form-urlencoded. Access fields through formData:
await server.post("/login") { request in
let form = request.formData
let username = form["username"] ?? ""
let password = form["password"] ?? ""
// Authenticate...
return .json(["user": username])
}
For complex forms with bracket notation like user[name]=Alice&user[address][city]=Paris:
await server.post("/register") { request in
let nested = request.nestedFormData
if let user = nested["user"] as? [String: Any] {
let name = user["name"] as? String ?? ""
if let address = user["address"] as? [String: Any] {
let city = address["city"] as? String ?? ""
return .json(["name": name, "city": city])
}
}
return .json(["error": "Invalid form data"], status: .badRequest)
}
You can also parse nested forms directly:
let data = PrismNestedFormParser.parse("colors[0]=red&colors[1]=blue&user[name]=Alice")
// {"colors": {"0": "red", "1": "blue"}, "user": {"name": "Alice"}}
XML Bodies
Parse XML payloads into a traversable tree of PrismXMLNode:
await server.post("/webhook") { request in
guard let root = request.xmlBody else {
return .json(["error": "Invalid XML"], status: .badRequest)
}
let event = root.child("event")?.text ?? "unknown"
let data = root.child("data")
let items = data?.childrenNamed("item") ?? []
return .json(["event": event, "itemCount": items.count])
}
PrismXMLNode provides:
name — element tag name
attributes — dictionary of XML attributes
text — text content of the element
children — child nodes
child("name") — first child with given name
childrenNamed("name") — all children with given name
// Parsing: <order id="123" status="pending"><item sku="ABC">Widget</item></order>
if let order = request.xmlBody {
let orderId = order.attributes["id"] // "123"
let status = order.attributes["status"] // "pending"
let itemName = order.child("item")?.text // "Widget"
let sku = order.child("item")?.attributes["sku"] // "ABC"
}
You don’t need PrismBodyParserMiddleware to use the parsing extensions — decodeJSON(), formData, xmlBody, and nestedFormData work on any request with a body. The middleware just adds the content type tag for downstream logic.
XML parsing uses Foundation’s XMLParser under the hood — fully native, no dependencies. For large XML payloads, consider streaming the body in chunks instead.