|
1 | | -# graphql-rest-router |
| 1 | +# GraphQL Rest Router |
| 2 | +GraphQL Rest Router allows you to expose an internal GraphQL API as a REST API without exposing the entire schema with a simple DSL. |
2 | 3 |
|
3 | | -GraphQL Rest Router allows you to expose an internal GraphQL API as a REST API. |
| 4 | +```js |
| 5 | +import GraphQLRestRouter from 'graphql-rest-router'; |
| 6 | +const clientSchema = fs.require('./clientSchema.gql', 'utf-8'); |
| 7 | + |
| 8 | +const options = { |
| 9 | + defaultCacheTimeInMS: 10 |
| 10 | +}; |
| 11 | + |
| 12 | +const api = new GraphQLRestRouter('http://graphqlurl.com', clientSchema, options); |
| 13 | + |
| 14 | +api.mount('SearchUsers').at('/users'); |
| 15 | +api.mount('GetUserById').at('/users/:id'); |
| 16 | +api.mount('CreateUser').at('/users').as('post').disableCache(); |
| 17 | + |
| 18 | +api.listen(3000, () => { |
| 19 | + console.log('GraphQL Rest Router is listening!'); |
| 20 | +}); |
| 21 | +``` |
4 | 22 |
|
5 | | -- Introduction |
6 | | -- DSL / Documentation |
7 | | -- Example Usage |
8 | | -- Caching |
9 | | -- Custom Routes |
10 | | -- Supported Servers |
| 23 | +__Table of Contents__ |
| 24 | +- [Overview / Introduction](/#) |
| 25 | + - [Internal GraphQL Usage](/#) |
| 26 | + - [External GraphQL Usage](/#) |
| 27 | +- [Documentation](/#) |
| 28 | + - [Getting Started](/#) |
| 29 | + - [Caching](/#) |
| 30 | + - [Swagger / OpenAPI / Documentation](/#) |
| 31 | + - [Custom Routes](/#) |
| 32 | + - [Express.js Usage](/#) |
| 33 | + - [KOA Usage](/#) |
| 34 | + - [Examples](/#) |
| 35 | +- Misc |
| 36 | + - [Typescript](/#) |
| 37 | + - [Contributing](/#) |
| 38 | + - [Support](/#) |
| 39 | + |
| 40 | +# Overview |
| 41 | +GraphQL has gained addoption as a replacement to the conventional REST API and for good reason. Development Time/Time to Market are signficantly shortened when no longer requiring every application to build and maintain its own API. |
| 42 | + |
| 43 | +## Internal GraphQL API |
| 44 | +While GraphQL has gained traction recently, the majority of GraphQL endpoints are used internally and not distributed or endorsed for public use. Because of this, exposing your GraphQL server to the public internet exposes you to risk (e.g. DDOS by allowing unknown users to create their own non-performant queries, accidental exposure of sensitive data, etc). |
| 45 | + |
| 46 | +GraphQL Rest Router attempts to solve these problems by allowing you to leverage GraphQL upstream for all of your data resolution, but exposing predefined queries to the downstream to the public in the form of a cacheable REST url. |
| 47 | + |
| 48 | +Instead of exposing your server by having your web interface interact with api calls directly to `http://yourgraphqlserver.com/?query={ getUserById(1) { firstName, lastName }` that can be altered to `http://yourgraphqlserver.com/?query={ getUserById(1) { firstName, lastName, socialSecurityNumber }`, GraphQL Rest Router allows you to predefine a query and expose it as `http://yourserver/api/users/1` and always execute a safe query with minimal code: |
11 | 49 |
|
12 | | -_Example Usage_ |
13 | 50 | ```js |
14 | 51 | import GraphQLRestRouter from 'graphql-rest-router'; |
15 | | -import * as OpenApi from 'graphql-rest-router/OpenApi'; |
16 | | - |
17 | | -const Schema = ` |
18 | | - query UserById($id: Int!) { |
19 | | - getUserById(id: $id) { |
20 | | - ...UserDetails |
| 52 | +const schema = ` |
| 53 | + query GetUserById($id: ID!) { |
| 54 | + getUserById(1) { |
| 55 | + firstName |
| 56 | + lastName |
21 | 57 | } |
22 | 58 | } |
23 | | -
|
24 | | - query UserByEmail($email: String!, $activeOnly: Boolean, $adminOnly: Boolean) { |
25 | | - getUserByEmail(email: $email, activeOnly: $activeOnly, adminOnly: $adminOnly) { |
26 | | - ...UserDetails |
| 59 | + |
| 60 | + query SearchUsers($page: Int) { |
| 61 | + search(page: $page) { |
| 62 | + id |
| 63 | + firstName |
| 64 | + lastName |
27 | 65 | } |
28 | 66 | } |
| 67 | +`; |
| 68 | + |
| 69 | +const api = new GraphQLRestRouter('http://yourgraphqlserver.com', schema); |
29 | 70 |
|
30 | | - fragment UserDetails on User { |
| 71 | +api.mount('GetUserById').at('/users/:id'); |
| 72 | +api.mount('SearchUsers').at('/users') |
| 73 | + .disableCache(); |
| 74 | + |
| 75 | +api.listen(3000); |
| 76 | +``` |
| 77 | + |
| 78 | +See [Usage with Express](/#) and read [Getting Started](/#) to see all available options. |
| 79 | + |
| 80 | +## External GraphQL API |
| 81 | +When dealing with a publicly exposed GraphQL layer, the main benefit GraphQL Rest Client provides is caching. While implementing individual caches at a content level with dynamic expiration in the GraphQL layer is optimal, actually building these systems out are laborous and aren't always included in MVP products. GraphQL Rest Client allows you to expose a GraphQL query as a REST endpoing with built in cache management that is compatible with all CDNs and cache management layers (e.g. CloudFlare, Akamai, Varnish, etc). |
| 82 | + |
| 83 | +One line of GraphQL Rest Router code allows you to take |
| 84 | +```gql |
| 85 | + |
| 86 | +query UserById($id: ID!) { |
| 87 | + getUserById(id: $id) { |
31 | 88 | id |
32 | 89 | email |
| 90 | + firstName |
| 91 | + lastName |
33 | 92 | } |
34 | | -`; |
| 93 | +} |
| 94 | +``` |
| 95 | +and expose it as `http://www.youapiurl.com/user/:id` |
| 96 | +```js |
| 97 | +api.mount('UserById').at('/user/:id'); |
| 98 | +``` |
35 | 99 |
|
36 | | -const swaggerDoc = new OpenApi.V2({ |
37 | | - title: 'Example API', |
38 | | - version: '1.0.0', |
| 100 | +# Documentation |
| 101 | +GraphQL Rest Router is available via NPM as `graphql-rest-router` (`npm install graphql-rest-router`) |
39 | 102 |
|
40 | | - host: 'http://127.0.0.1', |
41 | | - basePath: '/api', |
42 | | -}); |
| 103 | +## Getting Started |
43 | 104 |
|
44 | | -const openApiDoc = new OpenApi.V3({ |
45 | | - title: 'Example API', |
46 | | - version: '1.0.0', |
| 105 | +### Configuring GraphQL Rest Router |
47 | 106 |
|
48 | | - host: 'http://127.0.0.1', |
49 | | - basePath: '/api', |
50 | | -}); |
| 107 | +### Mounting Queries |
51 | 108 |
|
52 | | -const api = new GraphQLRestRouter(url, Schema, { |
53 | | - cacheEngine: GraphQLRestRouter.InMemoryCache, |
| 109 | +### GET / POST |
54 | 110 |
|
55 | | - defaultCacheTimeInMs: 300, |
| 111 | +## Caching |
| 112 | +GraphQL Rest Router ships with two cache interfaces stock and supports any number of custom or third party caching interfaces as long as they adhere to `ICacheInterface` |
56 | 113 |
|
57 | | - autoDiscoverEndpoints: false, |
| 114 | +### InMemory Cache |
| 115 | +InMemoryCache stores your cached route data on your server in memory. This can be used in development or with low TTLs in order to prevent a [thundering herd](https://en.wikipedia.org/wiki/Thundering_herd_problem) however it is strongly discouraged to use this in production. In Memory caches have the ability to deplete your system's resources and take down your instance of GraphQLRestRouter. |
58 | 116 |
|
59 | | - headers: { |
60 | | - 'x-jwt': 1234, |
61 | | - }, |
62 | | -}); |
| 117 | +```js |
| 118 | +import GraphQLRestRouter from 'graphql-rest-router'; |
| 119 | +import InMemoryCache from 'graphql-rest-router/InMemoryCache'; |
63 | 120 |
|
64 | | -api.mount('UserByEmail', { |
65 | | - path: '/user/:email', |
| 121 | +const api = new GraphQLRestRouter('http://localhost:1227', schema, { |
| 122 | + cacheEngine: new InMemoryCache(), |
| 123 | + |
| 124 | + defaultCacheTimeInMs: 300, |
| 125 | +}); |
66 | 126 |
|
67 | | - method: 'POST', |
| 127 | +api.mount('CreateUser') |
| 128 | + .disableCache(); |
| 129 | + |
| 130 | +api.mount('GetUser', { cacheTimeInMs: 500 }); |
| 131 | +``` |
68 | 132 |
|
69 | | - variables: { |
70 | | - 'adminOnly': true, |
71 | | - }, |
| 133 | +### Redis Cache |
72 | 134 |
|
73 | | - defaultVariables: { |
74 | | - 'activeOnly': true, |
75 | | - }, |
| 135 | +## Swagger / Open API |
| 136 | +As GraphQL Rest Router exposes your API with new routes that aren't covered by GraphQL's internal documentation or introspection queries, GraphQL Rest Router ships with support for Swagger (Open Api V2), Open API (V3) and API Blueprint (planned). When mounting a documentation on GraphQL Rest Router, it will automatically inspect all queries in the schema you provided and run an introspection query on your GraphQL server to dynamically assemble and document the types / endpoints. |
76 | 137 |
|
77 | | - cacheTimeInMs: 0, |
78 | | -}); // creates GET /user/:email?activeOnly=:active |
| 138 | +### Open API (Preferred) |
| 139 | +```js |
| 140 | +const OpenApi = require('graphql-rest-router/OpenApi'); |
79 | 141 |
|
80 | | -api.mount('UserById'); // creates GET /UserById?id=:id |
| 142 | +const documentation = new OpenApi.V3({ |
| 143 | + title: 'My REST API', // REQUIRED! |
| 144 | + version: '1.0.0', // REQUIRED! |
| 145 | + |
| 146 | + host: 'http://localhost:1227', |
| 147 | + basePath: '/api', |
| 148 | +}); |
81 | 149 |
|
82 | | -api.mount('UserById').at('/:id') // creates GET /:id |
| 150 | +const api = new GraphQLRestRouter('http://yourgraphqlendpoint', schema); |
83 | 151 |
|
84 | | -api.mount('UserById').at('/:id').as('POST') |
85 | | - .disableCache() |
86 | | - .transformRequest(headers => { |
87 | | - headers['x-context-jwt'] = '1234'; |
88 | | - }) |
| 152 | +api.mount(documentation).at('/docs/openapi'); |
| 153 | +``` |
89 | 154 |
|
90 | | -api.mount('UserById').withOptions({ |
91 | | - path: '/user/0', |
| 155 | +### Swagger |
| 156 | +```js |
| 157 | +const OpenApi = require('graphql-rest-router/OpenApi'); |
92 | 158 |
|
93 | | - method: 'GET', |
94 | | - variables: { |
95 | | - id: 3 |
96 | | - } |
| 159 | +const swaggerDocumentation = new OpenApi.V2({ |
| 160 | + title: 'My REST API', // REQUIRED! |
| 161 | + version: '1.0.0', // REQUIRED! |
| 162 | + |
| 163 | + host: 'http://localhost:1227', |
| 164 | + basePath: '/api', |
97 | 165 | }); |
98 | 166 |
|
99 | | -api.mount(swaggerDoc).at('/docs/swagger'); |
100 | | -api.mount(openApiDoc).at('/docs/openapi'); |
| 167 | +const api = new GraphQLRestRouter('http://yourgraphqlendpoint', schema); |
101 | 168 |
|
102 | | -// Export Options |
103 | | -module.exports = api.asExpressRouter(); |
| 169 | +api.mount(swaggerDocumentation).at('/docs/swagger'); |
104 | 170 | ``` |
| 171 | + |
| 172 | + |
| 173 | +## Custom Routes |
| 174 | + |
| 175 | +## Usage with Express |
| 176 | + |
| 177 | +## Usage with KOA |
| 178 | + |
| 179 | +## Examples |
0 commit comments