具有更高类型安全性和更少麻烦的双向路由器

swift-url-routing

双向 URL 路由器,具有更高的类型安全性和更少的麻烦。此库是使用解析构建的。


了解更多信息

这个库在 Point-Free 的一集中进行了讨论,这是一个探索函数式编程、Swift 编程和 Swift 语言的视频系列,由 Brandon WilliamsStephen Celis 主持。

视频海报图片

赋予动机

URL 路由是客户端和服务器端应用程序中普遍存在的问题:

  • 客户端(如 iOS 应用程序)需要路由 URL 以进行深层链接,这相当于挑选一个 URL,以确定在应用程序中导航用户的位置。
  • 服务器,如 Vapor 应用程序,也需要挑选 URL 请求以确定要服务的页面,但还需要生成有效的 URL 以在网站内链接。

此库为客户端和服务器应用程序提供 URL 路由函数,并以可组合、类型安全的方式执行此操作。

开始

要使用库,首先要从域建模练习开始。您为一个路由枚举建模,该枚举表示要在应用程序中识别的每个 URL,枚举的每个大小写都包含要从 URL 中提取的数据。

For example, if we had screens in our Books application that represent showing all books, showing a particular book, and searching books, we can model this as an enum:

enum AppRoute {
  case books
  case book(id: Int)
  case searchBooks(query: String, count: Int = 10)
}

Notice that we only encode the data we want to extract from the URL in these cases. There are no details of where this data lives in the URL, such as whether it comes from path parameters, query parameters or POST body data.

Those details are determined by the router, which can be constructed with the tools shipped in this library. Its purpose is to transform an incoming URL into the type. For example:AppRoute

import URLRouting

let appRouter = OneOf {
  // GET /books
  Route(.case(AppRoute.books))) {
    Path { "books" }
  }

  // GET /books/:id
  Route(.case(AppRoute.books(id:))) {
    Path { "books"; Digits() }
  }

  // GET /books/search?query=:query&count=:count
  Route(.case(AppRoute.searchBooks(query:count:))) {
    Path { "books"; "search" }
    Query {
      Field("query")
      Field("count", default: 10) { Digits() }
    }
  }
}

This router describes at a high-level how to pick apart the path components, query parameters, and more from a URL in order to transform it into an .AppRoute

Once this router is defined you can use it to implement deep-linking logic in your application. You can implement a single function that accepts a , use the router’s method to transform it into an , and then switch on the route to handle each deep link destination:URLmatchAppRoute

func handleDeepLink(url: URL) throws {
  switch try appRouter.match(url: url) {
  case .books:
    // navigate to books screen

  case let .book(id: id):
    // navigate to book with id

  case let .searchBooks(query: query, count: count):
    // navigate to search screen with query and count
  }
}

This kind of routing is incredibly useful in client side iOS applications, but it can also be used in server-side applications. Even better, it can automatically transform values back into URL’s which is handy for linking to various parts of your website:AppRoute

appRoute.path(for: .searchBooks(query: "Blob Bio"))
// "/books/search?query=Blob%20Bio"

Node.ul(
  books.map { book in
    .li(
      .a(
        .href(appRoute.path(for: .book(id: book.id))),
        book.title
      )
    )
  }
)

<ul>
  <li><a href="/books/1">Blob Autobiography</a></li>
  <li><a href="/books/2">Blobbed around the world</a></li>
  <li><a href="/books/3">Blob's guide to success</a></li>
</ul>

For Vapor bindings to URL Routing, see the Vapor Routing package.

Documentation

The documentation for releases and main are available here:

License

This library is released under the MIT license. See LICENSE for details.

GitHub

点击跳转