blob: 837b39fb78352884fba2d46ec6f70345c958aeb2 [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import Gnostic
extension ServiceRenderer {
func renderServer() -> String {
var code = CodePrinter()
code.print(header)
code.print()
code.print("// Service code")
code.print("import Kitura")
code.print("import KituraNet")
code.print("import Foundation")
code.print("// A server requires an instance of an implementation of this protocol.")
code.print("public protocol Service {")
code.indent()
for serviceMethod in self.methods {
code.print("// " + serviceMethod.description)
code.print("func " + serviceMethod.name + " (" +
protocolParametersDeclaration(serviceMethod) + ") throws " +
protocolReturnDeclaration(serviceMethod))
}
code.outdent()
code.print("}")
code.print("func intValue(_ s:String?) -> Int64 {")
code.indent()
code.print("guard let s = s else {")
code.indent()
code.print("return 0")
code.outdent()
code.print("}")
code.print("guard let value = Int64(s) else {")
code.indent()
code.print("return 0")
code.outdent()
code.print("}")
code.print("return value")
code.outdent()
code.print("}")
code.print("public func server(service : Service) -> Router {")
code.indent()
code.print("// Create a new router")
code.print("let router = Router()")
for serviceMethod in self.methods {
code.print("// " + serviceMethod.description)
code.print("router." + lowercase(serviceMethod.method) + "(\"" + kituraPath(serviceMethod) + "\") { req, res, next in")
code.indent()
if hasParameters(serviceMethod) {
code.print("// instantiate the parameters structure")
code.print("let parameters = " + serviceMethod.parametersTypeName! + "()")
for serviceTypeField in parametersTypeFields(serviceMethod) {
if serviceTypeField.position == "path" {
code.print("parameters." + serviceTypeField.name +
" = intValue(req.parameters[\"" +
serviceTypeField.name + "\"])")
}
}
if serviceMethod.method == "POST" {
code.print("// deserialize request from post data")
code.print("let bodyString = try req.readString() ?? \"\"")
code.print("guard let bodyData = bodyString.data(using:.utf8) else {")
code.indent()
code.print("try res.send(status:.badRequest).end()")
code.print("return")
code.outdent()
code.print("}")
code.print("var jsonObject : Any? = nil")
code.print("do {")
code.indent()
code.print("jsonObject = try JSONSerialization.jsonObject(with:bodyData)")
code.outdent()
code.print("} catch {")
code.indent()
code.print("try res.send(status:.badRequest).end()")
code.print("return")
code.outdent()
code.print("}")
code.print("guard let bodyObject = " + serviceMethod.resultTypeName! + "(jsonObject:jsonObject) else {")
code.print("try res.send(status:.badRequest).end()")
code.indent()
code.print("return")
code.outdent()
code.print("}")
code.print("parameters." + bodyParameterFieldName(serviceMethod) + " = bodyObject")
}
}
if hasParameters(serviceMethod) {
if hasResponses(serviceMethod) {
code.print("let responses = try service." + serviceMethod.name + "(parameters)")
} else {
code.print("try service." + serviceMethod.name + "(parameters)")
}
} else {
if hasResponses(serviceMethod) {
code.print("let responses = try service." + serviceMethod.name + "()")
} else {
code.print("try service." + serviceMethod.name + "()")
}
}
if hasResponses(serviceMethod) {
if responsesHasFieldNamedOK(serviceMethod) {
code.print("if let ok = responses.ok {")
code.indent()
code.print("let jsonObject = ok.jsonObject()")
code.print("let responseData = try JSONSerialization.data(withJSONObject:jsonObject)")
code.print("try res.send(data:responseData).end()")
code.print("return")
code.outdent()
code.print("}")
}
if responsesHasFieldNamedError(serviceMethod) {
code.print("if let errorResponse = responses.error {")
code.indent()
code.print("guard let statusCode = HTTPStatusCode(rawValue:Int(errorResponse.code)) else {")
code.indent()
code.print("try res.send(status:.unknown).end()")
code.print("return")
code.outdent()
code.print("}")
code.print("try res.send(status:statusCode).end()")
code.print("return")
code.outdent()
code.print("}")
}
code.print("try res.send(status:.internalServerError).end()")
} else {
code.print("try res.send(status:.OK).end()")
}
code.outdent()
code.print("}")
}
code.print("return router")
code.outdent()
code.print("}")
code.print("public func initialize(service: Service, port:Int) {")
code.indent()
code.print("// Create a new router")
code.print("let router = server(service:service)")
code.print("// Add an HTTP server and connect it to the router")
code.print("Kitura.addHTTPServer(onPort:port, with: router)")
code.outdent()
code.print("}")
code.print("public func run() {")
code.indent()
code.print("// Start the Kitura runloop (this call never returns)")
code.print("Kitura.run()")
code.outdent()
code.print("}")
return code.content
}
}