LoginSignup
1
0

More than 1 year has passed since last update.

Point Free製のURL-ROUTINGを使ってディープリンクのルーティング書くとめちゃくちゃ便利でした

Posted at

Point Free製のURL-ROUTINGを使ってディープリンクのルーティング書くとめちゃくちゃ便利でした

https://github.com/pointfreeco/swift-url-routing

動機

使用してみて便利だったので記事にします。

DeepLinkで渡っていたURLをどう処理するかを、文字列をゴニョゴニョすることなく、
うまくルーティングすることができたので備忘録として残しておきます。

SwiftでiOSアプリ開発だけでなく、サーバーサイドにも使用できるそうです。

ルートをenumで定義する

ルーティングをenumで定義していきます。

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

URLごとに、どういうPathで渡ってきた場合、
どのcaseで返せばよいかを記述します。
パラメータとして渡される場合、どんな型で渡されるかも記述します。

例えば以下の2つ目の例では、数字が渡ってくることを
Digits()を通じてparseしています。


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() }
    }
  }
}

パラメータとして渡される値をどのようにParseするかは、
https://github.com/pointfreeco/swift-parsing
このPoint Free製のSwift-Parsingを使用しています。

渡ってきたURLをどのように処理するかを書く

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
  }
}

appRouterの関数で

func match(url: URL)

にURLを渡すとenum AppRouteが返さるので、
ルートごとにどのような処理をするか書きます。

Deeplinkの場合は、

ディープリンクの場合で例えば以下のようなURLがあるとき

mydeeplink://foo/bar/3

  Route(.case(AppRoute.fooBar(id:))) {
    Path { "foo"; "bar"; Digits() }
  }

このようなRouterだと機能しません。

/bar/3
しか見ていないので。

つまり、hostを判定する必要があります。

以下、Swift-Parsing https://github.com/pointfreeco/swift-parsing
を拡張してHost名を判定するParseを作りました↓

import Foundation
import URLRouting
import Parsing

struct Host: ParserPrinter {
  @usableFromInline
  let name: String

  @inlinable
  public init(_ name: String) {
    self.name = name
  }

  @inlinable
  public func parse(_ input: inout URLRequestData) throws {
    guard let host = input.host else { throw RoutingError() }
    try self.name.parse(host)
    input.host = nil
  }

  @inlinable
  public func print(_ output: (), into input: inout URLRequestData) {
    input.host = self.name
  }
}

@usableFromInline
struct RoutingError: Error {
  @usableFromInline
  init() {}
}

mydeeplink://foo/bar/3

  Route(.case(AppRoute.fooBar(id:))) {
    Host("foo")
    Path {"bar"; Digits() }
  }

追加したHostを使って上記のように記述すればよいです。

おわり

これのおかげで、文字列でゴニョゴニョする手間を省けるので便利でした!
指定した型に変換して返すことも、Swift Parse https://github.com/pointfreeco/swift-parsing を利用してParserを作れば良いみたいです。

余談

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0