Skip to content

Commit

Permalink
adds basic support for remote schemas/schema stitching (#952)
Browse files Browse the repository at this point in the history
  • Loading branch information
ecthiender authored and 0x777 committed Nov 23, 2018
1 parent 5b6a386 commit 512ee6f
Show file tree
Hide file tree
Showing 154 changed files with 7,294 additions and 997 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ npm-debug.log
*.DS_Store
.tern-project
test-server-output
.vscode
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<a href="https://twitter.com/intent/follow?screen_name=HasuraHQ"><img src="https://img.shields.io/badge/Follow-HasuraHQ-blue.svg?style=flat&logo=twitter"></a>
<a href="https://eepurl.com/dBUfJ5"><img src="https://img.shields.io/badge/newsletter-subscribe-yellow.svg?style=flat"></a>

Hasura GraphQL Engine is a blazing-fast GraphQL server that gives you **instant, realtime GraphQL APIs over Postgres**, with [**webhook triggers**](event-triggers.md) on database events for asynchronous business logic.
Hasura GraphQL Engine is a blazing-fast GraphQL server that gives you **instant, realtime GraphQL APIs over Postgres**, with [**webhook triggers**](event-triggers.md) on database events, and [**remote schemas**](remote-schemas.md) for business logic.

Hasura helps you build GraphQL apps backed by Postgres or incrementally move to GraphQL for existing applications using Postgres.

Expand All @@ -28,6 +28,7 @@ Read more at [hasura.io](https://hasura.io) and the [docs](https://docs.hasura.i

* **Make powerful queries**: Built-in filtering, pagination, pattern search, bulk insert, update, delete mutations
* **Realtime**: Convert any GraphQL query to a live query by using subscriptions
* **Merge remote schemas**: Access custom GraphQL schemas for business logic via a single GraphQL Engine endpoint. [**Read more**](remote-schemas.md).
* **Trigger webhooks or serverless functions**: On Postgres insert/update/delete events ([read more](event-triggers.md))
* **Works with existing, live databases**: Point it to an existing Postgres database to instantly get a ready-to-use GraphQL API
* **Fine-grained access control**: Dynamic access control that integrates with your auth system (eg: auth0, firebase-auth)
Expand All @@ -47,7 +48,7 @@ Read more at [https://hasura.io](https://hasura.io) and the [docs](https://docs.
- [Architecture](#architecture)
- [Client-side tooling](#client-side-tooling)
- [Add business logic](#add-business-logic)
- [Custom resolvers](#custom-resolvers)
- [Remote schemas](#remote-schemas)
- [Trigger webhooks on database events](#trigger-webhooks-on-database-events)
- [Demos](#demos)
- [Realtime applications](#realtime-applications)
Expand Down Expand Up @@ -87,7 +88,7 @@ guides](https://docs.hasura.io/1.0/graphql/manual/getting-started/index.html) or

The Hasura GraphQL Engine fronts a Postgres database instance and can accept GraphQL requests from your client apps. It can be configured to work with your existing auth system and can handle access control using field-level rules with dynamic variables from your auth system.

You can also place the engine behind a central GraphQL proxy that fronts multiple GraphQL APIs via schema stitching.
You can also merge remote GraphQL schemas and provide a unified GraphQL API.

![Hasura GraphQL Engine architecture](assets/hasura-arch.svg)

Expand All @@ -97,18 +98,22 @@ Hasura works with any GraphQL client. We recommend using [Apollo Client](https:/

## Add business logic

### Custom resolvers
GraphQL Engine provides easy-to-reason, scalable and performant methods for adding custom business logic to your backend:

Add custom resolvers in addition to Hasura GraphQL engine. Ideal for delegating
to HTTP APIs, making direct calls to another data-source or writing business
logic in code - [read more](community/boilerplates/custom-resolvers).
### Remote schemas

Add custom resolvers in a remote schema in addition to Hasura's Postgres-based GraphQL schema. Ideal for use-cases like implementing a payment API, or querying data that is not in your database - [read more](remote-schemas.md).

### Trigger webhooks on database events

Add asynchronous business logic that is triggered based on database events.
Ideal for notifications, data-pipelines from Postgres or asynchronous
processing - [read more](event-triggers.md).

### Derived data or data transformations

Transform data in Postgres or run business logic on it to derive another dataset that can be queried using GraphQL Engine - [read more](https://docs.hasura.io/1.0/graphql/manual/business-logic/index.html).

## Demos

Check out all the example applications in the
Expand Down
2 changes: 1 addition & 1 deletion assets/hasura-arch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/remote-schemas-arch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions cli/commands/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var ravenVersions = []mt.Version{

var testMetadata = map[string][]byte{
"metadata": []byte(`query_templates: []
remote_schemas: []
tables:
- array_relationships: []
delete_permissions: []
Expand All @@ -40,6 +41,7 @@ tables:
update_permissions: []
`),
"empty-metadata": []byte(`query_templates: []
remote_schemas: []
tables: []
`),
}
Expand Down
5 changes: 4 additions & 1 deletion community/boilerplates/custom-resolvers/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# GraphQL Custom Resolver Example

This is a simple example of using a custom resolver with Hasura's GraphQL API.
> **NOTE**: now merge [Remote Schemas](../../../remote-schemas.md) from [GraphQL servers](../graphql-servers) using Hasura
> - Boilerplates for custom GraphQL servers have been moved [here](../graphql-servers). Also, a recently released feature removes the need for an external GraphQL gateway by letting you merge remote schemas in GraphQL Engine itself - [read more](../../../remote-schemas.md) (*Please check caveats for current limitations in the feature*).
> - Once schemas have been merged in GraphQL Engine, Hasura proxies requests to remote GraphQL servers.
> - Adding another layer in front of GraphQL Engine impacts performance by as much as **4X**, due the serialization-deserialization overhead. Using an external GraphQL gateway is recommended only if your use case is blocked on any of the current limitations.
## Motivation

Expand Down
15 changes: 15 additions & 0 deletions community/boilerplates/graphql-servers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# GraphQL Server Boilerplates

Hasura GraphQL Engine can combine schemas from multiple remote GraphQL servers
and expose them at a single endpoint. You can write these GraphQL servers in any
language and Hasura takes care of stitching together the schema from these
servers ([read more](../../../remote-schemas.md)).

This directory contains boilerplates for writing GraphQL servers using various
languages and frameworks.

- [Docs on Remote Schemas](https://docs.hasura.io/1.0/graphql/manual/remote-schemas/index.html)

## Architecture

![Remote schema architecture diagram](../../../assets/remote-schemas-arch.png)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
package-lock.json
11 changes: 11 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-apollo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:8

WORKDIR /server

COPY ./package.json /server/

RUN npm install

COPY . /server/

CMD ["npm", "start"]
57 changes: 57 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-apollo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# GraphQL server using NodeJS and Apollo

A boilerplate Python GraphQL Server using NodeJS and [Apollo Server](https://www.apollographql.com/docs/apollo-server/)

## Deploying

Clone the repo:

```bash
git clone https://github.com/hasura/graphql-engine
cd graphql-engine/community/boilerplates/graphql-servers/nodejs-apollo
```

### Using Zeit Now

Install the [Zeit Now](https://zeit.co/now) CLI:

```bash
npm install -g now
```

Deploy the server:
```bash
now
```

Get the URL and make a sample query:
```bash
curl https://app-name-something.now.sh/graphql \
-H 'Content-Type:application/json' \
-d'{"query":"{ hello }"}'

{"data":{"hello":"Hello World!"}}
```

You can also visit the now url to open GraphiQL.

## Running locally
Running the server locally:

```bash
npm install
npm start
```

Running the server using Docker:

```bash
docker build -t nodejs-apollo-graphql .
docker run -p 4000:4000 nodejs-apollo-graphql
```

GraphQL endpoint will be `http://localhost:4000/graphql`.

**Note**: When GraphQL Engine is running in a Docker container, `localhost` will
point to the containers local interface, not the host's interface. You might
have to use the host's docker host IP or a specific DNS label based on your OS.
22 changes: 22 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-apollo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "nodejs-apollo-gql-server",
"version": "1.0.0",
"description": "A GraphQL server boilerplate written in NodeJS using and Apollo Server",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Hasura",
"license": "MIT",
"dependencies": {
"apollo-server": "^2.2.1",
"graphql": "^14.0.2",
"graphql-tools": "^4.0.3"
},
"devDependencies": {
"esm": "^3.0.84"
},
"scripts": {
"start": "node -r esm server.js"
}
}
50 changes: 50 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-apollo/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const { ApolloServer } = require('apollo-server');
const { makeExecutableSchema } = require('graphql-tools');

const port = process.env.PORT || 3000;

let count = 0;

const typeDefs = `
type Query {
hello: String!
count: Int!
}
type Mutation {
increment_counter: count_mutation_response!
}
type count_mutation_response {
new_count: Int!
}
`;

const resolvers = {
Query: {
hello: () => {
return "Hello World!"
},
count: () => {
return count;
}
},
Mutation: {
increment_counter: () => {
return { new_count: ++count }
}
}
};

const schema = makeExecutableSchema({
typeDefs,
resolvers
});

const server = new ApolloServer({
schema
});

server.listen({ port }).then(({url}) => {
console.log(`GraphQL server running at ${url}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
package-lock.json
11 changes: 11 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-express/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:8

WORKDIR /server

COPY ./package.json /server/

RUN npm install

COPY . /server/

CMD ["npm", "start"]
57 changes: 57 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-express/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# GraphQL server using NodeJS-Express

A boilerplate Python GraphQL Server using NodeJS-Express using the official [graphql-js](https://graphql.github.io/graphql-js/running-an-express-graphql-server/) library.

## Deploying

Clone the repo:

```bash
git clone https://github.com/hasura/graphql-engine
cd graphql-engine/community/boilerplates/graphql-servers/nodejs-express
```

### Using Zeit Now

Install the [Zeit Now](https://zeit.co/now) CLI:

```bash
npm install -g now
```

Deploy the server:
```bash
now
```

Get the URL and make a sample query:
```bash
curl https://app-name-something.now.sh/graphql \
-H 'Content-Type:application/json' \
-d'{"query":"{ hello }"}'

{"data":{"hello":"Hello World!"}}
```

You can also visit the `/graphql` endpoint of the now url to open GraphiQL.

## Running locally
Running the server locally:

```bash
npm install
npm start
```

Running the server using Docker:

```bash
docker build -t nodejs-express-graphql .
docker run -p 4000:4000 nodejs-express-graphql
```

GraphQL endpoint will be `http://localhost:4000/graphql`.

**Note**: When GraphQL Engine is running in a Docker container, `localhost` will
point to the containers local interface, not the host's interface. You might
have to use the host's docker host IP or a specific DNS label based on your OS.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": 1
}
20 changes: 20 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-express/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "nodejs-express-gql-server",
"version": "1.0.0",
"description": "A GraphQL server boilerplate for NodeJS-Express using graphql-js library",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node -r esm server.js"
},
"author": "Hasura",
"license": "MIT",
"dependencies": {
"express": "^4.16.4",
"express-graphql": "^0.7.1",
"graphql": "^14.0.2"
},
"devDependencies": {
"esm": "^3.0.84"
}
}
44 changes: 44 additions & 0 deletions community/boilerplates/graphql-servers/nodejs-express/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');

let count = 0;
const port = process.env.port || 3000;

// Construct a schema, using GraphQL schema language
const schema = buildSchema(`
type Query {
hello: String!
count: Int!
}
type Mutation {
increment_counter: count_mutation_response!
}
type count_mutation_response {
new_count: Int!
}
`);

// The root provides a resolver function for each API endpoint
const root = {
hello: () => {
return 'Hello world!';
},
count: () => {
return count;
},
increment_counter: () => {
return { new_count: ++count }
}
};

var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(port);
console.log(`Running a GraphQL API server at localhost:${port}/graphql`);
Loading

0 comments on commit 512ee6f

Please sign in to comment.