Skip to content

Commit

Permalink
Rename Service to API.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulofaria committed Jun 27, 2020
1 parent 119ce19 commit 78878bd
Show file tree
Hide file tree
Showing 8 changed files with 600 additions and 416 deletions.
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,38 +85,40 @@ extension Message : Keyable {
}
}

struct MessageAPI : Keyable {
struct MessageRoot : Keyable {
enum Keys : String {
case getMessage
}

// The first parameter is the context, you can name it anything you want.
// We're calling it `store` here because the context type is `MessageStore`.
func getMessage(store: MessageStore, arguments: NoArguments) -> Message {
store.getMessage()
}
}
```

#### Defining the service
#### Defining the API

Now we can finally define the Schema using the builder pattern.

```swift
struct MessageService : Service {
let root: MessageAPI
let schema: Schema<MessageAPI, MessageStore>
struct MessageAPI : API {
let root: MessageRoot
let schema: Schema<MessageRoot, MessageStore>

// Notice that `Service` allows dependency injection.
// Notice that `API` allows dependency injection.
// You could pass mocked subtypes of `root` and `context` when testing, for example.
init(root: MessageAPI) throws {
init(root: MessageRoot) throws {
self.root = root

self.schema = try Schema<MessageAPI, MessageStore> { schema in
self.schema = try Schema<MessageRoot, MessageStore> { schema in
schema.type(Message.self) { type in
type.field(.content, at: \.content)
}

schema.query { query in
query.field(.getMessage, at: MessageAPI.getMessage)
query.field(.getMessage, at: MessageRoot.getMessage)
}
}
}
Expand All @@ -125,27 +127,27 @@ struct MessageService : Service {

#### Querying

To query the schema we need to instantiate the service and pass in an EventLoopGroup to feed the execute function alongside the query itself.
To query the schema we need to instantiate the api and pass in an EventLoopGroup to feed the execute function alongside the query itself.

```swift
import NIO

let root = MessageAPI()
let root = MessageRoot()
let context = MessageStore()
let service = try MessageService(root: root)
let api = try MessageAPI(root: root)
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

defer {
try? group.syncShutdownGracefully()
}

let result = try service.execute(
api.execute(
request: "{ getMessage { content } }",
context: context,
on: group
).wait()

print(result)
).whenSuccess { result in
print(result)
}
```

The output will be:
Expand All @@ -154,7 +156,7 @@ The output will be:
{"data":{"getMessage":{"content":"Hello, world!"}}}
```

`Service.execute` returns a `GraphQLResult` which adopts `Encodable`. You can use it with a `JSONEncoder` to send the response back to the client using JSON.
`API.execute` returns a `GraphQLResult` which adopts `Encodable`. You can use it with a `JSONEncoder` to send the response back to the client using JSON.

#### Async resolvers

Expand Down
4 changes: 2 additions & 2 deletions Sources/Graphiti/Service.swift → Sources/Graphiti/API.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import GraphQL
import NIO

public protocol Service {
public protocol API {
associatedtype RootType : Keyable
associatedtype ContextType
var root: RootType { get }
var schema: Schema<RootType, ContextType> { get }
}

extension Service {
extension API {
public func execute(
request: String,
context: ContextType,
Expand Down
131 changes: 85 additions & 46 deletions Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ final class Context {
}
}

struct Root : Keyable {
struct HelloRoot : Keyable {
enum Keys : String {
case hello
case asyncHello
Expand Down Expand Up @@ -109,11 +109,11 @@ struct Root : Keyable {
}
}

struct HelloService : Service {
let root = Root()
struct HelloAPI : API {
let root = HelloRoot()
let context = Context()

let schema = try! Schema<Root, Context> { schema in
let schema = try! Schema<HelloRoot, Context> { schema in
schema.scalar(Float.self)
.description("The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).")

Expand All @@ -131,21 +131,21 @@ struct HelloService : Service {
}

schema.query { query in
query.field(.hello, at: Root.hello)
query.field(.asyncHello, at: Root.asyncHello)
query.field(.float, at: Root.getFloat)
query.field(.id, at: Root.getId)
query.field(.user, at: Root.getUser)
query.field(.hello, at: HelloRoot.hello)
query.field(.asyncHello, at: HelloRoot.asyncHello)
query.field(.float, at: HelloRoot.getFloat)
query.field(.id, at: HelloRoot.getId)
query.field(.user, at: HelloRoot.getUser)
}

schema.mutation { mutation in
mutation.field(.addUser, at: Root.addUser)
mutation.field(.addUser, at: HelloRoot.addUser)
}
}
}

class HelloWorldTests : XCTestCase {
private let service = HelloService()
private let api = HelloAPI()
private var group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

deinit {
Expand All @@ -156,82 +156,106 @@ class HelloWorldTests : XCTestCase {
let query = "{ hello }"
let expected = GraphQLResult(data: ["hello": "world"])

let result = try service.execute(
let expectation = XCTestExpectation()

api.execute(
request: query,
context: service.context,
context: api.context,
on: group
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectation.fulfill()
}

XCTAssertEqual(result, expected)
wait(for: [expectation], timeout: 10)
}

func testHelloAsync() throws {
let query = "{ asyncHello }"
let expected = GraphQLResult(data: ["asyncHello": "world"])

let result = try service.execute(
let expectation = XCTestExpectation()

api.execute(
request: query,
context: service.context,
context: api.context,
on: group
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectation.fulfill()
}

XCTAssertEqual(result, expected)
wait(for: [expectation], timeout: 10)
}

func testBoyhowdy() throws {
let query = "{ boyhowdy }"

let expectedErrors = GraphQLResult(
let expected = GraphQLResult(
errors: [
GraphQLError(
message: "Cannot query field \"boyhowdy\" on type \"Query\".",
locations: [SourceLocation(line: 1, column: 3)]
)
]
)

let expectation = XCTestExpectation()

let result = try service.execute(
api.execute(
request: query,
context: service.context,
context: api.context,
on: group
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectation.fulfill()
}

XCTAssertEqual(result, expectedErrors)
wait(for: [expectation], timeout: 10)
}

func testScalar() throws {
var query: String
var expected = GraphQLResult(data: ["float": 4.0])
var result: GraphQLResult

query = """
query Query($float: Float!) {
float(float: $float)
}
"""

result = try service.execute(
let expectationA = XCTestExpectation()

api.execute(
request: query,
context: service.context,
context: api.context,
on: group,
variables: ["float": 4]
).wait()

XCTAssertEqual(result, expected)
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectationA.fulfill()
}

wait(for: [expectationA], timeout: 10)

query = """
query Query {
float(float: 4)
}
"""

result = try service.execute(
let expectationB = XCTestExpectation()

api.execute(
request: query,
context: service.context,
context: api.context,
on: group
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectationB.fulfill()
}

XCTAssertEqual(result, expected)
wait(for: [expectationB], timeout: 10)

query = """
query Query($id: String!) {
Expand All @@ -241,28 +265,38 @@ class HelloWorldTests : XCTestCase {

expected = GraphQLResult(data: ["id": "85b8d502-8190-40ab-b18f-88edd297d8b6"])

result = try service.execute(
let expectationC = XCTestExpectation()

api.execute(
request: query,
context: service.context,
context: api.context,
on: group,
variables: ["id": "85b8d502-8190-40ab-b18f-88edd297d8b6"]
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectationC.fulfill()
}

XCTAssertEqual(result, expected)
wait(for: [expectationC], timeout: 10)

query = """
query Query {
id(id: "85b8d502-8190-40ab-b18f-88edd297d8b6")
}
"""

result = try service.execute(
let expectationD = XCTestExpectation()

api.execute(
request: query,
context: service.context,
context: api.context,
on: group
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectationD.fulfill()
}

XCTAssertEqual(result, expected)
wait(for: [expectationD], timeout: 10)
}

func testInput() throws {
Expand All @@ -281,14 +315,19 @@ class HelloWorldTests : XCTestCase {
data: ["addUser" : [ "id" : "123", "name" : "bob" ]]
)

let result = try service.execute(
let expectation = XCTestExpectation()

api.execute(
request: mutation,
context: service.context,
context: api.context,
on: group,
variables: variables
).wait()
).whenSuccess { result in
XCTAssertEqual(result, expected)
expectation.fulfill()
}

XCTAssertEqual(result, expected)
wait(for: [expectation], timeout: 10)
}
}

Expand Down
Loading

0 comments on commit 78878bd

Please sign in to comment.