Scalaã¨Swiftã¯ãç°ãªãã¨ã³ã·ã¹ãã ã«å±ããããã°ã©ãã³ã°è¨èªã§ãããããããã®å¼·ã¿ãæ´»ããã¦é£æºããããã¨ã§ãããã©ã¼ãã³ã¹ãéçºå¹çãåä¸ããããã¨ãã§ãã¾ããScalaã¯é¢æ°åããã°ã©ãã³ã°ã¨ãªãã¸ã§ã¯ãæåããã°ã©ãã³ã°ãçµã¿åãããJVMä¸ã®è¨èªã§ãç¹ã«å¤§è¦æ¨¡ãªãã¼ã¿å¦çããµã¼ãã¼ãµã¤ãã§ã®å©ç¨ãå¤ãã§ãã䏿¹ãSwiftã¯Apple製åã®ã¢ããªã±ã¼ã·ã§ã³éçºã«ä½¿ãããè¨èªã§ãiOSãmacOSã®ã¢ããªã±ã¼ã·ã§ã³ã§ä¸»ã«å©ç¨ããã¦ãã¾ãã
Scalaã¨Swiftã飿ºãããã·ããªãªã¨ãã¦ã¯ãScalaã§ãµã¼ãã¼ãµã¤ãã®å¦çãè¡ããSwiftã§ããã³ãã¨ã³ãã®UIãã¢ãã¤ã«ã¢ããªãå®è£ ããã±ã¼ã¹ãä¸è¬çã§ãããã®è¨äºã§ã¯ãããã2ã¤ã®è¨èªãã©ã®ããã«é£æºãããããå ·ä½çãªä¾ãéãã¦èª¬æãã¾ãã
飿ºã®ã·ããªãª
Scalaã¨Swiftã®é£æºãå¿ è¦ã«ãªãã±ã¼ã¹ã¯æ¬¡ã®éãã§ãã
Scalaã§ããã¯ã¨ã³ãããSwiftã§ããã³ãã¨ã³ããæ§ç¯ããå ´å
Scalaã使ã£ã¦ããã¯ã¨ã³ãAPIãå®è£ ããSwiftã使ã£ã¦ã¢ãã¤ã«ã¢ããªã®ããã³ãã¨ã³ãã使ããå ´åãAPIéä¿¡ãéãã¦é£æºãå¯è½ã§ããSwiftã§ãã¤ãã£ãiOSã¢ããªãéçºãã¤ã¤ãScalaã§ãã¸ãã¹ãã¸ãã¯ãå®è£ ããå ´å
ãã¸ãã¹ãã¸ãã¯ããã¼ã¿å¦çãScalaã§æ¸ãããããSwiftããå¼ã³åºããã¨ãã§ããã°ãããã©ã¼ãã³ã¹ãæé©åã§ãã¾ããã¯ãã¹ãã©ãããã©ã¼ã ã®éçºç°å¢ã§ç°ãªãå½¹å²ãæãããå ´å
ã¢ãã¤ã«ã¨ãµã¼ãã¼éã®éä¿¡ãã·ã³ãã«ã«ä¿ã¡ã¤ã¤ãåãã©ãããã©ã¼ã ã®æé©åãããã³ã¼ãã飿ºããããã¨ãã§ãã¾ãã
飿ºæ¹æ³
Scalaã¨Swiftã飿ºãããæ¹æ³ã¯å¤§ããåãã¦ä»¥ä¸ã®2ã¤ãããã¾ãã
Web APIã使ã£ã飿º
Scalaå´ã§Web APIãå®è£ ããSwiftå´ãããã®APIãå¼ã³åºãæ¹æ³ãRESTful APIãgRPCãªã©ãéãã¦ãSwiftã¢ããªããScalaã®ããã¯ã¨ã³ãã«ã¢ã¯ã»ã¹ããå½¢ã§ããã·ã¹ãã éã§å ±éã®ãããã³ã«ã使ã
両è ãåãéä¿¡ãããã³ã«ããã¼ã¿å½¢å¼ï¼ä¾ãã°JSONãProtobufï¼ã使ã£ã¦ãã¼ã¿ãããåããããã¨ã§é£æºãã¾ãã
以ä¸ã§ã¯ãScalaã§APIã使ãããããSwiftããå¼ã³åºãå ·ä½çãªä¾ã示ãã¾ãã
Scalaã§ããã¯ã¨ã³ãAPIãæ§ç¯
ã¾ããScalaå´ã§ç°¡åãªREST APIã使ãããããSwiftã¢ããªããå¼ã³åºããããã«ãã¾ããScalaã§ã¯ãAkka HTTP
ã¨ãããã¬ã¼ã ã¯ã¼ã¯ã使ã£ã¦ã·ã³ãã«ãªAPIãµã¼ãã¼ãç«ã¦ããã¨ãã§ãã¾ãã
Akka HTTPã§ã®APIå®è£ (Scala)
以ä¸ã®Scalaã³ã¼ãã¯ãAkka HTTPã使ã£ã¦åä½ããã·ã³ãã«ãªAPIãµã¼ãã¼ã§ãããã®ãµã¼ãã¼ã¯ã/greet
ã¨ããã¨ã³ããã¤ã³ãã«ã¢ã¯ã»ã¹ãããã¨ã§ãã¯ã©ã¤ã¢ã³ãã«"Hello from Scala!"ã¨ããã¡ãã»ã¼ã¸ãè¿ãã¾ãã
import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.server.Directives._ import akka.stream.ActorMaterializer object ScalaApiServer extends App { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() val route = path("greet") { get { complete("Hello from Scala!") } } Http().bindAndHandle(route, "localhost", 8080) println("Scala API server is running at http://localhost:8080/greet") }
ãã®ã³ã¼ããå®è¡ããã¨ãScala APIãµã¼ãã¼ã8080ãã¼ãã§åä½ãã¾ããããã§ãSwiftã¢ããªããHTTPãªã¯ã¨ã¹ããéã£ã¦ãScala APIãå¼ã³åºãæºåãæ´ãã¾ããã
Swiftã§Scala APIãå¼ã³åºã
次ã«ãSwiftãããã®Scala APIãå¼ã³åºãæ¹æ³ãè¦ã¦ããã¾ããããSwiftã§ã¯ãURLSession
ã使ã£ã¦HTTPãªã¯ã¨ã¹ããéä¿¡ããAPIãããã¼ã¿ãåå¾ãããã¨ãã§ãã¾ãã
Swiftã§ã®APIå¼ã³åºã
以ä¸ã®ã³ã¼ãã¯ãSwiftã§Scalaã®APIãå¼ã³åºãã¦ã¬ã¹ãã³ã¹ãåå¾ããä¾ã§ãã
import Foundation let url = URL(string: "http://localhost:8080/greet")! let task = URLSession.shared.dataTask(with: url) { (data, response, error) in if let error = error { print("Error: \(error)") return } if let data = data, let responseString = String(data: data, encoding: .utf8) { print("Response from Scala API: \(responseString)") } } task.resume()
ãã®Swiftã³ã¼ãã§ã¯ãURLSession
ã使ã£ã¦Scalaã®APIã«ã¢ã¯ã»ã¹ãã¦ãã¾ããæåããã¨ãScalaãµã¼ãã¼ããã®ã¬ã¹ãã³ã¹ãã¿ã¼ããã«ã«è¡¨ç¤ºããã¾ãã
å®è¡çµæ:
Response from Scala API: Hello from Scala!
gRPCã使ã£ã飿º
ããä¸ã¤ã®æ¹æ³ã¨ãã¦ãgRPCã使ã£ã¦Scalaã¨Swiftã飿ºããããã¨ãã§ãã¾ããgRPCã¯Googleãéçºããé«éãªRPCãã¬ã¼ã ã¯ã¼ã¯ã§ãã¹ãã¼ãé§åã®éçºãå¯è½ã§ããgRPCã使ç¨ãããã¨ã§ãå¹ççã«2ã¤ã®ç°ãªãè¨èªéã§ã®éä¿¡ãè¡ããã¨ãã§ãã¾ãã
gRPCã®ã»ããã¢ãã
Scalaå´ã§gRPCãµã¼ãã¼ãã»ããã¢ãã
Scalaã§gRPCãµã¼ãã¼ãå®è£ ãããµã¼ãã¹ãå®ç¾©ãã¾ããprotoc
ï¼Protocol Buffers Compilerï¼ã使ã£ã¦ã¹ãã¼ããå®ç¾©ããSwiftã¨Scalaéã§å ±éã®ã¤ã³ã¿ã¼ãã§ã¼ã¹ãæããã¾ããSwiftå´ã§gRPCã¯ã©ã¤ã¢ã³ããã»ããã¢ãã
Swiftã§gRPCã¯ã©ã¤ã¢ã³ããçæããScalaã®gRPCãµã¼ãã¼ã¨éä¿¡ãè¡ãã¾ããSwiftã®gRPCã©ã¤ãã©ãªã使ããã¨ã§ãã¹ãã¼ãã«åºã¥ããåå®å ¨ãªéä¿¡ãå¯è½ã§ãã
ãã¼ã¿å½¢å¼ã®å ±éå: JSONãProtocol Buffers
Scalaã¨Swiftéã§ãã¼ã¿ãããåãããéã«ãå ±éã®ãã¼ã¿å½¢å¼ã使ç¨ããå¿ è¦ãããã¾ããæãä¸è¬çãªã®ã¯JSONã§ãããããå¹ççãªéä¿¡ãå®ç¾ããããã«Protocol Buffersï¼Protobufï¼ã使ããã¨ãå¯è½ã§ãã
JSONã§ã®é£æº
Scalaå´ã§JSONãè¿ãAPIã使ããSwiftã§ãã®JSONãè§£æããæµãã§ããScalaã§ã¯ãspray-json
ãªã©ã使ã£ã¦ç°¡åã«JSONãçæã§ãã¾ãã
import spray.json._ case class User(name: String, age: Int) object UserJsonProtocol extends DefaultJsonProtocol { implicit val userFormat = jsonFormat2(User) } import UserJsonProtocol._ val route = path("user") { get { val user = User("Alice", 25) complete(user.toJson.toString) } }
Swiftå´ã§ã¯ãJSONDecoder
ã使ã£ã¦ãã®JSONãè§£æãã¾ãã
import Foundation let url = URL(string: "http://localhost:8080/user")! let task = URLSession.shared.dataTask(with: url) { (data, response, error) in if let data = data { do { let user = try JSONDecoder().decode(User.self, from: data) print("User name: \(user.name), age: \(user.age)") } catch { print("Failed to decode JSON: \(error)") } } } task.resume() struct User: Codable { let name: String let age: Int }
å®è¡çµæ:
User name: Alice, age: 25
ã¾ã¨ã
Scalaã¨Swiftã¯ããããããå¼·åãªç¹å¾´ãæã¤ããã°ã©ãã³ã°è¨èªã§ãç°ãªããã©ãããã©ã¼ã éã§ã®é£æºãéãã¦ãå¼·åãªã¢ããªã±ã¼ã·ã§ã³ãéçºãããã¨ãå¯è½ã§ããScalaã§ãµã¼ãã¼ãµã¤ãã®å¦çãæ å½ããSwiftã§ããã³ãã¨ã³ããã¢ãã¤ã«ã¢ããªãæ§ç¯ããéã«ãAPIãgRPCãªã©ã使ã£ã¦å¹ççã«ãã¼ã¿ãããåãã§ãã¾ãã
ä»åã¯ãScalaã§ä½æããAPIãSwiftããå¼ã³åºãæ¹æ³ãä¸å¿ã«ç´¹ä»ãã¾ããããããã¸ã§ã¯ãã®è¦æ¨¡ãè¦ä»¶ã«å¿
ãã¦ãæ§ã ãªé£æºæ¹æ³ãçµã¿åããã¦ä½¿ããã¨ãã§ããã§ãããã