10.4 C
Canberra
Tuesday, July 1, 2025

Encoding and decoding knowledge utilizing the Hummingbird framework


HTTP is all about sending and receiving knowledge over the community. Initially it was solely utilized to switch HTML paperwork, however these days we use HTTP to switch CSS, JavaScript, JSON and lots of different knowledge sorts. Based on the requirements, the Content material-Kind and Content material-Size headers can be utilized to have a greater understanding in regards to the knowledge contained in the physique of the HTTP request.

Trendy net servers can routinely ship again these headers primarily based on the article you come in a request handler operate. That is the case with Hummingbird, it has built-in encoding and decoding assist, which makes the info transformation course of actually easy.

For instance if we setup the next route handler and name the howdy endpoint utilizing cURL with the -i flag, the output will comprise a bit extra details about the response. ℹ️

router.get("howdy") { _ in "howdy" }
        

There are some primary headers within the response, the content-type header incorporates the kind of the physique, which is at the moment a plain textual content with an UTF-8 encoded string, since we have returned a String sort utilizing our Swift code. The content-length is 5, as a result of the character rely of howdy is 5.

There are another headers, however ignore these, the attention-grabbing half for us is the content-type header, and the way it’s injected into the response. Each Hummingbird utility has an encoder and a decoder property. The default values for these are NullEncoder and NullDecoder. The encoders can magically add the correct content material sort header to the response and encode some object right into a HTTP response knowledge. Not every little thing is response encodable and decodable by default, however you’ll be able to encode String objects in Hummingbird by default. 👍

Encoding and decoding JSON objects

Most of the server-side Swift programs are used to create JSON-based RESTful API backends for cell frontends. Hummingbird may help you with this, because it has built-in encoding and decoding assist for JSON objects via the Codable protocol.

First you need to import the HummingbirdFoundation library, since it’s a standalone helper instrument constructed across the Basis framework, and that bundle incorporates the Codable sort extensions. Subsequent you need to setup the encoder and decoder utilizing a JSONEncoder and JSONDecoder occasion. After this, you’ll be able to simply remodel incoming HTTP physique objects into Swift knowledge constructions and return with them as effectively. Let me present you a fast instance. ⤵️

import Hummingbird
import HummingbirdFoundation

struct Foo: Codable {
    let bar: String
    let baz: Int
}

extension Foo: HBResponseCodable {}


extension HBApplication {

    func configure(_ args: AppArguments) throws {
        
        decoder = JSONDecoder()
        encoder = JSONEncoder()
        
        router.submit("foo") { req async throws -> Foo in
            guard let foo = strive? req.decode(as: Foo.self) else {
                throw HBHTTPError(.badRequest, message: "Invalid request physique.")
            }
            return foo
        }
    }

    
}

As you’ll be able to see the kind of the returned content material is now correctly set to utility/json and the size can be offered by default. We had been additionally in a position to decode the Foo object from the request physique and routinely encode the article after we returned with it.

Codable routing works like magic and these days it is a fairly customary strategy if it involves server-side Swift frameworks. Enjoyable reality: this strategy was initially ‘invented’ for Swift by the builders of the Kitura framework. Thanks. 🙏

The HBResponseCodable and the HBResponseEncodable protocols are the fundamental constructing blocks and the HBRequestDecoder and the HBResponseEncoder are answerable for this magic. They make it doable to decode a Decodable object from a HBRequest and encode issues right into a HBResponse object and in addition present further headers. If you want to know extra, I extremely suggest to check out the JSONCoding.swift file contained in the framework. 😉

Encoding and decoding HTML varieties

I do not need to get an excessive amount of into the main points of constructing varieties utilizing HTML code, by the way in which there’s a higher method utilizing SwiftHtml, however I might prefer to focus extra on the underlying knowledge switch mechanism and the enctype attribute. There are 3 doable, however solely two helpful values of the encoding sort:

  • utility/x-www-form-urlencoded
  • multipart/form-data

URL encoding and decoding is supported out of the field when utilizing HummingbirdFoundation, it is a easy wrapper across the URL encoding mechanism to simply assist knowledge transformation.

decoder = URLEncodedFormDecoder()
encoder = URLEncodedFormEncoder()

In order that’s one solution to course of a URL encoded type, the opposite model relies on the multipart strategy, which has no built-in assist in Hummingbird, however you need to use the multipart-kit library from the Vapor framework to course of such varieties. Yow will discover a working instance right here. I even have an article about how one can add recordsdata utilizing multipart type knowledge requests. So there are many sources on the market, that is why I will not embody an instance on this article. 😅

Header primarily based encoding and decoding

First we’ve got to implement a customized request decoder and a response encoder. Within the decoder, we will test the Content material-Kind header for a given request and decode the HTTP physique primarily based on that. The encoder will do the very same factor, however the response physique output goes to rely upon the Settle for header discipline. This is how one can implement it:

struct AppDecoder: HBRequestDecoder {
    
    func decode(
        _ sort: T.Kind,
        from req: HBRequest
    ) throws -> T the place T: Decodable {
        change req.headers["content-type"].first {
        case "utility/json", "utility/json; charset=utf-8":
            return strive JSONDecoder().decode(sort, from: req)
        case "utility/x-www-form-urlencoded":
            return strive URLEncodedFormDecoder().decode(sort, from: req)
        default:
            throw HBHTTPError(.badRequest)
        }
    }
}

struct AppEncoder: HBResponseEncoder {

    func encode(
        _ worth: T,
        from req: HBRequest
    ) throws -> HBResponse the place T: Encodable {
        change req.headers["accept"].first {
        case "utility/json":
            return strive JSONEncoder().encode(worth, from: req)
        case "utility/x-www-form-urlencoded":
            return strive URLEncodedFormEncoder().encode(worth, from: req)
        default:
            throw HBHTTPError(.badRequest)
        }
    }
}

Now in the event you change the configuration and use the AppEncoder & AppDecoder you must have the ability to reply primarily based on the Settle for header and course of the enter primarily based on the Content material-Kind header.

import Hummingbird
import HummingbirdFoundation

struct Foo: Codable {
    let bar: String
    let baz: Int
}

extension Foo: HBResponseEncodable {}
extension Foo: HBResponseCodable {}

extension HBApplication {

    func configure(_ args: AppArguments) throws {
        
        decoder = AppDecoder()
        encoder = AppEncoder()
        
        router.submit("foo") { req async throws -> Foo in
            guard let foo = strive? req.decode(as: Foo.self) else {
                throw HBHTTPError(.badRequest, message: "Invalid request physique.")
            }
            return foo
        }
    }
}

Be happy to mess around with some cURL snippets… 👾

# ought to return JSON encoded knowledge
curl -i -X POST http://localhost:8080/foo 
    -H "Content material-Kind: utility/x-www-form-urlencoded" 
    -H "Settle for: utility/json" 
    --data-raw 'bar=bar&baz=42'

# ought to return URL encoded knowledge
curl -i -X POST http://localhost:8080/foo 
    -H "Content material-Kind: utility/json" 
    -H "Settle for: utility/x-www-form-urlencoded" 
    --data-raw '{"bar": "bar", "baz": 42}'

# ought to return with a 400 standing code
curl -i -X POST http://localhost:8080/foo 
    -H "Content material-Kind: utility/json" 
    -H "Settle for: multipart/form-data" 
    --data-raw '{"bar": "bar", "baz": 42}'

So, primarily based on this text you must have the ability to implement assist to much more content material sorts by merely extending the app encoder and decoder. In fact you may need to import some further bundle dependencies, however that is effective.

Uncooked requests and responses

Another little factor, earlier than I finish this text: you’ll be able to entry the uncooked request physique knowledge and ship again a uncooked response utilizing the HBResponse object like this:

router.submit("foo") { req async throws -> HBResponse in
    
    if let buffer = req.physique.buffer {
        let rawInputData = buffer.getData(
            at: 0,
            size: buffer.readableBytes
        )
        print(rawInputData)
    }
    
    
    if let sequence = req.physique.stream?.sequence {
        for strive await chunk in sequence {
            print(chunk)
        }
    }
    
    guard let knowledge = "howdy".knowledge(utilizing: .utf8) else {
        throw HBHTTPError(.internalServerError)
    }
    
    return .init(
        standing: .okay,
        headers: .init(),
        physique: .byteBuffer(.init(knowledge: knowledge))
    )
}

For smaller requests, you need to use the req.physique.buffer property and switch it right into a Information sort if wanted. Hummingbird has nice assist for the brand new Swift Concurreny API, so you need to use the sequence on the physique stream in the event you want chunked reads. Now just one query left:

What sorts ought to I assist?

The reply is easy: it relies upon. Like actually. These days I began to ditch multipart encoding and I choose to speak with my API utilizing REST (JSON) and add recordsdata as uncooked HTTP physique. I by no means actually needed to assist URL encoding, as a result of in the event you submit HTML varieties, you may ultimately face the necessity of file add and that will not work with URL encoded varieties, however solely with multipart.

In conclusion I might say that the excellent news is that we’ve got loads of alternatives and if you wish to present assist for many of those sorts you do not have to reinvent the wheel in any respect. The multipart-kit library is constructed into Vapor 4, however that is one of many causes I began to love Hummingbird a bit extra, as a result of I can solely embody what I really want. Anyway, competitors is an effective factor to have on this case, as a result of hopefully each frameworks will evolve for good… 🙃

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles