Skip to content

Latest commit

 

History

History
189 lines (153 loc) · 5.86 KB

OVERVIEW.md

File metadata and controls

189 lines (153 loc) · 5.86 KB

gRPC for Swift - Public API

This document will provide an overview of the gRPC API for Swift. It follows a standard form used by each language-platform implementation.

Basic Functionality

The following examples use echo.proto to demonstrate basic gRPC operation and generated code.

How is a New Stub Created?

Swift gRPC client and server code is generated by the protoc-gen-swiftgrpc plugin. The plugin is called from protoc and can be invoked for echo.proto like this:

protoc Examples/Echo/echo.proto --proto_path=Examples/Echo --swiftgrpc_out=. 

Simple Request-Response RPC: Client-side RPC

var requestMessage = Echo_EchoRequest(text:message)
print("Sending: " + requestMessage.text)
let responseMessage = try service.get(requestMessage)
print("get received: " + responseMessage.text)

Simple Request-Response RPC: Server Implementation of RPC

// get returns requests as they were received.
func get(request : Echo_EchoRequest) throws -> Echo_EchoResponse {
  return Echo_EchoResponse(text:"Swift echo get: " + request.text)
}

Show how Client does two RPCs sequentially

Show how Client does two RPCs asynchronously

Any code for handling incoming RPC on server that might need to be written

Server Streaming RPC: Client-side code

let requestMessage = Echo_EchoRequest(text:message)
print("Sending: " + requestMessage.text)
let expandCall = try service.expand(requestMessage)
var running = true
while running {
  do {
    let responseMessage = try expandCall.Receive()
    print("Received: \(responseMessage.text)")
  } catch Echo_EchoClientError.endOfStream {
    print("expand closed")
    running = false
  }
}

Server Streaming RPC: Server-side code

// expand splits a request into words and returns each word in a separate message.
func expand(request : Echo_EchoRequest, session : Echo_EchoExpandSession) throws -> Void {
  let parts = request.text.components(separatedBy: " ")
  var i = 0
  for part in parts {
    try session.Send(Echo_EchoResponse(text:"Swift echo expand (\(i)): \(part)"))
    i += 1
    sleep(1)
  }
}

How is a Server Created?

var done = NSCondition()
let echoProvider = EchoProvider()
var echoServer: Echo_EchoServer!
if useSSL {
  print("Starting secure server")
  let certificateURL = URL(fileURLWithPath:"ssl.crt")
  let keyURL = URL(fileURLWithPath:"ssl.key")
  echoServer = Echo_EchoServer(address:"localhost:8443",
                               certificateURL:certificateURL,
                               keyURL:keyURL,
                               provider:echoProvider)
} else {
  print("Starting insecure server")
  echoServer = Echo_EchoServer(address:"localhost:8081",
                               provider:echoProvider)
}
echoServer.start()
// Block to keep the main thread from finishing while the server runs.
// This server never exits. Kill the process to stop it.
done.lock()
done.wait()
done.unlock()

Advanced

RPC canceling on client side

Code to look for and handle cancelled RPC on Server side

Client Streaming RPC: Client-side code

let collectCall = try service.collect()
let parts = message.components(separatedBy:" ")
for part in parts {
  let requestMessage = Echo_EchoRequest(text:part)
  print("Sending: " + part)
  try collectCall.Send(requestMessage)
  sleep(1)
}
let responseMessage = try collectCall.CloseAndReceive()

Client Streaming RPC: Server-side code

// collect collects a sequence of messages and returns them concatenated when the caller closes.
func collect(session : Echo_EchoCollectSession) throws -> Void {
  var parts : [String] = []
  while true {
    do {
      let request = try session.Receive()
      parts.append(request.text)
    } catch Echo_EchoServerError.endOfStream {
      break
    } catch (let error) {
      print("\(error)")
    }
  }
  let response = Echo_EchoResponse(text:"Swift echo collect: " + parts.joined(separator: " "))
  try session.SendAndClose(response)
}

Flow control interactions while sending & receiving messages

Flow control and buffer pool : Control API

Bi Directional Streaming : Client-side code

var done = NSCondition()
let updateCall = try service.update()
DispatchQueue.global().async {
  var running = true
  while running {
    do {
      let responseMessage = try updateCall.Receive()
      print("Received: \(responseMessage.text)")
    } catch Echo_EchoClientError.endOfStream {
      print("update closed")
      done.lock()
      done.signal()
      done.unlock()
      break
    } catch (let error) {
      print("error: \(error)")
    }
  }
}
let parts = message.components(separatedBy:" ")
for part in parts {
  let requestMessage = Echo_EchoRequest(text:part)
  print("Sending: " + requestMessage.text)
  try updateCall.Send(requestMessage)
  sleep(1)
}
try updateCall.CloseSend()
// Wait for the call to complete.
done.lock()
done.wait()
done.unlock()

Bi Directional Streaming : Server-side code

// update streams back messages as they are received in an input stream.
func update(session : Echo_EchoUpdateSession) throws -> Void {
  var count = 0
  while true {
    do {
      let request = try session.Receive()
      count += 1
      try session.Send(Echo_EchoResponse(text:"Swift echo update (\(count)): \(request.text)"))
    } catch Echo_EchoServerError.endOfStream {
      break
    } catch (let error) {
      print("\(error)")
    }
  }
  try session.Close()
}

Any stub deletion/cleanup code needed