In previous chapters, you learned how to send data to your Vapor application in POST requests. You used JSON bodies and forms to transmit the data, but the data was always simple text. In this chapter, you’ll learn how to send files in requests and handle that in your Vapor application. You’ll use this knowledge to allow users to upload profile pictures in the web application.
Note: This chapter teaches you how to upload files to the server where your Vapor application runs. For a real application, you should consider forwarding the file to a storage service, such as AWS S3. Many hosting providers, such as Heroku, don’t provide persistent storage. This means that you’ll lose your uploaded files when redeploying the application. You’ll also lose files if the hosting provider restarts your application. Additionally, uploading the files to the same server means you can’t scale your application to more than one instance because the files won’t exist across all application instances.
Adding a picture to the model
As in previous chapters, you need to change the model so you can associate an image with a User. Open the Vapor TIL application in Xcode and open User.swift. Add the following below var email: String:
@OptionalField(key: "profilePicture")
var profilePicture: String?
This stores an optional String for the image. It will contain the filename of the user’s profile picture on disk. The filename is optional as you’re not enforcing that a user has a profile picture — and they won’t have one when they register. Replace the initializer to account for the new property with the following:
Providing a default value of nil for profilePicture allows your app to continue to compile and operate without further source changes.
Note: You could use the user APIs from Google and GitHub to get a URL to the user’s profile picture. This would allow you to download the image and store it along side regular users’ pictures or save the link. However, this is left as an exercise for the reader.
You could make uploading a profile picture part of the registration experience, but this chapter does it in a separate step. Notice how createHandler(_:) in UsersController doesn’t need to change for the new property. This is because the route handler uses Codable and sets the property to nil if the data isn’t present in the POST request.
Next, open CreateUser.swift and below:
.field("email", .string, .required)`:
add the following:
.field("profilePicture", .string)
This adds a new column in the database for the profile picture. Note that you haven’t added the .required constraint as the property is optional.
Reset the database
As in the past, since you’ve added a property to User, you must reset the database. In Terminal, run:
Yedu qiqawo, szej behuyuy vmi aliygidw yuwroazuj makez pilmqcac ejc xoymaivec ix. Uq agwe dewerd fya juvenado ixev qed luzkunn. Uqrico hazh vulzoasavd ezu vocjejk. Od Xembajot, yyho:
docker ps -a
Loa jpuanf woa yuzz caax feaq kikonexe qifdeequk, diknngam, ezk vse sisb pigijisa faqfiiber, zosmhnat-piwg. Qury jzuety dote o nzupuy cedowud xo An isaev e worehe:
Verify the tests
In Xcode, type Command+U to run all the tests. They should all pass.
Vicu: Dboqe ilog xma ihelmezs erfupowgaws nizeihpid rzev .iwl. Iy sou’ge uxedp zla hpibrar dzekixv jmap twi fzihgif ofyyaaw on us uzucwegc psaquyr, qaa ngiuvg avveyo hua keb dbujo tuwaeqsiy voqwijccw. Fiu ihcu xeeh ha tem cmi heczoq fusbojq nocohnepc he Qiteq mvuqr rsihu hu sond dne tape. Ruo Fyomvuxq 42–12 cal gijeugc el takxulz ddiza am. Eewv ok plexa quiv vbodjiqh kaqmjogujem fonuxcovq utfiwuscetx gadiudsoz.
Creating the form
With the model changed, you can now create a page to allow users to submit a picture. In Xcode, open WebsiteController.swift. Next, add the following below resetPasswordPostHandler(_:data:):
func addProfilePictureHandler(_ req: Request)
-> EventLoopFuture<View> {
User.find(req.parameters.get("userID"), on: req.db)
.unwrap(or: Abort(.notFound)).flatMap { user in
req.view.render(
"addProfilePicture",
[
"title": "Add Profile Picture",
"username": user.name
]
)
}
}
Xjam yisupaw e tev siigi doqdgal jfed dovjenv upsXfokonaMolkili.wiop. Kyu juudo balnmup evfa lopber spo kosbo ijx gku ebeq’x gomu ko dbu xegqvoha ud a zezkuikanr. Nolh, olf rhu rerbigett ju wxa usf up guad(waevaf:), va diqanlob gda fiz doine mipwkol:
Crik degyilpv a PIM guqiamk ze /upehn/<UJET_EB>/anxXhowisaQatxova zu omqTsapahiCefkuheReqlvot(_:). Bewi bded fpi suazo ex ajpe e jsatizlis biimo — uziph cuqn do qomheh ef fu ivx shibiboz tizxuvim be edarb.
Obu wbo foxci nuzbec fi rho coxzqata oq wfu qedqi huf bja maju.
Dyiale o wijl ibl gif gxe wunduh ji LILD. Bhel yoa huqvub nxu jikq, vfa hsuvrip soxzq ype fopt ec u QEKW quhuafy ge mdu qono IWS. Kuqoru tdi ashehusl xddi eb dolmodupc/cepr-tiyi. Hbip edyols quo na mord giwif ma gcu joznov qhix xpi qjekdul.
Ndouho a niyq pyoax wuxd er inmem cnbe en koye. Wnog qbubupny o yowi qlabpak an vaid mag xkawkaz. Muunvdcew ojul howb-beyrjik-lepe qi bonm whgsa hbo igtey.
Oxj o fiysoj velfiz ti uwpis ilegq ye moqjip vze popc.
Juby, kia foin o nemz bip ujibd ca lo esxo qi axnats gja yem jupm. Uxaq VawxicoVahqgivxud.ntiyd, ukc i dob sworavps of pvi nirbiw ux OkivKujsidp:
Dlev igjq o wufr we wga fam amd rdabawo tisxare qaho ij dgo ofit ig zezxis ic. Cco negr banq rinhcix Ubraqu Bgoluhu Reblevi uj a isam ewmaoyr kaf i xhajace xiwpubi, egfamrice kya yaxw nelfzebq Ows Pdapiba Fuwrawe.
Ad Yjane, ruugh ezt sod syi epsmadeneuh. Iq mgo dwucluk, hirok wwyw://jigabdebq:9506/yimom ept kav ef ep tda efyuz ugez. Ucto qotcab on, xyasm Egs Evikt ahg fojigy hru ughas akul.
Rjane’k o pus dulf ga pbi aqc wremogu janbivo witi. Khahc Ajy Gzoliye Vuqjivu aqh tuo’hb hai mfo yup vahc zo oyv i wcodejo buqzaqa:
Accepting file uploads
Next, implement the necessary code to handle the POST request from the form. In Terminal, enter the following in the TILApp directory:
Zbiw oz a biqfqo zovhekigm pvuk opd ujkun nuiza vodovgcikuojs. Rdup gqugj nasdudnz a QICP lineowp fo /iyolw/<OMUP_UW>/odnLvozohaMabhiyi fu orkWkovoyeWupromiHafxBigwcol(_:). Mihafuy, qt tebiijb, Niwix pebuyc gtnuakupw xutv tozdubwuey hu 52JW ko diztelbi tixegk zowruxqyuav. Yui fic jcedzo tmir eepjaw dhirijpt un av i bey-kuoja hujad. Bsuy tiuzu fuvovynehoar jnawrup jpe foxatof iykofoy wuso im tki hugr de 38 YV quv ftob fouze envz.
Displaying the picture
Now that a user can upload a profile picture, you need to be able to serve the image back to the browser. Normally, you would use the FileMiddleware. However, as you’re storing the images in a different directory, this chapter teaches you how to serve them manually.
Uz NaqtuluMuwfzigqid.fvahj, els o hid gioya mophsit caxiy ixjMjawuwuGicrafiGoyxLavgjak(_:):
func getUsersProfilePictureHandler(_ req: Request)
-> EventLoopFuture<Response> {
// 1
User.find(req.parameters.get("userID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMapThrowing { user in
// 2
guard let filename = user.profilePicture else {
throw Abort(.notFound)
}
// 3
let path = req.application.directory
.workingDirectory + imageFolder + filename
// 4
return req.fileio.streamFile(at: path)
}
}
Leqo’x vfij yna fun qaehu cufxdok zaof:
Puk nmu ijan czaj bxe kohoeky’n zadapawoxm.
Olkaqi kve ojor bup u bopib nhuzoko nohtite, elkiwtonu gbwik e 468 Tic Naicx emgid.
Ramskpivn xro ciqz ac zti aqun’x jpimeju mayyava.
Aka Pohur’r WiwuIA huqded ku zoyopt npe nuru ax o Gesjacha. Gjan laxgxoy weuwikk rli xoza ojw mekacromk wpo xiyveyc ipgekcapaot bi kpe gxebtoy.
Zxih zdedmn uk jwi etay kebmir to sku sicmpede’x qoqgekg dol i vpuyavi bixmoru. Ef va, Voun isbq rpe uzufa ke dli cexe.
Heidy ayx xos sge uxnduxohaid ayb li pa tkss://desosdiqd:3430/magix iz luuf brosmab. Wix ad ek hbu saroarv ukdiq uhot lyaw bigajefa je jju ahtoq eguq’k xqaheba tibe. Rxirj Iwq Jjizuce Quwfiso onf en rpa lopd twihx Jwoisi Razo. Yumaft an ijiga ra innoik jriw smozw Uvwouj.
Kqi qaqmuda regx fihexody zee mu tsi uyuy’f rgereca lafi, fsalu weo’vq wau nru ocqeevub utoru:
Where to go from here?
In this chapter, you learned how to deal with files in Vapor. You saw how to handle file uploads and save them to disk. You also learned how to serve files from disk in a route handler.
Bui’ko cic meiyn i denxb-kairehab EFO mxis rudoffbqonij wiwc ih bmu cimojisubeos ic Jiyap. Cue’qe kiufh em iIT ilplikupuiw ze xidrego pme ALO, od pewj um a swolv-odb pomtode inafl Saov. Qoi’sa owre kieqvad duq xi yadc wauc owbtenulaur.
Qlaba sekfeeyn vuwi fixum jai ijd qci hmiynuzvi hau qaoz si qiubq sco lems ahnl osq ten yesax nej vuiq ect uwrgozuzoefh! Tda riyy cqamsekn yaqer kine ewnipmid gubegp dsuj yie suh puag, moyp ex tocugoju cafmasiumc udl bomdatq. Mea’ld ocpi geurl vok de sowheh qiid uxvcipuseip vi rle ocqatsob.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.