在 Swift 中管理多个 URL 端点的命名空间的简单方法

主要 科德科夫

什么是网址外部 📟

URLRouter 提供了一种在 Swift 中管理多个 URL 端点的简单方法。 它提供了一个简单的界面来管理多个端点,并允许开发人员以单一、统一的方式与它们进行交互。 它还为开发人员提供了一种创建自定义终结点 DSL(域特定语言)和管理每个终结点自己的设置的方法。 此外,它还提供了一种跟踪每个终结点的状态并轻松检测所做的任何更改或更新的方法。

与 Swift evolution 的正则表达式生成器 DSL 类似,URL 字符串文字和更强大的模式结果生成器有助于使 Swift URL 字符串处理快速、简单且没有错误。最终,使用 APIRouter,更改很容易检测到并且对维护很有用。

🤔 在这里提出你想知道的问题。在这里分享想法。 💡

安装 📦

  • 使用 Swift 包管理器

    import PackageDescription
    
    let package = Package(
      name: "SomeApp",
      dependencies: [
        .Package(url: "https://github.com/devyhan/URLRouter", majorVersion: "<LATEST_RELEASES_VERSION>"),
      ]
    )

Configure URLRouter 📝

Implement URLs Namespace

  • To implement URLs namespace we create a new type that will house the domain and behavior of the URLs by conforming to .RouterProtocol

import URLRouter

public enum URLs: RouterProtocol {
  ...
}

HttpHeader declaration

  • Using to declaration.HeaderBuilderhttpHeader

Request {
  ...
  Header {
    Field("HEADERVALUE", forKey: "HEADERKEY")
    Field("HEADERVALUE1", forKey: "HEADERKEY1")
    Field("HEADERVALUE2", forKey: "HEADERKEY2")
    ...
  }
  ...
}
  • Using to declaration.DictionaryhttpHeader

Request {
  ...
  Header([
    "HEADERKEY": "HEADERVALUE",
    "HEADERKEY1": "HEADERVALUE1",
    "HEADERKEY2": "HEADERVALUE2",
    ...
  ])
  ...
}

HttpBody declaration

  • Using to declaration.HeaderBuilderhttpHeader

Request {
  ...
  Body {
    Field("VALUE", forKey: "KEY")
    Field("VALUE1", forKey: "KEY1")
    Field("VALUE2", forKey: "KEY2")
    ...
  }
  ...
}
  • Using to declaration.Dictionary<String, Any>httpHeader

Request {
  ...
  Body([
    "KEY": "VALUE",
    "KEY1": "VALUE1",
    "KEY2": "VALUE2",
    ...
  ])
  ...
}

HttpMethod declaration

  • Using to declaration.Method(_ method:)httpMethod

Request {
  ...
  Method(.get)
  ...
}
  • Using to declaration.static let method:httpMethod

Request {
  ...
  Method.get
  ...
}

URL declaration

  • Using to declaration.URL(_ url:)URL

Request {
  ...
  URL("https://www.baseurl.com/comments?postId=1")
  ...
}
  • Using to declaration and declaration.URLBuilderURLURLComponents

Request {
  ...
  URL {
    Scheme(.https)
    Host("www.baseurl.com")
    Path("comments")
    Query("postId", value: "1")
  }
  ...
}
// https://www.baseurl.com/comments?postId=1
  • Using for override.BaseURL(_ url:)URL

Request {
  BaseURL("https://www.baseurl.com")
  URL {
    Path("comments")
    Query("postId", value: "1")
  }
}
// https://www.baseurl.com/comments?postId=1

Router {
  BaseURL("https://www.baseurl.com")
  Request {
    URL {
      Scheme(.https)
      Host("www.overrideurl.com")
      Path("comments")
      Query("postId", value: "1")
    }
  }
}
// https://www.overrideurl.com/comments?postId=1

URL Scheme declaration

  • Using to declaration.Scheme(_ scheme:)Scheme

Request {
  ...
  URL {
    Scheme(.https)
    ...
  }
  ...
}
  • Using to declaration.static let scheme:Scheme

Request {
  ...
  URL {
    Scheme.https
    ...
  }
  ...
}

URL Query declaration

  • Using to declaration.Dictionary<String, String?>Query

Request {
  ...
  URL {
    Query(
      [
        "first": "firstQuery",
        "second": "secondQuery",
        ...
      ]
    )
  }
  ...
}
  • Using to declaration.Query(_, value:)Query

Request {
  ...
  URL {
    Query("test", value: "query")
    Query("test", value: "query")
    ...
  }
  ...
}
  • Using to declaration.Field(_, forKey:)Query

Request {
  ...
  URL {
    Query {
      Field("firstQuery", forKey: "first")
      Field("secondQuery", forKey: "second")
      ...
    }
    ...
  }
  ...
}

How to configure and use URLRouter in a real world project?

  • Just create URLRouter.swift in your project! Happy hacking! 😁

import URLRouter

enum URLs: RouterProtocol {
  // DOC: https://docs.github.com/ko/rest/repos/repos?apiVersion=2022-11-28#list-organization-repositories
  case listOrganizationRepositories(organizationName: String)
  // DOC: https://docs.github.com/ko/rest/repos/repos?apiVersion=2022-11-28#create-an-organization-repository
  case createAnOrganizationRepository(organizationName: String, repositoryInfo: RepositoryInfo)
  // DOC: https://docs.github.com/ko/rest/search?apiVersion=2022-11-28#search-repositories
  case searchRepositories(query: String)
  case deeplink(path: String = "home")

  struct RepositoryInfo {
    let name: String
    let description: String
    let homePage: String
    let `private`: Bool
    let hasIssues: Bool
    let hasProjects: Bool
    let hasWiki: Bool
  }
  
  var router: Router? {
    Router {
      BaseURL("http://api.github.com")
      switch self {
      case let .listOrganizationRepositories(organizationName):
        Request {
          Method.post
          Header {
            Field("application/vnd.github+json", forKey: "Accept")
            Field("Bearer <YOUR-TOKEN>", forKey: "Authorization")
            Field("2022-11-28", forKey: "X-GitHub-Api-Version")
          }
          URL {
            Path("orgs/\(organizationName)/repos")
          }
        }
      case let .createAnOrganizationRepository(organizationName, repositoryInfo):
        Request {
          Method.post
          Header {
            Field("application/vnd.github+json", forKey: "Accept")
            Field("Bearer <YOUR-TOKEN>", forKey: "Authorization")
            Field("2022-11-28", forKey: "X-GitHub-Api-Version")
          }
          URL {
            Path("orgs/\(organizationName)/repos")
          }
          Body {
            Field(repositoryInfo.name, forKey: "name")
            Field(repositoryInfo.description, forKey: "description")
            Field(repositoryInfo.homePage, forKey: "homepage")
            Field(repositoryInfo.private, forKey: "private")
            Field(repositoryInfo.hasIssues, forKey: "has_issues")
            Field(repositoryInfo.hasProjects, forKey: "has_projects")
            Field(repositoryInfo.hasWiki, forKey: "has_wiki")
          }
        }
      case let .searchRepositories(query):
        Request {
          Method.get
          Header {
            Field("application/vnd.github+json", forKey: "Accept")
            Field("Bearer <YOUR-TOKEN>", forKey: "Authorization")
            Field("2022-11-28", forKey: "X-GitHub-Api-Version")
          }
          URL {
            Path("search/repositories")
            Query("q", value: query)
          }
        }
      case let .deeplink(path):
        URL {
          Scheme.custom("example-deeplink")
          Host("detail")
          Path(path)
          Query {
            Field("postId", forKey: "1")
            Field("createdAt", forKey: "2021-04-27T04:39:54.261Z")
          }
        }
      }
    }
  }
}

// http://api.github.com/orgs/organization/repos
let listOrganizationRepositoriesUrl = URLs.listOrganizationRepositories(organizationName: "organization").router?.urlRequest?.url

// http://api.github.com/search/repositories?q=urlrouter
let searchRepositoriesUrl = URLs.searchRepositories(query: "urlrouter").router?.urlRequest?.url

// example-deeplink://detail/comments?1=postId&2021-04-27T04:39:54.261Z=createdA
let deeplink = URLs.deeplink(path: "detail").router.url
  • Using URLRouter to provide .URLRequest

let repositoryInfo: URLs.RepositoryInfo = .init(name: "Hello-World", description: "This is your first repository", homePage: "https://github.com", private: false, hasIssues: true, hasProjects: true, hasWiki: false)
let request = URLs.createAnOrganizationRepository(organizationName: "SomeOrganization", repositoryInfo: repositoryInfo).router?.urlRequest

URLSession.shared.dataTask(with: request) { data, response, error in
...
  • Using URLRouter to provide deeplink and check to match this .URLURL

class AppDelegate: UIResponder, UIApplicationDelegate {
  ... 
  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
    let detailDeeplink = URLs.deeplink(path: "detail").router.url
    if detailDeeplink == url {
      ...
    }
  ...

License

URLRouter is under MIT license. See the LICENSE file for more info.


Twitter Follow @devyhan93

GitHub

点击跳转