reactive-graphql
Advanced tools
Comparing version 3.0.0 to 3.0.1
@@ -72,3 +72,3 @@ "use strict"; | ||
var fieldResolverSchema = graphql_tools_1.makeExecutableSchema({ | ||
typeDefs: "\n type Plain {\n noFieldResolver: String!\n fieldResolver: String!\n giveMeTheParentFieldResolver: String!\n giveMeTheArgsFieldResolver(arg: String!): String!\n giveMeTheContextFieldResolver: String!\n }\n\n type ObjectValue {\n value: String!\n }\n\n type Item {\n nodeFieldResolver: ObjectValue!\n giveMeTheParentFieldResolver: ObjectValue!\n giveMeTheArgsFieldResolver(arg: String!): ObjectValue!\n giveMeTheContextFieldResolver: ObjectValue!\n }\n\n type Nested {\n firstFieldResolver: Nesting!\n }\n\n type Nesting {\n noFieldResolverValue: String!\n secondFieldResolver: String!\n }\n\n type Query {\n plain: Plain!\n item: Item!\n nested: Nested!\n throwingResolver: String\n }\n ", | ||
typeDefs: "\n type Plain {\n noFieldResolver: String!\n fieldResolver: String!\n giveMeTheParentFieldResolver: String!\n giveMeTheArgsFieldResolver(arg: String!): String!\n giveMeTheContextFieldResolver: String!\n }\n\n type ObjectValue {\n value: String!\n }\n\n type Item {\n nodeFieldResolver: ObjectValue!\n nullableNodeFieldResolver: ObjectValue\n giveMeTheParentFieldResolver: ObjectValue!\n giveMeTheArgsFieldResolver(arg: String!): ObjectValue!\n giveMeTheContextFieldResolver: ObjectValue!\n }\n\n type Nested {\n firstFieldResolver: Nesting!\n }\n\n type Nesting {\n noFieldResolverValue: String!\n secondFieldResolver: String!\n }\n\n type Query {\n plain: Plain!\n item: Item!\n nested: Nested!\n throwingResolver: String\n }\n ", | ||
resolvers: { | ||
@@ -93,2 +93,5 @@ Plain: { | ||
}, | ||
nullableNodeFieldResolver: function () { | ||
return null; | ||
}, | ||
giveMeTheParentFieldResolver: function (parent) { | ||
@@ -217,3 +220,3 @@ return rxjs_1.of({ value: JSON.stringify(parent) }); | ||
}); | ||
itMarbles.only("resolves using root value", function (m) { | ||
itMarbles("resolves using root value", function (m) { | ||
var query = graphql_tag_1.default(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n query {\n launched {\n name\n }\n }\n "], ["\n query {\n launched {\n name\n }\n }\n "]))); | ||
@@ -312,4 +315,18 @@ var expectedData = [{ name: "challenger", firstFlight: 1984 }]; | ||
}); | ||
itMarbles("if nullable field resolver returns null, it resolves null", function (m) { | ||
var query = graphql_tag_1.default(templateObject_13 || (templateObject_13 = __makeTemplateObject(["\n query {\n item {\n nullableNodeFieldResolver {\n value\n }\n }\n }\n "], ["\n query {\n item {\n nullableNodeFieldResolver {\n value\n }\n }\n }\n "]))); | ||
var expected = m.cold("(a|)", { | ||
a: { | ||
data: { | ||
item: { | ||
nullableNodeFieldResolver: null | ||
} | ||
} | ||
} | ||
}); | ||
var result = __1.graphql(fieldResolverSchema, query, null, {}); | ||
m.expect(result.pipe(operators_1.take(1))).toBeObservable(expected); | ||
}); | ||
itMarbles("the field resolvers 1st argument is parent", function (m) { | ||
var query = graphql_tag_1.default(templateObject_13 || (templateObject_13 = __makeTemplateObject(["\n query {\n item {\n giveMeTheParentFieldResolver {\n value\n }\n }\n }\n "], ["\n query {\n item {\n giveMeTheParentFieldResolver {\n value\n }\n }\n }\n "]))); | ||
var query = graphql_tag_1.default(templateObject_14 || (templateObject_14 = __makeTemplateObject(["\n query {\n item {\n giveMeTheParentFieldResolver {\n value\n }\n }\n }\n "], ["\n query {\n item {\n giveMeTheParentFieldResolver {\n value\n }\n }\n }\n "]))); | ||
var expected = m.cold("(a|)", { | ||
@@ -332,3 +349,3 @@ a: { | ||
itMarbles("the field resolvers 2nd argument is arguments", function (m) { | ||
var query = graphql_tag_1.default(templateObject_14 || (templateObject_14 = __makeTemplateObject(["\n query {\n item {\n giveMeTheArgsFieldResolver(arg: \"My passed arg\") {\n value\n }\n }\n }\n "], ["\n query {\n item {\n giveMeTheArgsFieldResolver(arg: \"My passed arg\") {\n value\n }\n }\n }\n "]))); | ||
var query = graphql_tag_1.default(templateObject_15 || (templateObject_15 = __makeTemplateObject(["\n query {\n item {\n giveMeTheArgsFieldResolver(arg: \"My passed arg\") {\n value\n }\n }\n }\n "], ["\n query {\n item {\n giveMeTheArgsFieldResolver(arg: \"My passed arg\") {\n value\n }\n }\n }\n "]))); | ||
var expected = m.cold("(a|)", { | ||
@@ -351,3 +368,3 @@ a: { | ||
itMarbles("the field resolvers 3rd argument is context", function (m) { | ||
var query = graphql_tag_1.default(templateObject_15 || (templateObject_15 = __makeTemplateObject(["\n query {\n item {\n giveMeTheContextFieldResolver {\n value\n }\n }\n }\n "], ["\n query {\n item {\n giveMeTheContextFieldResolver {\n value\n }\n }\n }\n "]))); | ||
var query = graphql_tag_1.default(templateObject_16 || (templateObject_16 = __makeTemplateObject(["\n query {\n item {\n giveMeTheContextFieldResolver {\n value\n }\n }\n }\n "], ["\n query {\n item {\n giveMeTheContextFieldResolver {\n value\n }\n }\n }\n "]))); | ||
var expected = m.cold("(a|)", { | ||
@@ -367,3 +384,3 @@ a: { | ||
itMarbles("nested resolvers pass down the context and parent", function (m) { | ||
var query = graphql_tag_1.default(templateObject_16 || (templateObject_16 = __makeTemplateObject(["\n query {\n nested {\n firstFieldResolver {\n noFieldResolverValue\n secondFieldResolver\n }\n }\n }\n "], ["\n query {\n nested {\n firstFieldResolver {\n noFieldResolverValue\n secondFieldResolver\n }\n }\n }\n "]))); | ||
var query = graphql_tag_1.default(templateObject_17 || (templateObject_17 = __makeTemplateObject(["\n query {\n nested {\n firstFieldResolver {\n noFieldResolverValue\n secondFieldResolver\n }\n }\n }\n "], ["\n query {\n nested {\n firstFieldResolver {\n noFieldResolverValue\n secondFieldResolver\n }\n }\n }\n "]))); | ||
var expected = m.cold("(a|)", { | ||
@@ -386,3 +403,3 @@ a: { | ||
itMarbles("throwing an error results in an error observable", function (m) { | ||
var query = graphql_tag_1.default(templateObject_17 || (templateObject_17 = __makeTemplateObject(["\n query {\n throwingResolver\n }\n "], ["\n query {\n throwingResolver\n }\n "]))); | ||
var query = graphql_tag_1.default(templateObject_18 || (templateObject_18 = __makeTemplateObject(["\n query {\n throwingResolver\n }\n "], ["\n query {\n throwingResolver\n }\n "]))); | ||
var expected = m.cold("#", {}, new Error("reactive-graphql: resolver 'throwingResolver' throws this error: 'Error: my personal error'")); | ||
@@ -393,3 +410,3 @@ var result = __1.graphql(fieldResolverSchema, query, null, {}); | ||
itMarbles("accessing an unknown query field results in an error observable", function (m) { | ||
var query = graphql_tag_1.default(templateObject_18 || (templateObject_18 = __makeTemplateObject(["\n query {\n youDontKnowMe\n }\n "], ["\n query {\n youDontKnowMe\n }\n "]))); | ||
var query = graphql_tag_1.default(templateObject_19 || (templateObject_19 = __makeTemplateObject(["\n query {\n youDontKnowMe\n }\n "], ["\n query {\n youDontKnowMe\n }\n "]))); | ||
var expected = m.cold("#", {}, new Error("reactive-graphql: field 'youDontKnowMe' was not found on type 'Query'. The only fields found in this Object are: plain,item,nested,throwingResolver.")); | ||
@@ -402,3 +419,3 @@ var result = __1.graphql(fieldResolverSchema, query, null, {}); | ||
itMarbles("createShuttle adds a shuttle and return its name", function (m) { | ||
var mutation = graphql_tag_1.default(templateObject_19 || (templateObject_19 = __makeTemplateObject(["\n mutation {\n createShuttle(name: \"RocketShip\") {\n name\n }\n }\n "], ["\n mutation {\n createShuttle(name: \"RocketShip\") {\n name\n }\n }\n "]))); | ||
var mutation = graphql_tag_1.default(templateObject_20 || (templateObject_20 = __makeTemplateObject(["\n mutation {\n createShuttle(name: \"RocketShip\") {\n name\n }\n }\n "], ["\n mutation {\n createShuttle(name: \"RocketShip\") {\n name\n }\n }\n "]))); | ||
var fakeRequest = { name: "RocketShip" }; | ||
@@ -415,3 +432,3 @@ var commandContext = rxjs_1.of(fakeRequest); | ||
itMarbles("createShuttleList adds a shuttle and return all shuttles", function (m) { | ||
var mutation = graphql_tag_1.default(templateObject_20 || (templateObject_20 = __makeTemplateObject(["\n mutation {\n createShuttleList(name: \"RocketShip\") {\n name\n }\n }\n "], ["\n mutation {\n createShuttleList(name: \"RocketShip\") {\n name\n }\n }\n "]))); | ||
var mutation = graphql_tag_1.default(templateObject_21 || (templateObject_21 = __makeTemplateObject(["\n mutation {\n createShuttleList(name: \"RocketShip\") {\n name\n }\n }\n "], ["\n mutation {\n createShuttleList(name: \"RocketShip\") {\n name\n }\n }\n "]))); | ||
var commandContext = rxjs_1.of("a request"); | ||
@@ -435,3 +452,3 @@ var result = __1.graphql(schema, mutation, null, { | ||
itMarbles("accept alias name", function (m) { | ||
var mutation = graphql_tag_1.default(templateObject_21 || (templateObject_21 = __makeTemplateObject(["\n mutation {\n shut: createShuttle(name: $name) {\n name\n }\n }\n "], ["\n mutation {\n shut: createShuttle(name: $name) {\n name\n }\n }\n "]))); | ||
var mutation = graphql_tag_1.default(templateObject_22 || (templateObject_22 = __makeTemplateObject(["\n mutation {\n shut: createShuttle(name: $name) {\n name\n }\n }\n "], ["\n mutation {\n shut: createShuttle(name: $name) {\n name\n }\n }\n "]))); | ||
var commandContext = rxjs_1.of("a resquest"); | ||
@@ -451,3 +468,3 @@ var variables = { | ||
}); | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12, templateObject_13, templateObject_14, templateObject_15, templateObject_16, templateObject_17, templateObject_18, templateObject_19, templateObject_20, templateObject_21; | ||
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12, templateObject_13, templateObject_14, templateObject_15, templateObject_16, templateObject_17, templateObject_18, templateObject_19, templateObject_20, templateObject_21, templateObject_22; | ||
//# sourceMappingURL=graphqlObservable-test.js.map |
@@ -65,8 +65,8 @@ "use strict"; | ||
if (isFieldNode(definition)) { | ||
var field = getField(type, definition); | ||
var field_1 = getField(type, definition); | ||
// Something unexpcected was passed into getField | ||
if (field === null) { | ||
if (field_1 === null) { | ||
return throwObservable("field '" + definition.name.value + "' was not found on type '" + type + "'. " + fieldNotFoundMessageForType(type)); | ||
} | ||
var resolvedObservable = resolveField(field, definition, context, variables, parent); | ||
var resolvedObservable = resolveField(field_1, definition, context, variables, parent); | ||
// Directly return the leaf nodes | ||
@@ -78,3 +78,6 @@ if (definition.selectionSet === undefined) { | ||
if (!emitted) { | ||
return throwObservable("resolver emitted empty value"); | ||
if (graphql_1.isNonNullType(type)) { | ||
return throwObservable("resolver for " + field_1.name + " emitted empty value"); | ||
} | ||
return rxjs_1.of(null); | ||
} | ||
@@ -81,0 +84,0 @@ if (emitted instanceof Array) { |
@@ -12,3 +12,3 @@ { | ||
], | ||
"version": "3.0.0", | ||
"version": "3.0.1", | ||
"license": "Apache-2.0", | ||
@@ -38,3 +38,3 @@ "scripts": { | ||
"rxjs-marbles": "5.0.0", | ||
"semantic-release": "15.12.4", | ||
"semantic-release": "^15.12.4", | ||
"ts-jest": "23.10.5", | ||
@@ -41,0 +41,0 @@ "typescript": "3.2.1" |
108
README.md
# Reactive GraphQL | ||
This project aims to become a complete GraphQL implementation based around [RxJS](https://github.com/ReactiveX/rxjs). | ||
> GraphQL reactive executor | ||
## Usage Example [![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/DanielMSchmidt/reactive-graphql-demo/tree/master/?hidenavigation=1) | ||
[![npm version](https://badge.fury.io/js/reactive-graphql.svg)](https://badge.fury.io/js/reactive-graphql) [![Build Status](https://travis-ci.org/mesosphere/reactive-graphql.svg?branch=master)](https://travis-ci.org/mesosphere/reactive-graphql) | ||
Execute GraphQL queries against reactive resolvers (resolvers that return Observable) to get a reactive results. | ||
_This project aims to become a complete GraphQL implementation based around [RxJS](https://github.com/ReactiveX/rxjs)._ | ||
## Install | ||
``` | ||
$ npm i reactive-graphql --save | ||
``` | ||
## Usage | ||
The usage is very similar to `graphql-js`'s [`graphql`](https://graphql.org/graphql-js/graphql/#graphql) function, except that: | ||
- resolvers can return an Observable | ||
- the returned value is an Observable | ||
```js | ||
import { makeExecutableSchema } from "graphql-tools"; | ||
import gql from "graphql-tag"; | ||
import { timer } from "rxjs"; | ||
import graphql from "reactive-graphql"; | ||
const typeDefs = ` | ||
type Query { | ||
time: Int! | ||
} | ||
`; | ||
const resolvers = { | ||
Query: { | ||
// resolvers can return an Observable | ||
time: () => { | ||
// Observable that emits increasing numbers every 1 second | ||
return timer(1000, 1000); | ||
} | ||
} | ||
}; | ||
const schema = makeExecutableSchema({ | ||
typeDefs, | ||
resolvers | ||
}); | ||
const query = gql` | ||
query { | ||
time | ||
} | ||
`; | ||
const stream = graphql(query, schema); | ||
// stream is an Observable | ||
stream.subscribe(res => console.log(res)); | ||
``` | ||
outputs | ||
``` | ||
{ data: { time: 0 } } | ||
{ data: { time: 1 } } | ||
{ data: { time: 2 } } | ||
{ data: { time: 3 } } | ||
{ data: { time: 4 } } | ||
... | ||
``` | ||
## API | ||
The first argument you pass into `reactive-graphql` is a GraphQL query, either parsed or as string, the second one is an executable schema. You can pass in the root context as an object as a third parameter. The variables can be passed as 4th parameter. | ||
The implementation will always return an Observable. | ||
If any of the resolvers returns an error the implementation will emit the error on the stream. | ||
Otherwise the data will be wrapped in a `{ data }` object, like most implementations handle this. | ||
## Caveats | ||
Unsupported GraphQL features: | ||
- fragments of all kinds | ||
- subscriptions (as everything is treated as a subscription) | ||
## See Also | ||
- [reactive-graphql-react](https://github.com/DanielMSchmidt/reactive-graphql-react) | ||
- [apollo-link-reactive-schema](https://github.com/getstation/apollo-link-reactive-schema) | ||
- [@dcos/data-service](https://github.com/dcos-labs/data-service) | ||
- [graphql-rxjs](https://github.com/DxCx/graphql-rxjs/) | ||
## Advanced usage [![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/DanielMSchmidt/reactive-graphql-demo/tree/master/?hidenavigation=1) | ||
```js | ||
import React from "react"; | ||
@@ -106,18 +196,4 @@ import ReactDOM from "react-dom"; | ||
## Unsupported features | ||
- fragments of all kinds | ||
- subscriptions (as everything is treated as a subscription) | ||
- only one top-level operation is supported | ||
## API | ||
The 1st argument you pass into `reactive-graphql` is an executable schema, the 2nd one a GraphQL query, either parsed or as string. You can pass in the root value as 3rd and the root context as an object as 4th parameter. The variables can be passed as 5th parameter. | ||
The implementation will always return an Observable. | ||
If any of the resolvers returns an error the implementation will emit the error on the stream. | ||
Otherwise the data will be wrapped in a `{ data }` object, like most implementations handle this. | ||
## License | ||
Apache 2.0 |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
139671
1749
199