LoginSignup
4
4

More than 5 years have passed since last update.

Linux+Docker上のSwift環境で駅すぱあとWebサービスを使ってみる

Posted at

ヴァル研究所 Advent Calendar 2017 3日目の記事です。
今日は駅すぱあとWebサービスをLinux上のSwiftから扱ってみる話をしようと思います。

LinuxにSwiftをインストールする

お手軽に環境を構築したいので、Linux+Docker上にSwift環境を構築します。
環境はホスト、ゲスト(Dockerコンテナ)共に Ubuntu 16.04.2 LTS を使用しています。

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"

Docker上にLinux環境を作成する

以下の手順でUbuntuのDockerコンテナを起動します。Swiftの動作に必要なパッケージとして clang libpython2.7 libxml2 libcurl3 をインストールしています。 gitSwiftPMを利用したい場合に必要となります。

$ docker images 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              7b9b13f7b9c0        6 months ago        118.3 MB
$
$ docker run -ti --privileged --name swift_env -d 7b9b13f7b9c0 /sbin/init 
712906ddad7b3535eabfae0261eb00476455379fa5f9b81435c18938e388d24a
$ docker exec -ti swift_env bash
root@712906ddad7b:/# apt-get update -y
root@712906ddad7b:/# apt-get install net-tools vim lv curl -y 
root@712906ddad7b:/# apt-get install language-pack-ja-base language-pack-ja
root@712906ddad7b:~# apt-get install clang libpython2.7 libxml2 libcurl3 git

Swiftをインストールする

Download SwiftからLinux版のSwiftバイナリをダウンロードして展開します。

root@712906ddad7b:~# curl -O https://swift.org/builds/swift-4.0.2-release/ubuntu1604/swift-4.0.2-RELEASE/swift-4.0.2-RELEASE-ubuntu16.04.tar.gz
root@712906ddad7b:~# tar zxf swift-4.0.2-RELEASE-ubuntu16.04.tar.gz -C .

上記の例では、カレントディレクトリの直下に swift-4.0.2-RELEASE-ubuntu16.04/usr/... の形で展開されます。今回は /usr 以下ではなく、 /opt/swift-4.0.2 に配置することにします。

root@712906ddad7b:~# [ ! -d /opt ] && mkdir /opt
root@712906ddad7b:~# mv swift-4.0.2-RELEASE-ubuntu16.04 /opt/swift-4.0.2

あとは .bashrc にSwiftのパスとライブラリパスを設定して準備は完了です。

export PATH=$PATH:/opt/swift-4.0.2/usr/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATHBRARY_PATH:/opt/swift-4.0.2/usr/lib

swift コマンドが実行できれば確認完了です。

root@712906ddad7b:~# swift --version
Swift version 4.0.2 (swift-4.0.2-RELEASE)
Target: x86_64-unknown-linux-gnu

Swiftから駅すぱあとWebサービスを呼び出してみる

Swiftから駅すぱあとWebサービスの経路探索を実行してみます。この例では、新宿駅〜高円寺の探索を行っています。

import Foundation

// 駅すぱあとWebサービスのアクセスキーを指定してください。
let accessKey = "<駅すぱあとWebサービスのアクセスキー>"

// 22741 => 新宿, 22671 => 高円寺
let urlStr = "http://api.ekispert.jp/v1/json/search/course/extreme?key=\(accessKey)&answerCount=1&viaList=22741:22671"

let req = URLRequest(url: URL(string: urlStr)!)

let session = URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: req) { (data, response, error) in
    do {
        let object = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<String, Any>

        // ResultSet.Course.Route.{Line,Point[]}を順次取り出します。
        let top = object["ResultSet"] as! Dictionary<String, Any>
        let course = top["Course"] as! Dictionary<String, Any>  
        let route = course["Route"] as! Dictionary<String, Any> 

        // Line要素には、路線名と行先の文字列が入っています。
        let line  = route["Line"]  as! Dictionary<String, Any>

        // Point[].Stationには、出発駅、到着駅の情報が入っています。
        let point = route["Point"] as! Array<Dictionary<String, Any>>

        // Point[]要素からStation要素を取り出します。
        let line_name = line["Name"] as! String
        let from_station = point[0]["Station"] as! Dictionary<String, Any>
        let to_station   = point[1]["Station"] as! Dictionary<String, Any>
        let from_station_name = from_station["Name"] as! String
        let to_station_name   = to_station["Name"] as! String

        // あとは表示するだけです。
        print(" * \(from_station_name)")
        print(" | \(line_name)")
        print(" * \(to_station_name)")

    } catch let e { 
        print(e)
    }   
}
task.resume()

実行結果は以下になります。

root@712906ddad7b:~# swift sample.swift 
 * 新宿
 | JR中央線・高尾行
 * 高円寺

補足:SwiftyJSONでJSONのパースを楽に行いたい...

サンプルプログラムでは、Swiftの標準クラスライブラリのみを用いてJSONのパースを行っていました。
これはだいぶ骨と心が折れる感じなので、SwiftyJSON等のライブラリを使って楽をしたいところです。

Linux環境でSwiftPMを利用してのSwiftyJSONインストールは以下になります。
ただし、私の環境では swift build 時にエラーになってしまいます...ので、以下は作業メモ的な感じです。

root@712906ddad7b:~/sample# swift package init --type=executable
Creating executable package: sample
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/sample/main.swift
Creating Tests/

Package.swift にSwiftyJSONのパッケージを使用するための設定を追加します。ハマり所として、 dependencies[] への設定追加だけでなく、 targets[] 内の dependencies にも dependencies: ["SwiftyJSON"] の記述が必要な点に注意してください。
この記述が抜けていると、 swift build 時に No such module "SwiftyJSON" エラーになります。

root@712906ddad7b:~/sample# diff -ur Package.swift.ORIG Package.swift
--- Package.swift.ORIG  2017-12-03 10:55:58.662163611 +0000
+++ Package.swift       2017-12-03 11:36:03.231307500 +0000
@@ -8,12 +8,13 @@
     dependencies: [
         // Dependencies declare other packages that this package depends on.
         // .package(url: /* package url */, from: "1.0.0"),
+        .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "3.0.0")
     ],
     targets: [
         // Targets are the basic building blocks of a package. A target can define a module or a test suite.
         // Targets can depend on other targets in this package, and on products in packages which this package depends on.
         .target(
             name: "sample",
-            dependencies: []),
+            dependencies: ["SwiftyJSON"]),
     ]
 )

が、先述の通り、今回試した環境では swift build でビルドエラーが発生してしまい、SwiftyJSONは扱えない状態となっています...orz。

root@712906ddad7b:~/sample# swift build 
Compile Swift Module 'SwiftyJSON' (1 sources)
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:67:101: error: use of undeclared type 'NSErrorPointer'
    public init(data: Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer = nil) {
                                                                                                    ^~~~~~~~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:120:23: error: argument labels '(data:)' do not match any available overloads
            .flatMap{ JSON(data: $0) } ?? JSON(NSNull())
                      ^   ~~~~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:120:23: note: overloads for 'JSON' exist with these partially matching parameter lists: (Any), (parseJSON: String), (jsonObject: Any), (array: [JSON]), (dictionary: [String : JSON]), (stringLiteral: StringLiteralType), (extendedGraphemeClusterLiteral: StringLiteralType), (unicodeScalarLiteral: StringLiteralType), (integerLiteral: IntegerLiteralType), (booleanLiteral: BooleanLiteralType), (floatLiteral: FloatLiteralType), (dictionaryLiteral: (String, Any)...), (dictionaryLiteral: [(String, Any)]), (arrayLiteral: Any...), (nilLiteral: ()), (rawValue: Any)
            .flatMap{ JSON(data: $0) } ?? JSON(NSNull())
                      ^
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:1323:20: error: cannot convert value of type '[Any]' to type 'NSArray' in coercion
        return lhs.rawArray as NSArray == rhs.rawArray as NSArray
               ~~~~^~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:1325:20: error: cannot convert value of type '[String : Any]' to type 'NSDictionary' in coercion
        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
               ~~~~^~~~~~~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:1343:20: error: cannot convert value of type '[Any]' to type 'NSArray' in coercion
        return lhs.rawArray as NSArray == rhs.rawArray as NSArray
               ~~~~^~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:1345:20: error: cannot convert value of type '[String : Any]' to type 'NSDictionary' in coercion
        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
               ~~~~^~~~~~~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:1363:20: error: cannot convert value of type '[Any]' to type 'NSArray' in coercion
        return lhs.rawArray as NSArray == rhs.rawArray as NSArray
               ~~~~^~~~~~~~
/root/sample/.build/checkouts/SwiftyJSON.git--6185397035495820793/Source/SwiftyJSON.swift:1365:20: error: cannot convert value of type '[String : Any]' to type 'NSDictionary' in coercion
        return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
               ~~~~^~~~~~~~~~~~~
error: terminated(1): /opt/swift-4.0.2/usr/bin/swift-build-tool -f /root/sample/.build/debug.yaml main

まとめ

Swiftから駅すぱあとWebサービスを呼び出す手順を紹介しました。macOSの環境ではなく、Linux上でSwiftを動作させるという方法でしたが参考になればと思います。

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