适用于 Vapor 应用的基于文件的路由

金妮 💧

Ginny 是一个 Swift Package 插件,可为 Vapor 应用程序启用基于文件的路由。它的工作原理是在构建时生成代码,像在任何普通 Vapor 应用程序中一样注册路由。

基本用法

Ginny 删除了一些与 Vapor 应用程序中的路由相关的样板文件,同时支持其大部分功能。(有关不支持的功能的列表,请参阅下文。

使用Ginny就像一行更改一样简单:

let app = try Application(.detect())
defer { app.shutdown() }

+ app.registerRoutes()
try app.run()

从现在开始,只要插件正在运行,就会根据您在 Vapor 应用程序目标中组织文件的方式以及其中的内容生成路由。

以下文件夹结构:

pages/
├── api/
│   ├── hello.swift
│   ├── world
│   │   ├── world.index.swift
│   │   ├── foo.swift

结果为以下路线:

/api/hello
/api/world
/api/world/foo

Ginny在目录中查找包含与 OR 匹配的文件,并为您生成路由注册代码的其余部分。/pages.swiftRequestHandlerAsyncRequestHandler

例如,取以下文件:/pages/api/hello.swift

import Foundation
import Ginny
import Vapor

struct Hello: RequestHandler {

  var method: HTTPMethod {
    .GET
  }

  func handle(req: Request) throws -> String {
    "Hello, world!"
  }
}

Each time that your project builds, Ginny finds the inside of and generates the Vapor boilerplate under-the-hood to register your route. You can always see the exact code that Ginny generates by checking your target’s build logs for .RequestHandler/pages/api/hello.swiftRoutes.generated.swift

From here, you can run your server like you would normally and make a request to the corresponding endpoint:

curl -X GET http://localhost:8080/api/hello

Installation

  1. Add Ginny as a dependency in your :Package.swift
.package(url: "https://github.com/gonzalonunez/ginny.git", from: "0.1.1"),
  1. In your Vapor app’s executable, add the library as a dependency and the as a plugin. See the example app for more.GinnyGinnyPlugin

.executableTarget(
  name: "MyApp",
  dependencies: [
    .product(name: "Ginny", package: "ginny"),
    .product(name: "Vapor", package: "vapor"),
   ],
  plugins: [
    .plugin(name: "GinnyPlugin", package: "ginny"),
   ]),

Now, Ginny will run any time that you build your project if any of your API routes have changed.

Gotchas

There are a few subtleties related to how Ginny generates code for you:

  • Normally, in other systems, files named are used to refer to the root of a directory. Unfortunately, this doesn’t work in Swift because you can’t have two files in the same module with the same name. Ginny works around this by dropping any path components that contain , whether that’s a file or a folder. This allows you to prefix your files with anything else you need to disambiguate them. So, is routed to and is routed to . See the example app for more.index.indexindexapi/hello/hello.index.swiftapi/helloapi/hello/world/world.index.swiftapi/hello/world/

  • Ginny is smart enough to support two s in the same file, it will register both of them for you. So, you can declare multiple handlers in the same file with different HTTP methods and get the behavior that you would expect: and , for example.RequestHandlerGET api/helloPOST api/hello

  • Ginny registers routes in alphabetic order according to the file system. You can always inspect in your build logs to see the code that Ginny generates. If you’d like different behavior here, please file a GitHub issue.Routes.generated.swift

Feature parity with Vapor

Ginny supports most of Vapor’s routing features at the moment. Support for missing features can be added if there’s any appetite for them, please file a GitHub issue to get a discussion going!

Supported

  • Route parameters: Vapor’s route parameters are supported with a syntax. For example, a file named ends up getting registered with Vapor as []api/user/[id].swiftapi/user/:id

  • Catchall parameters: Vapor’s catchall parameters are supported with a syntax. For example, a file named ends up getting registered with Vapor as and allows you to later retrieve the catchall. The part does not matter, you can name that whatever you’d like (and you’ll have to if you want to have multiple files in the same module that support catchall parameters because you can’t have two files in the same Swift module with the same name)...api/user/[...slug].swiftapi/user/***slug

Not yet supported

Inspiration

Ginny was inspired by the way Vercel does routing. I’m a big fan of all things Vercel and Next.js, I highly recommend taking a look.

Why Ginny?

Ginny Strazisar developed the first true IP router in 1975.

GitHub

点击跳转