Sunday, April 2, 2023
Learning Code
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
Learning Code
No Result
View All Result
Home Swift

File upload using Vapor 4

learningcode_x1mckf by learningcode_x1mckf
September 18, 2022
in Swift
0
File upload using Vapor 4
74
SHARES
1.2k
VIEWS
Share on FacebookShare on Twitter


2020/12/10

Discover ways to implement a primary HTML file add kind utilizing the Leaf template engine and Vapor, all written in Swift in fact.

Vapor

Constructing a file add kind

Let’s begin with a primary Vapor venture, we will use Leaf (the Tau launch) for rendering our HTML recordsdata. It’s best to be aware that Tau was an experimental launch, the adjustments had been reverted from the ultimate 4.0.0 Leaf launch, however you may nonetheless use Tau should you pin the precise model in your manifest file. Tau will probably be printed afterward in a standalone repository… 🤫


import PackageDescription

let bundle = Package deal(
    identify: "myProject",
    platforms: [
       .macOS(.v10_15)
    ],
    dependencies: [
        .package(url: "https://github.com/vapor/vapor", from: "4.35.0"),
        .package(url: "https://github.com/vapor/leaf", .exact("4.0.0-tau.1")),
        .package(url: "https://github.com/vapor/leaf-kit", .exact("1.0.0-tau.1.1")),
    ],
    targets: [
        .target(
            name: "App",
            dependencies: [
                .product(name: "Leaf", package: "leaf"),
                .product(name: "LeafKit", package: "leaf-kit"),
                .product(name: "Vapor", package: "vapor"),
            ],
            swiftSettings: [
                .unsafeFlags(["-cross-module-optimization"], .when(configuration: .launch))
            ]
        ),
        .goal(identify: "Run", dependencies: [.target(name: "App")]),
        .testTarget(identify: "AppTests", dependencies: [
            .target(name: "App"),
            .product(name: "XCTVapor", package: "vapor"),
        ])
    ]
)

Now should you open the venture with Xcode, remember to setup a customized working listing first, as a result of we will create templates and Leaf will search for these view recordsdata underneath the present working listing by default. We’re going to construct a quite simple index.leaf file, you may place it into the Assets/Views listing.


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta identify="viewport" content material="width=device-width, initial-scale=1">
    <title>File add instance</title>
  </head>
  <physique>
    <h1>File add instance</h1>

    <kind motion="/add" technique="publish" enctype="multipart/form-data">
        <enter sort="file" identify="file"><br><br>
        <enter sort="submit" worth="Submit">
    </kind>
  </physique>
</html>


As you may see, it is a normal file add kind, once you wish to add recordsdata utilizing the browser you all the time have to make use of the multipart/form-data encryption sort. The browser will pack each discipline within the kind (together with the file knowledge with the unique file identify and a few meta data) utilizing a particular format and the server software can parse the contents of this. Happily Vapor has built-in help for simple decoding multipart kind knowledge values. We’re going to use the POST /add route to save lots of the file, let’s setup the router first so we will render our principal web page and we’re going to put together our add path as properly, however we’ll reply with a dummy message for now.

import Vapor
import Leaf

public func configure(_ app: Utility) throws 

    
    app.routes.defaultMaxBodySize = "10mb"
    
    
    app.middleware.use(FileMiddleware(publicDirectory: app.listing.publicDirectory))
    
    
    LeafRenderer.Choice.caching = .bypass
    app.views.use(.leaf)

    
    app.get  req in
        req.leaf.render(template: "index")
    
    
    
    app.publish("add")  req in
        "Add file..."
    

You possibly can put the snippet above into your configure.swift file then you may attempt to construct and run your server and go to http://localhost:8080, then attempt to add any file. It will not truly add the file, however at the least we’re ready to write down our server facet Swift code to course of the incoming kind knowledge. ⬆️



File add handler in Vapor

Now that we now have a working uploader kind we must always parse the incoming knowledge, get the contents of the file and place it underneath our Public listing. You possibly can truly transfer the file anyplace in your server, however for this instance we’re going to use the Public listing so we will merely check if everthing works through the use of the FileMiddleware. If you do not know, the file middleware serves every part (publicly accessible) that’s situated inside your Public folder. Let’s code.

app.publish("add")  req -> EventLoopFuture<String> in
    struct Enter: Content material 
        var file: File
    
    let enter = attempt req.content material.decode(Enter.self)
    
    let path = app.listing.publicDirectory + enter.file.filename
    
    return req.software.fileio.openFile(path: path,
                                           mode: .write,
                                           flags: .allowFileCreation(posixMode: 0x744),
                                           eventLoop: req.eventLoop)
        .flatMap  deal with in
            req.software.fileio.write(fileHandle: deal with,
                                         buffer: enter.file.knowledge,
                                         eventLoop: req.eventLoop)
                .flatMapThrowing  _ in
                    attempt deal with.shut()
                    return enter.file.filename
                
        

So, let me clarify what simply occurred right here. First we outline a brand new Enter sort that can comprise our file knowledge. There’s a File sort in Vapor that helps us decoding multipart file add varieties. We will use the content material of the request and decode this kind. We gave the file identify to the file enter kind beforehand in our leaf template, however in fact you may change it, however should you achieve this you additionally should align the property identify contained in the Enter struct.

After we now have an enter (please be aware that we do not validate the submitted request but) we will begin importing our file. We ask for the situation of the general public listing, we append the incoming file identify (to maintain the unique identify, however you may generate a brand new identify for the uploaded file as properly) and we use the non-blocking file I/O API to create a file handler and write the contents of the file into the disk. The fileio API is a part of SwiftNIO, which is nice as a result of it is a non-blocking API, so our server will probably be extra performant if we use this as an alternative of the common FileManager from the Basis framework. After we opened the file, we write the file knowledge (which is a ByteBuffer object, unhealthy naming…) and eventually we shut the opened file handler and return the uploaded file identify as a future string. If you have not heard about futures and guarantees you must examine them, as a result of they’re all over the place on the server facet Swift world. Cannot look forward to async / awake help, proper? 😅

We’ll improve the add consequence web page just a bit bit. Create a brand new consequence.leaf file contained in the views listing.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta identify="viewport" content material="width=device-width, initial-scale=1">
    <title>File uploaded</title>
  </head>
  <physique>
    <h1>File uploaded</h1>

    #if(isImage):
        <img src="#(fileUrl)" width="256px"><br><br>
    #else:
    <a href="#(fileUrl)" goal="_blank">Present me!</a><br><br>
    #endif
    
    <a href="/">Add new one</a>
  </physique>
</html>

So we will test if the uploaded file has a picture extension and cross an isImage parameter to the template engine, so we will show it if we will assume that the file is a picture, in any other case we will render a easy hyperlink to view the file. Contained in the publish add handler technique we’re going to add a date prefix to the uploaded file so we can add a number of recordsdata even with the identical identify.

app.publish("add")  req -> EventLoopFuture<View> in
        struct Enter: Content material 
            var file: File
        
        let enter = attempt req.content material.decode(Enter.self)

        guard enter.file.knowledge.readableBytes > 0 else 
            throw Abort(.badRequest)
        

        let formatter = DateFormatter()
        formatter.dateFormat = "y-m-d-HH-MM-SS-"
        let prefix = formatter.string(from: .init())
        let fileName = prefix + enter.file.filename
        let path = app.listing.publicDirectory + fileName
        let isImage = ["png", "jpeg", "jpg", "gif"].incorporates(enter.file.extension?.lowercased())

        return req.software.fileio.openFile(path: path,
                                               mode: .write,
                                               flags: .allowFileCreation(posixMode: 0x744),
                                               eventLoop: req.eventLoop)
            .flatMap  deal with in
                req.software.fileio.write(fileHandle: deal with,
                                             buffer: enter.file.knowledge,
                                             eventLoop: req.eventLoop)
                    .flatMapThrowing  _ in
                        attempt deal with.shut()
                    
                    .flatMap 
                        req.leaf.render(template: "consequence", context: [
                            "fileUrl": .string(fileName),
                            "isImage": .bool(isImage),
                        ])
                    
            
    

If you happen to run this instance you must have the ability to view the picture or the file straight from the consequence web page.



A number of file add utilizing Vapor

By the best way, it’s also possible to add a number of recordsdata directly should you add the a number of attribute to the HTML file enter discipline and use the recordsdata[] worth as identify.

<enter sort="file" identify="recordsdata[]" a number of><br><br>

To help this we now have to change our add technique, don’t be concerned it is not that sophisticated because it seems at first sight. 😜

app.publish("add")  req -> EventLoopFuture<View> in
    struct Enter: Content material 
        var recordsdata: [File]
    
    let enter = attempt req.content material.decode(Enter.self)

    let formatter = DateFormatter()
    formatter.dateFormat = "y-m-d-HH-MM-SS-"
    let prefix = formatter.string(from: .init())
    
    struct UploadedFile: LeafDataRepresentable 
        let url: String
        let isImage: Bool
        
        var leafData: LeafData 
            .dictionary([
                "url": url,
                "isImage": isImage,
            ])
        
    
    
    let uploadFutures = enter.recordsdata
        .filter  $0.knowledge.readableBytes > 0 
        .map  file -> EventLoopFuture<UploadedFile> in
            let fileName = prefix + file.filename
            let path = app.listing.publicDirectory + fileName
            let isImage = ["png", "jpeg", "jpg", "gif"].incorporates(file.extension?.lowercased())
            
            return req.software.fileio.openFile(path: path,
                                                   mode: .write,
                                                   flags: .allowFileCreation(posixMode: 0x744),
                                                   eventLoop: req.eventLoop)
                .flatMap  deal with in
                    req.software.fileio.write(fileHandle: deal with,
                                                 buffer: file.knowledge,
                                                 eventLoop: req.eventLoop)
                        .flatMapThrowing  _ in
                            attempt deal with.shut()
                            return UploadedFile(url: fileName, isImage: isImage)
                        
                    
                
        

    return req.eventLoop.flatten(uploadFutures).flatMap  recordsdata in
        req.leaf.render(template: "consequence", context: [
            "files": .array(files.map(.leafData))
        ])
    

The trick is that we now have to parse the enter as an array of recordsdata and switch each attainable add right into a future add operation. We will filter the add candidates by readable byte dimension, then we map the recordsdata into futures and return an UploadedFile consequence with the right file URL and is picture flag. This construction is a LeafDataRepresentable object, as a result of we wish to cross it as a context variable to our consequence template. We even have to alter that view as soon as once more.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta identify="viewport" content material="width=device-width, initial-scale=1">
    <title>Recordsdata uploaded</title>
  </head>
  <physique>
    <h1>Recordsdata uploaded</h1>

    #for(file in recordsdata):
        #if(file.isImage):
        <img src="#(file.url)" width="256px"><br><br>
        #else:
        <a href="#(file.url)" goal="_blank">#(file.url)</a><br><br>
        #endif
    #endfor
    
    <a href="/">Add new recordsdata</a>
  </physique>
</html>

Properly, I do know it is a lifeless easy implementation, nevertheless it’s nice if you wish to observe or learn to implement file uploads utilizing server facet Swift and the Vapor framework. You may also add recordsdata on to a cloud service utilizing this method, there’s a library referred to as Liquid, which is analogous to Fluent, however for file storages. Presently you should utilize Liquid to add recordsdata to the local storage or you should utilize an AWS S3 bucket or you may write your personal driver utilizing LiquidKit. The API is fairly easy to make use of, after you configure the motive force you may add recordsdata with just some traces of code.

I hope you preferred this tutorial, you probably have any questions or concepts, please let me know.






Source link

You might also like

Swift Against Humanity – Hacking with Swift

Introducing MotionBar – the Animated Tab Bar Library

Introducing – AI Utils for macOS

Share30Tweet19
learningcode_x1mckf

learningcode_x1mckf

Recommended For You

Swift Against Humanity – Hacking with Swift

by learningcode_x1mckf
April 1, 2023
0
Swift Against Humanity – Hacking with Swift

So that you suppose you already know Swift? Assume once more! Recent from the success of our audiobook launch, Laboratoires TwoStraws is again with an all-new card sport...

Read more

Introducing MotionBar – the Animated Tab Bar Library

by learningcode_x1mckf
March 31, 2023
0
Introducing MotionBar – the Animated Tab Bar Library

In an earlier tutorial, we shared find out how to create a customized tab bar view utilizing SwiftUI to exchange the usual tab bar. If you happen to’ve...

Read more

Introducing – AI Utils for macOS

by learningcode_x1mckf
March 24, 2023
0
Introducing – AI Utils for macOS

⚠️ REQUIRES a FREE OpenAI API key. You will get one utilizing this hyperlink. ⚠️ Improve your productiveness with our AI powered utility application. - accessible...

Read more

Encoding and decoding data using the Hummingbird framework

by learningcode_x1mckf
March 22, 2023
0
Encoding and decoding data using the Hummingbird framework

HTTP is all about sending and receiving information over the community. Initially it was solely utilized to switch HTML paperwork, however these days we use HTTP to switch...

Read more

Hummingbird routing and requests – The.Swift.Dev.

by learningcode_x1mckf
March 17, 2023
0
Hummingbird routing and requests – The.Swift.Dev.

Routing on the server facet means the server goes to ship a response primarily based on the URL path that the consumer referred to as when firing up...

Read more
Next Post
How to Use localStorage in JavaScript

How to Use localStorage in JavaScript

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related News

Google expands open source bounties, will soon support Javascript fuzzing too – ZDNet

SourceBuddy Brings Eval To Java – iProgrammer

February 11, 2023
Google expands open source bounties, will soon support Javascript fuzzing too – ZDNet

Regions asked to replicate C Java's anti-stunting programs – ANTARA English

February 15, 2023
What is C++ Programming Language?

What is C++ Programming Language?

September 17, 2022

Browse by Category

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

RECENT POSTS

  • So why did they decide to call it Java? – InfoWorld
  • Senior Java Developer – IT-Online
  • 4 Packages for Working With Date and Time in JavaScript – MUO – MakeUseOf

CATEGORIES

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

© 2022 Copyright Learning Code

No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#

© 2022 Copyright Learning Code

Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?