Awesome
Submissions 📩
Installation
Package.swift
Add Submissions
to the Package dependencies:
dependencies: [
...,
.package(url: "https://github.com/nodes-vapor/submissions.git", from: "3.0.0")
]
as well as to your target (e.g. "App"):
targets: [
...
.target(
name: "App",
dependencies: [
...
.product(name: "Submissions", package: "submissions")
]
),
...
]
Introduction
Submissions was written to reduce the amount of boilerplate needed to write the common tasks of rendering forms and processing and validating data from POST/PUT/PATCH requests (PPP-request, or submission for short). Submissions makes it easy to present detailed validation errors for web users as well as API consumers.
Submissions is designed to be flexible. Its functionality is based around Field
s which are abstractions that model the parts of a submission.
single values with its validators and meta data such as a label. Usually a form or API request involves multiple properties comprising a model. This can be modeled using multiple Field
s.
Getting started 🚀
First make sure that you've imported Submissions everywhere it's needed:
import Submissions
Adding the Provider
"Submissions" comes with a light-weight provider that we'll need to register in the configure
function in our configure.swift
file:
try services.register(SubmissionsProvider())
This makes sure that fields and errors can be stored on the request using a FieldCache
service.
Validating API requests
TODO
Validating HTML form requests
Submissions comes with leaf tags that can render fields into HTML. The leaf files needs to be copied from the folder Resources/Views/Submissions
from Submissions
to your project's Resources/Views
. Then we can register Submissions' leaf tags where you register your other leaf tags, for instance:
var leafTagConfig = LeafTagConfig.default()
...
leafTagConfig.useSubmissionsLeafTags()
services.register(leafTagConfig)
You can customize where Submissions looks for the leaf tags by passing in a modified instance of TagTemplatePaths
to useSubmissionsLeafTags(paths:)
.
In order to render a view that contains Submissions leaf tags we need to ensure that the Field
s are added to the field cache and that the Request
is passed into the render
call:
let nameField = Field(key: "name", value: "", label: "Name")
try req.fieldCache().addFields([nameField])
try req.view().render("index", on: req)
In your leaf file you can then refer to this field using an appropriate tag and the key "name" as defined when creating the Field.
Tags
Input tags
The following input tags are available for your leaf files.
#submissions:checkbox( ... )
#submissions:email( ... )
#submissions:hidden( ... )
#submissions:password( ... )
#submissions:text( ... )
#submissions:textarea( ... )
They all accept the same number of parameters.
With these options:
Position | Type | Description | Example | Required? |
---|---|---|---|---|
1 | key | Key to the related field in the field cache | "name" | yes |
2 | placeholder | Placeholder text | "Enter name" | no |
3 | help text | Help text | "This name will be visible to others" | no |
File tag
To add a file upload to your form use this leaf tag.
#submissions:file( ... )
With these options:
Position | Type | Description | Example | Required? |
---|---|---|---|---|
1 | key | Key to the related field in the field cache | "avatar" | yes |
2 | help text | Help text | "This will replace your existing avatar" | no |
3 | accept | Placeholder text | "image/*" | no |
4 | multiple | Support multple file uploads | "true" (or any other non-nil value) | no |
Select tag
A select tag can be added as follows.
#submissions:select( ... )
With these options:
Position | Type | Description | Example | Required? |
---|---|---|---|---|
1 | key | Key to the related field in the field cache | "role" | yes |
2 | options | The possible options in the drop down | roles | no |
3 | placeholder | Placeholder text | "Select an role" | no |
4 | help text | Help text | "The role defines the actions a user is allowed to perform" | no |
The second option (e.g. roles
) is a special parameter that defines the dropdown options. It has to be passed into the render call something like this.
enum Role: String, CaseIterable, Codable {
case user, admin, superAdmin
}
extension Role: OptionRepresentable {
var optionID: String? {
return self.rawValue
}
var optionValue: String? {
return self.rawValue.uppercased()
}
}
let roles: [Role] = .
try req.view().render("index", ["roles": roles.allCases.makeOptions()] on: req)
🏆 Credits
This package is developed and maintained by the Vapor team at Nodes.
📄 License
This package is open-sourced software licensed under the MIT license.