Generalized Parsing: Part 2

Episode #125 • Nov 16, 2020 • Subscriber-Only

Now that we have generalized the parser type it’s time to parse things that aren’t just plain strings. In just a few lines of code the parser type can parse environment variable dictionaries and even become a fully capable URL router.

Part 2
Parsing dictionaries
Parsing URL requests: defining a parsable type
Parsing URL requests: defining parsers
Optional parsers
Next time: what’s the point?

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.


Now although it is a little annoying that we have to sprinkle a little bit of extra syntax to let the compiler know exactly what type it is working with, it is also forcing a very good pattern on us. The prefix parser only works for collections whose SubSequence is equal to itself. Such collections are able to mutate themselves in an efficient manner because they operate on views of a shared storage rather than make needless copies all over the place.

This is why we are forced to provide array slices and substrings as input to these parsers, because it allows them to do their work in the most efficient way possible.

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in


  1. Write a function that transforms a URLRequest into the parser-friendly RequestData type.

    extension RequestData {
      init(urlRequest: URLRequest) {
        self.body = urlRequest.httpBody
        self.headers = urlRequest.allHTTPHeaderFields?.mapValues { $0[...] } ?? [:]
        self.method = urlRequest.httpMethod
        self.pathComponents = urlRequest.url?.path.split(separator: "/")[...] ?? []
        self.queryItems = urlRequest.url
          .flatMap {
            URLComponents(url: $0, resolvingAgainstBaseURL: false)?.queryItems?
              .map { ($, $0.value?[...] ?? "") }
          ?? []
  2. Implement a header parser that can parse a value from a given header name. For example:

    Parser.header(name: "Content-Length", .int)
    // Parser<RequestData, Int>
    extension Parser where Input == RequestData {
      static func header(name: String, _ parser: Parser<Substring, Output>) -> Self {
        .init { input in
            var value = input.headers[name],
            let output =,
          else { return nil }
          input.headers[name] = nil
          return output
  3. Implement a JSON body parser that can decode a particular value from a request body. For example:

    struct User: Decodable {
      var id: Int
      var name: String
    Parser.body(as: User.self, decoder: JSONDecoder())
    // Parser<RequestData, User>
    extension Parser where Input == RequestData {
      static func body(
        as decodable: Output.Type = Output.self,
        decoder: JSONDecoder = .init()
      ) -> Self where Output: Decodable {
        .init { input in
            let data = input.body,
            let output = try? decoder.decode(decodable, from: data)
          else { return nil }
          input.body = nil
          return output