introduce v1/graphql (fix #1368) (#2064)

Changes compared to `/v1alpha1/graphql`

* Changed all graphql responses in **/v1/graphql** endpoint to be 200. All graphql clients expect responses to be HTTP 200. Non-200 responses are considered transport layer errors. 

* Errors in http and websocket layer are now consistent and have similar structure.
This commit is contained in:
Anon Ray
2019-05-10 06:05:11 +00:00
committed by Vamshi Surabhi
parent d942266c59
commit a21f6cd648
283 changed files with 803 additions and 484 deletions

View File

@@ -56,7 +56,7 @@ Further reading: [Firebase SDK for Cloud Functions](https://firebase.google.com/
const idToken = await getIdToken()
const axios = axiosBase.create({
baseURL: 'https://YOURHASURADOMAIN/v1alpha1/graphql',
baseURL: 'https://YOURHASURADOMAIN/v1/graphql',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + idToken

View File

@@ -31,7 +31,7 @@ exports.handler = (event, context, callback) => {
body: "success"
};
const qv = {noteId: request.event.data.old.id, data: request.event.data.old.note};
fetch(hgeEndpoint + '/v1alpha1/graphql', {
fetch(hgeEndpoint + '/v1/graphql', {
method: 'POST',
body: JSON.stringify({query: query, variables: qv}),
headers: {'Content-Type': 'application/json', 'x-hasura-admin-secret': adminSecret},

View File

@@ -21,7 +21,7 @@ mutation updateNoteRevision ($noteId: Int!, $data: String!) {
exports.handler = async (event) => {
try {
const qv = { noteId: event.body.event.data.old.id, data: event.body.event.data.old.note };
const result = await fetch(hgeEndpoint + '/v1alpha1/graphql', {
const result = await fetch(hgeEndpoint + '/v1/graphql', {
method: 'POST',
body: JSON.stringify({ query: query, variables: qv }),
headers: { 'Content-Type': 'application/json', 'x-hasura-access-key': accessKey },

View File

@@ -4,7 +4,7 @@ from botocore.vendored import requests
ADMIN_SECRET = os.environ['ADMIN_SECRET']
HGE_ENDPOINT = os.environ['HGE_ENDPOINT']
HGE_URL = HGE_ENDPOINT + '/v1alpha1/graphql'
HGE_URL = HGE_ENDPOINT + '/v1/graphql'
HEADERS = {
'Content-Type': 'application/json',

View File

@@ -25,7 +25,7 @@ module.exports = function (context, req) {
const qv = {noteId: data.old.id, data: data.old.note};
const hgeResponse = query({
query: MUTATION_NOTE_REVISION,
endpoint: HGE_ENDPOINT + '/v1alpha1/graphql',
endpoint: HGE_ENDPOINT + '/v1/graphql',
variables: qv,
headers: {
'x-hasura-admin-secret': ADMIN_SECRET

View File

@@ -41,7 +41,7 @@ Edit `.env.yaml` and add values for the following as shown:
```yaml
# .env.yaml
GMAPS_API_KEY: '[GMAPS_API_KEY]'
HASURA_GRAPHQL_ENGINE_URL: 'http://[HGE_IP]/v1alpha1/graphql'
HASURA_GRAPHQL_ENGINE_URL: 'http://[HGE_IP]/v1/graphql'
```
```bash

View File

@@ -41,7 +41,7 @@ Edit `.env.yaml` and add values for the following as shown:
```yaml
# .env.yaml
GMAPS_API_KEY: '[GMAPS_API_KEY]'
HASURA_GRAPHQL_ENGINE_URL: 'http://[HGE_IP]/v1alpha1/graphql'
HASURA_GRAPHQL_ENGINE_URL: 'http://[HGE_IP]/v1/graphql'
```
```bash

View File

@@ -37,7 +37,7 @@ Execute `now` in this directory with an env var required for the code to execute
a mutation:
```bash
now -e HGE_ENDPOINT=https://my-app.herokuapp.com/v1alpha1/graphql
now -e HGE_ENDPOINT=https://my-app.herokuapp.com/v1/graphql
```
`HGE_ENDPOINT` is the Hasura GraphQL Engine endpoint.

View File

@@ -37,7 +37,7 @@ Execute `now` in this directory with an env var required for the code to execute
a mutation:
```bash
now -e HGE_ENDPOINT=https://my-app.herokuapp.com/v1alpha1/graphql
now -e HGE_ENDPOINT=https://my-app.herokuapp.com/v1/graphql
```
`HGE_ENDPOINT` is the Hasura GraphQL Engine endpoint.

View File

@@ -13,7 +13,7 @@ We use [dotenv](https://github.com/motdotla/dotenv) for setting environment vari
```
PORT=3000
NODE_ENV=development
GRAPHQL_ENDPOINT=http://localhost:8090/v1alpha1/graphql
GRAPHQL_ENDPOINT=http://localhost:8090/v1/graphql
HEADER_STRING='{}'
VARIABLE_STRING='{}'
QUERY_STRING='query { test_table { id } }'

View File

@@ -53,7 +53,7 @@ dataApisContent.push({
},
request: {
method: 'POST',
url: getUrl('/v1alpha1/graphql'),
url: getUrl('/v1/graphql'),
headers: defaultHeader,
bodyType: 'graphql',
params: JSON.stringify({}, null, 4),

View File

@@ -25,8 +25,8 @@ data:
without /graphql/console
}
proxy /graphql/v1alpha1/graphql hasura/v1alpha1/graphql {
without /graphql/v1alpha1/graphql
proxy /graphql/v1/graphql hasura/v1/graphql {
without /graphql/v1/graphql
websocket
}
@@ -44,7 +44,7 @@ data:
proxy /graphql/react react-apollo
proxy /graphql hasura/v1alpha1/graphql {
proxy /graphql hasura/v1/graphql {
without /graphql
websocket
}

View File

@@ -1,9 +1,9 @@
This app uses environment variables.
```
REACT_APP_GRAPHQL_URL=https://hasura-todo-test.herokuapp.com/v1alpha1/graphql
REACT_APP_GRAPHQL_URL=https://hasura-todo-test.herokuapp.com/v1/graphql
REACT_APP_REALTIME_GRAPHQL_URL=wss://hasura-todo-test.herokuapp.com/v1alpha1/graphql
REACT_APP_REALTIME_GRAPHQL_URL=wss://hasura-todo-test.herokuapp.com/v1/graphql
REACT_APP_CALLBACK_URL=http://localhost:3000/callback

View File

@@ -1,9 +1,9 @@
This app uses environment variables.
```
REACT_APP_GRAPHQL_URL=https://hasura-todo-test.herokuapp.com/v1alpha1/graphql
REACT_APP_GRAPHQL_URL=https://hasura-todo-test.herokuapp.com/v1/graphql
REACT_APP_REALTIME_GRAPHQL_URL=wss://hasura-todo-test.herokuapp.com/v1alpha1/graphql
REACT_APP_REALTIME_GRAPHQL_URL=wss://hasura-todo-test.herokuapp.com/v1/graphql
REACT_APP_CALLBACK_URL=http://localhost:3000/callback

View File

@@ -83,7 +83,7 @@ export const query = graphql`
- Run the app:
```bash
HASURA_GRAPHQL_URL=https://my-app.herokuapp.com/v1alpha1/graphql npm run develop
HASURA_GRAPHQL_URL=https://my-app.herokuapp.com/v1/graphql npm run develop
```
- Test the app
Visit [http://localhost:8000](http://localhost:8000) to view the app

View File

@@ -45,7 +45,7 @@ Ensure to configure Hasura GraphQL Engine with the environment variables `HASURA
```js
const httpLink = new HttpLink({
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql', // Server URL (must be absolute)
uri: 'https://myapp.herokuapp.com/v1/graphql', // Server URL (must be absolute)
credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
})
```

View File

@@ -29,7 +29,7 @@ function create (initialState) {
return forward(operation);
})
const httpLink = new HttpLink({
uri: 'https://my-app.herokuapp.com/v1alpha1/graphql', // Server URL (must be absolute)
uri: 'https://my-app.herokuapp.com/v1/graphql', // Server URL (must be absolute)
credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
})
return new ApolloClient({

View File

@@ -47,7 +47,7 @@
connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
link: new HttpLink({
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql', // Server URL (must be absolute)
uri: 'https://myapp.herokuapp.com/v1/graphql', // Server URL (must be absolute)
credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
}),
cache: new InMemoryCache().restore(initialState || {})

View File

@@ -13,7 +13,7 @@ function create (initialState) {
connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
link: new HttpLink({
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql', // Server URL (must be absolute)
uri: 'https://myapp.herokuapp.com/v1/graphql', // Server URL (must be absolute)
credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
}),
cache: new InMemoryCache().restore(initialState || {})

View File

@@ -48,7 +48,7 @@ Boilerplate to get started with Nextjs, Hasura GraphQL engine as CMS and postgre
// can also be a function that accepts a `context` object (SSR only) and returns a config
const config = {
link: new HttpLink({
uri: 'https://my-app.herokuapp.com/v1alpha1/graphql', // <- Configure GraphQL Server URL (must be absolute)
uri: 'https://my-app.herokuapp.com/v1/graphql', // <- Configure GraphQL Server URL (must be absolute)
})
}

View File

@@ -3,7 +3,7 @@ import { HttpLink } from 'apollo-link-http'
const config = {
link: new HttpLink({
uri: 'https://hasura-graphql-2.herokuapp.com/v1alpha1/graphql', // <- Configure GraphQL Server URL (must be absolute)
uri: 'https://hasura-graphql-2.herokuapp.com/v1/graphql', // <- Configure GraphQL Server URL (must be absolute)
})
}

View File

@@ -49,11 +49,11 @@ columns: `id`, `title`, `content`, `author_id` (foreign key to `author` table's
export default function(context){
return {
httpLinkOptions: {
uri: 'https://my-app.herokuapp.com/v1alpha1/graphql',
uri: 'https://my-app.herokuapp.com/v1/graphql',
credentials: 'same-origin'
},
cache: new InMemoryCache(),
wsEndpoint: 'ws://my-app.herokuapp.com/v1alpha1/graphql',
wsEndpoint: 'ws://my-app.herokuapp.com/v1/graphql',
}
}
```

View File

@@ -2,10 +2,10 @@ import { InMemoryCache } from "apollo-cache-inmemory";
export default function(context){
return {
httpLinkOptions: {
uri: 'http://localhost:8080/v1alpha1/graphql',
uri: 'http://localhost:8080/v1/graphql',
credentials: 'same-origin'
},
cache: new InMemoryCache(),
wsEndpoint: 'ws://localhost:8080/v1alpha1/graphql',
wsEndpoint: 'ws://localhost:8080/v1/graphql',
}
}

View File

@@ -51,7 +51,7 @@ import VueApollo from 'vue-apollo'
import fetch from 'node-fetch'
import { createHttpLink } from 'apollo-link-http'
const httpLink = createHttpLink({ uri: 'https://myapp.herokuapp.com/v1alpha1/graphql', fetch: fetch })
const httpLink = createHttpLink({ uri: 'https://myapp.herokuapp.com/v1/graphql', fetch: fetch })
// Create the apollo client
const apolloClient = new ApolloClient({

View File

@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo'
import fetch from 'node-fetch'
import { createHttpLink } from 'apollo-link-http'
const httpLink = createHttpLink({ uri: 'https://myapp.herokuapp.com/v1alpha1/graphql', fetch: fetch })
const httpLink = createHttpLink({ uri: 'https://myapp.herokuapp.com/v1/graphql', fetch: fetch })
// Create the apollo client
const apolloClient = new ApolloClient({

View File

@@ -1,9 +1,9 @@
This app uses environment variables.
```
REACT_APP_GRAPHQL_URL=https://hasura-todo-test.herokuapp.com/v1alpha1/graphql
REACT_APP_GRAPHQL_URL=https://hasura-todo-test.herokuapp.com/v1/graphql
REACT_APP_REALTIME_GRAPHQL_URL=wss://hasura-todo-test.herokuapp.com/v1alpha1/graphql
REACT_APP_REALTIME_GRAPHQL_URL=wss://hasura-todo-test.herokuapp.com/v1/graphql
REACT_APP_CALLBACK_URL=http://localhost:3000/callback

View File

@@ -6,10 +6,10 @@ const scheme = proto => {
export const GRAPHQL_URL = `${scheme(
"http"
)}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
)}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
export const REALTIME_GRAPHQL_URL = `${scheme(
"ws"
)}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
)}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
export const authClientId = "Fl-hdc6xdYIkok9ynbcL6zoUZPAIdOZN";
export const authDomain = "hasura-react-apollo-todo.auth0.com";
export const callbackUrl = `${scheme(

View File

@@ -56,7 +56,7 @@ columns: `id`, `title`, `content`, `author_id` (foreign key to `author` table's
const client = new ApolloClient({
link: new HttpLink({
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql',
uri: 'https://myapp.herokuapp.com/v1/graphql',
fetch
}),
cache: new InMemoryCache(),

View File

@@ -5,7 +5,7 @@ import fetch from 'node-fetch'
const client = new ApolloClient({
link: new HttpLink({
uri: 'http://localhost:8080/v1alpha1/graphql', // replace this with your own Hasura GraphQL Endpoint
uri: 'http://localhost:8080/v1/graphql', // replace this with your own Hasura GraphQL Endpoint
fetch
}),
cache: new InMemoryCache(),

View File

@@ -12,11 +12,11 @@ import { split } from "apollo-link";
import VueApollo from "vue-apollo";
// Http endpoint
const httpLink = new HttpLink({
uri: "https://realtime-chat.demo.hasura.app/v1alpha1/graphql"
uri: "https://realtime-chat.demo.hasura.app/v1/graphql"
})
const wsLink = new WebSocketLink({
uri: "wss://realtime-chat.demo.hasura.app/v1alpha1/graphql",
uri: "wss://realtime-chat.demo.hasura.app/v1/graphql",
options: {
reconnect: true
}

View File

@@ -14,8 +14,8 @@ const scheme = (proto) => {
return window.location.protocol === 'https:' ? `${proto}s` : proto;
}
const HASURA_GRAPHQL_ENGINE_HOSTNAME = window.location.host;
export const GRAPHQL_ENDPOINT = `${scheme('http')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
export const WEBSOCKET_ENDPOINT = `${scheme('ws')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
export const GRAPHQL_ENDPOINT = `${scheme('http')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
export const WEBSOCKET_ENDPOINT = `${scheme('ws')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
// Make WebSocketLink with appropriate url
const mkWsLink = (uri) => {

View File

@@ -38,7 +38,7 @@ hosted on GitHub pages and the Postgres+GraphQL Engine is running on Postgres.
- Edit `HASURA_GRAPHQL_URL` in `src/constants.js` and set it to the
Heroku app URL:
```js
export const HASURA_GRAPHQL_URL = 'realtime-backend2.herokuapp.com/v1alpha1/graphql';
export const HASURA_GRAPHQL_URL = 'realtime-backend2.herokuapp.com/v1/graphql';
```
- Run the app (go to the root of the repo):
```bash

View File

@@ -8,8 +8,8 @@ const scheme = (proto) => {
return window.location.protocol === 'https:' ? `${proto}s` : proto;
}
const wsurl = `${scheme('ws')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
const httpurl = `${scheme('http')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
const wsurl = `${scheme('ws')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
const httpurl = `${scheme('http')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
const HASURA_LOCATION = {
lat: 12.93958,

View File

@@ -15,8 +15,8 @@ const scheme = (proto) => {
return window.location.protocol === 'https:' ? `${proto}s` : proto;
}
const wsurl = `${scheme('ws')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
const httpurl = `${scheme('http')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1alpha1/graphql`;
const wsurl = `${scheme('ws')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
const httpurl = `${scheme('http')}://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`;
const wsLink = new WebSocketLink({
uri: wsurl,

View File

@@ -85,7 +85,7 @@ Use the `TRIGGER_URL` from previous step.
### Step 5: Add configuration variables
Edit `index.js` and add the following values:
- `HGE_URL`, your GraphQL Engine URL (ending with `v1alpha1/graphql`)
- `HGE_URL`, your GraphQL Engine URL (ending with `v1/graphql`)
- `APP_ID`, the algolia application id
- `SEARCH_KEY`, algolia search api key created in Step 2

View File

@@ -5,7 +5,7 @@ if (!("Notification" in window)) {
const screens = ['#loading-screen', '#input-screen', '#search-screen'];
// Replace with HGE_URL
const HGE_URL = '/v1alpha1/graphql';
const HGE_URL = '/v1/graphql';
function showScreen(name) {
for (screen of screens) {
@@ -69,7 +69,7 @@ $( document ).ready(function() {
}
});
$('#hge-console-link').attr('href', HGE_URL.replace('v1alpha1/graphql', 'console'));
$('#hge-console-link').attr('href', HGE_URL.replace('v1/graphql', 'console'));
showScreen('#input-screen');
$('#book-title').focus();

View File

@@ -7,7 +7,7 @@ const messaging = firebase.messaging();
const screens = ['#loading-screen', '#permission-screen', '#input-screen', '#waiting-screen'];
// Replace with HGE_URL
const HGE_URL = '/v1alpha1/graphql';
const HGE_URL = '/v1/graphql';
function showScreen(name) {
for (screen of screens) {
@@ -149,5 +149,5 @@ $( document ).ready(function() {
}
});
$('#hge-console-link').attr('href', HGE_URL.replace('v1alpha1/graphql', 'console'));
$('#hge-console-link').attr('href', HGE_URL.replace('v1/graphql', 'console'));
});

View File

@@ -66,7 +66,7 @@ Save changes.
Setup values in `todo-app/src/constants.js`:
1. Auth0 domain
2. GraphQL engine deployed URL, e.g: `https://hasura-todo-auth0-jwt.herokuapp.com/v1alpha1/graphql`
2. GraphQL engine deployed URL, e.g: `https://hasura-todo-auth0-jwt.herokuapp.com/v1/graphql`
3. Auth0 application's client id
## Create the initial tables

View File

@@ -1,3 +1,3 @@
export const GRAPHQL_URL = 'https://hasura-todo-auth0-jwt.herokuapp.com/v1alpha1/graphql';
export const GRAPHQL_URL = 'https://hasura-todo-auth0-jwt.herokuapp.com/v1/graphql';
export const authClientId = "xxxxxxxxxxxxxxxxxxxxx";
export const authDomain = "<your-auth0-domain>.auth0.com";

View File

@@ -97,7 +97,7 @@ function (user, context, callback) {
request.post({
headers: {'content-type' : 'application/json', 'x-hasura-admin-secret': '<your-admin-secret>'},
url: 'http://myapp.herokuapp.com/v1alpha1/graphql',
url: 'http://myapp.herokuapp.com/v1/graphql',
body: `{\"query\":\"mutation($userId: String!, $nickname: String) {\\n insert_users(\\n objects: [{ auth0_id: $userId, name: $nickname }]\\n on_conflict: {\\n constraint: users_pkey\\n update_columns: [last_seen, name]\\n }\\n ) {\\n affected_rows\\n }\\n }\",\"variables\":{\"userId\":\"${userId}\",\"nickname\":\"${nickname}\"}}`
}, function(error, response, body){
console.log(body);

View File

@@ -11,7 +11,7 @@ Vue.use(VueApollo)
const AUTH_TOKEN = 'apollo-token'
// Http endpoint
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:8080/v1alpha1/graphql'
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:8080/v1/graphql'
// Files URL root
export const filesRoot = process.env.VUE_APP_FILES_ROOT || httpEndpoint.substr(0, httpEndpoint.indexOf('/graphql'))
@@ -23,7 +23,7 @@ const defaultOptions = {
httpEndpoint,
// You can use `wss` for secure connection (recommended in production)
// Use `null` to disable subscriptions
wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:8080/v1alpha1/graphql',
wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:8080/v1/graphql',
// LocalStorage token
tokenName: AUTH_TOKEN,
// Enable Automatic Query persisting with Apollo Engine

View File

@@ -40,7 +40,7 @@ import { InMemoryCache } from 'apollo-cache-inmemory'
const httpLink = new HttpLink({
// You should use an absolute URL here
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql'
uri: 'https://myapp.herokuapp.com/v1/graphql'
})
// Create the apollo client

View File

@@ -6,7 +6,7 @@ import { InMemoryCache } from 'apollo-cache-inmemory'
const httpLink = new HttpLink({
// You should use an absolute URL here
uri: 'https://myapp.herokuapp.com/v1alpha1/graphql'
uri: 'https://myapp.herokuapp.com/v1/graphql'
})
// Create the apollo client

View File

@@ -94,7 +94,7 @@ A sample CURL command using the above token would be:
```bash
curl -X POST \
http://localhost:8081/v1alpha1/graphql \
http://localhost:8081/v1/graphql \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmFtZSI6InRlc3QxMjMiLCJpYXQiOjE1NDAzNzY4MTUuODUzLCJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsiZWRpdG9yIiwidXNlciIsIm1vZCJdLCJ4LWhhc3VyYS11c2VyLWlkIjoiMSIsIngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1yb2xlIjoidXNlciJ9fQ.w9uj0FtesZOFUnwYT2KOWHr6IKWsDRuOC9G2GakBgMI' \
-H 'Content-Type: application/json' \
-d '{ "query": "{ table { column } }" }'

View File

@@ -1,7 +1,7 @@
module.exports = {
"schema": [
{
"http://localhost:8080/v1alpha1/graphql": {
"http://localhost:8080/v1/graphql": {
"headers": {
"x-hasura-admin-secret": ""
}

View File

@@ -2,7 +2,7 @@
"name":"whatsapp-clone",
"version": 1,
"env": {
"REACT_APP_SERVER_URL": "https://whatsapp-clone-hasura.herokuapp.com/v1alpha1/graphql",
"REACT_APP_SERVER_URL": "https://whatsapp-clone-hasura.herokuapp.com/v1/graphql",
"REACT_APP_AUTH_URL": "https://warm-hamlet-82072.herokuapp.com"
},
"public": true,

View File

@@ -110,7 +110,7 @@ const insertData = async (insertOrder, sampleData, tables, url, headers, callbac
return query(
{
query: mutation,
endpoint: `${url}/v1alpha1/graphql`,
endpoint: `${url}/v1/graphql`,
variables,
headers,
}

View File

@@ -20,7 +20,7 @@ query {
const verifyDataImport = () => {
query({
query: complexQuery,
endpoint: `${process.env.TEST_HGE_URL}/v1alpha1/graphql`,
endpoint: `${process.env.TEST_HGE_URL}/v1/graphql`,
headers: {'x-hasura-admin-secret': process.env.TEST_X_HASURA_ADMIN_SECRET},
}).then(response => {
if (

View File

@@ -25,7 +25,7 @@ query {
const verifyDataImport = () => {
query({
query: complexQuery,
endpoint: `${process.env.TEST_HGE_URL}/v1alpha1/graphql`,
endpoint: `${process.env.TEST_HGE_URL}/v1/graphql`,
headers: {'x-hasura-admin-secret': process.env.TEST_X_HASURA_ADMIN_SECRET},
}).then(response => {
if (

View File

@@ -28,7 +28,7 @@ query {
const verifyDataImport = () => {
query({
query: complexQuery,
endpoint: `${process.env.TEST_HGE_URL}/v1alpha1/graphql`,
endpoint: `${process.env.TEST_HGE_URL}/v1/graphql`,
headers: {'x-hasura-admin-secret': process.env.TEST_X_HASURA_ADMIN_SECRET},
}).then(response => {
if (

View File

@@ -21,7 +21,7 @@ query {
const verifyDataImport = () => {
query({
query: complexQuery,
endpoint: `${process.env.TEST_HGE_URL}/v1alpha1/graphql`,
endpoint: `${process.env.TEST_HGE_URL}/v1/graphql`,
headers: {'x-hasura-admin-secret': process.env.TEST_X_HASURA_ADMIN_SECRET},
}).then(response => {
if (

View File

@@ -13,7 +13,7 @@ We use [dotenv](https://github.com/motdotla/dotenv) for setting environment vari
```
PORT=3000
NODE_ENV=development
GRAPHQL_ENDPOINT=http://localhost:8090/v1alpha1/graphql
GRAPHQL_ENDPOINT=http://localhost:8090/v1/graphql
HEADER_STRING='{}'
VARIABLE_STRING='{}'
QUERY_STRING='query { test_table { id } }'

View File

@@ -43,7 +43,7 @@ dataApisContent.push({
},
request: {
method: 'POST',
url: getUrl('/v1alpha1/graphql'),
url: getUrl('/v1/graphql'),
headers: defaultHeader,
bodyType: 'graphql',
params: JSON.stringify({}, null, 4),

View File

@@ -8,7 +8,7 @@ The app directory has the React app that is already set up with a backend.
## Migrations (Hasura migrations)
The hasura directory contains the migrations for the Hasura GraphQL Engine backend that is setup at https://graphql2chartjs.hasura.app and has a GraphQL endpoint https://graphqlchartjs.hasura.app/v1alpha1/graphql
The hasura directory contains the migrations for the Hasura GraphQL Engine backend that is setup at https://graphql2chartjs.hasura.app and has a GraphQL endpoint https://graphqlchartjs.hasura.app/v1/graphql
## Scripts

View File

@@ -8,7 +8,7 @@ import { WebSocketLink } from 'apollo-link-ws';
import { InMemoryCache } from 'apollo-cache-inmemory';
const link = new WebSocketLink({
uri: 'wss://graphql2chartjs.hasura.app/v1alpha1/graphql',
uri: 'wss://graphql2chartjs.hasura.app/v1/graphql',
options: {
reconnect: true
}

View File

@@ -39,7 +39,7 @@ setInterval(changeMajor, 5000);
// Update stock prices
const updatePrices = () => {
fetch(
'https://graphql2chartjs.hasura.app/v1alpha1/graphql',
'https://graphql2chartjs.hasura.app/v1/graphql',
{
method: 'POST',
body: JSON.stringify({

View File

@@ -2,7 +2,7 @@ const fetch = require('node-fetch');
const db = async () => {
const response = await fetch(
'https://bazookaand.herokuapp.com/v1alpha1/graphql',
'https://bazookaand.herokuapp.com/v1/graphql',
{
method: 'POST',
headers: {

View File

@@ -69,7 +69,7 @@ const insertData = async (insertOrder, sampleData, tables, url, headers) => {
try {
const response = await query({
query: mutation,
endpoint: `${url}/v1alpha1/graphql`,
endpoint: `${url}/v1/graphql`,
variables,
headers,
});

View File

@@ -78,7 +78,7 @@ const verifyDataImport = () => {
let resp = null;
return query({
query: complexQuery,
endpoint: `${process.env.TEST_HGE_URL}/v1alpha1/graphql`,
endpoint: `${process.env.TEST_HGE_URL}/v1/graphql`,
headers: {'x-hasura-admin-secret': process.env.TEST_X_HASURA_ADMIN_SECRET},
}).then(response => {
resp = response;

View File

@@ -39,7 +39,7 @@ CURRENT_ENV = os.getenv("ENV") if os.getenv("ENV") else "development"
BASE_DOMAIN = os.getenv("BASE_DOMAIN", "development")
# GraphiQL defaults
GRAPHIQL_DEFAULT_ENDPOINT = "http://localhost:8080/v1alpha1/graphql"
GRAPHIQL_DEFAULT_ENDPOINT = "http://localhost:8080/v1/graphql"
# Get from env if set
if os.getenv("GRAPHIQL_DEFAULT_ENDPOINT"):
GRAPHIQL_DEFAULT_ENDPOINT = os.getenv("GRAPHIQL_DEFAULT_ENDPOINT")

View File

@@ -11,7 +11,14 @@ All GraphQL requests for queries, subscriptions and mutations are made to the Gr
Endpoint
--------
All requests are ``POST`` requests to the ``/v1alpha1/graphql`` endpoint.
All requests are ``POST`` requests to ``/v1/graphql`` (or ``/v1alpha1/graphql``) endpoint.
.. note::
``/v1/graphql`` endpoint returns HTTP 200 status codes for all responses.
This is a **breaking** change from ``/v1alpha1/graphql`` behaviour, where
request errors and internal errors were responded with 4xx and 5xx status
codes.
Request types
-------------

View File

@@ -12,7 +12,9 @@ Available APIs
+-----------------+----------------------------------------+------------------+
| API | Endpoint | Access |
+=================+========================================+==================+
| GraphQL | :ref:`/v1alpha1/graphql <graphql_api>` | Permission rules |
| GraphQL | :ref:`/v1/graphql <graphql_api>` | Permission rules |
+-----------------+----------------------------------------+------------------+
| Legacy GraphQL | :ref:`/v1alpha1/graphql <graphql_api>` | Permission rules |
+-----------------+----------------------------------------+------------------+
| Schema/Metadata | :ref:`/v1/query <schema_metadata_api>` | Admin only |
+-----------------+----------------------------------------+------------------+

View File

@@ -99,7 +99,7 @@ request.
.. code-block:: http
POST /v1alpha1/graphql HTTP/1.1
POST /v1/graphql HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWI...
X-Hasura-Role: editor

View File

@@ -18,7 +18,7 @@ GraphQL engine container:
$ docker logs cdfbc6b94c70
{"timestamp":"2018-10-09T11:20:32.054+0000", "level":"info", "type":"http-log", "detail":{"status":200, "query_hash":"01640c6dd131826cff44308111ed40d7fbd1cbed", "http_version":"HTTP/1.1", "query_execution_time":3.0177627e-2, "request_id":null, "url":"/v1alpha1/graphql", "user":{"x-hasura-role":"admin"}, "ip":"127.0.0.1", "response_size":209329, "method":"POST", "detail":null}}
{"timestamp":"2018-10-09T11:20:32.054+0000", "level":"info", "type":"http-log", "detail":{"status":200, "query_hash":"01640c6dd131826cff44308111ed40d7fbd1cbed", "http_version":"HTTP/1.1", "query_execution_time":3.0177627e-2, "request_id":null, "url":"/v1/graphql", "user":{"x-hasura-role":"admin"}, "ip":"127.0.0.1", "response_size":209329, "method":"POST", "detail":null}}
...

View File

@@ -13,7 +13,7 @@ of Hasura GraphQL engine deployed on Heroku:
$ heroku logs --app <hasura-graphql-engine-app-name>
2018-10-09T11:18:21.306000+00:00 app[web.1]: {"timestamp":"2018-10-09T11:18:21.305+0000", "level":"info", "type":"http-log", "detail":{"status":200, "query_hash":"48c74f902b53a886f9ddc1b7dd12a4a6020d70c3", "http_version":"HTTP/1.1", "query_execution_time":9.477913e-3, "request_id":"b7bb6fb3-97b3-4c6f-a54a-1e0f71a190e9", "url":"/v1alpha1/graphql", "user":{"x-hasura-role":"admin"}, "ip":"171.61.77.16", "response_size":15290, "method":"POST", "detail":null}}
2018-10-09T11:18:21.306000+00:00 app[web.1]: {"timestamp":"2018-10-09T11:18:21.305+0000", "level":"info", "type":"http-log", "detail":{"status":200, "query_hash":"48c74f902b53a886f9ddc1b7dd12a4a6020d70c3", "http_version":"HTTP/1.1", "query_execution_time":9.477913e-3, "request_id":"b7bb6fb3-97b3-4c6f-a54a-1e0f71a190e9", "url":"/v1/graphql", "user":{"x-hasura-role":"admin"}, "ip":"171.61.77.16", "response_size":15290, "method":"POST", "detail":null}}
...
See https://devcenter.heroku.com/articles/logging for more details on logging in Heroku.

View File

@@ -13,7 +13,7 @@ service, i.e. ``hasura``:
$ kubectl logs -f svc/hasura
{"timestamp":"2018-10-09T11:20:32.054+0000", "level":"info", "type":"http-log", "detail":{"status":200, "query_hash":"01640c6dd131826cff44308111ed40d7fbd1cbed", "http_version":"HTTP/1.1", "query_execution_time":3.0177627e-2, "request_id":null, "url":"/v1alpha1/graphql", "user":{"x-hasura-role":"admin"}, "ip":"127.0.0.1", "response_size":209329, "method":"POST", "detail":null}}
{"timestamp":"2018-10-09T11:20:32.054+0000", "level":"info", "type":"http-log", "detail":{"status":200, "query_hash":"01640c6dd131826cff44308111ed40d7fbd1cbed", "http_version":"HTTP/1.1", "query_execution_time":3.0177627e-2, "request_id":null, "url":"/v1/graphql", "user":{"x-hasura-role":"admin"}, "ip":"127.0.0.1", "response_size":209329, "method":"POST", "detail":null}}
...

View File

@@ -96,7 +96,7 @@ Our AWS Lambda code looks like this:
body: "success"
};
const qv = {noteId: request.data.old.id, data: request.data.old.note};
fetch(hgeEndpoint + '/v1alpha1/graphql', {
fetch(hgeEndpoint + '/v1/graphql', {
method: 'POST',
body: JSON.stringify({query: query, variables: qv}),
headers: {'Content-Type': 'application/json', 'x-hasura-admin-secret': adminSecret},

View File

@@ -31,7 +31,7 @@ Create a file called `apollo.config.js` in the root of your project and add the
client: {
service: {
name: "your-service-name",
url: "http://localhost:8080/v1alpha1/graphql",
url: "http://localhost:8080/v1/graphql",
headers: {
"x-hasura-admin-secret": "<your-admin-secret>"
}
@@ -41,7 +41,7 @@ Create a file called `apollo.config.js` in the root of your project and add the
Notes:
- Replace ``http://localhost:8080/v1alpha1/graphql`` with your GraphQL Endpoint
- Replace ``http://localhost:8080/v1/graphql`` with your GraphQL Endpoint
- You can also add custom headers in the headers object if you wish to emulate the schema for some specific roles or tokens.
For advanced configuration, check out the `docs for the plugin <https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo>`_.

View File

@@ -46,7 +46,7 @@ The GraphQL Endpoint will be:
.. code-block:: bash
http://<your_droplet_ip>/v1alpha1/graphql
http://<your_droplet_ip>/v1/graphql
A Postgres database is also provisioned on the Droplet. Using the console, you

View File

@@ -38,12 +38,12 @@ below these imports initialise your client to fetch subscriptions along with que
.. code-block:: js
const httpLink = new HttpLink({
uri: "https://<your-app>/v1alpha1/graphql",
uri: "http://<your-app>/v1/graphql", // use https for secure endpoint
});
// Create a WebSocket link:
const wsLink = new WebSocketLink({
uri: "ws://<your-app>/v1alpha1/graphql",
uri: "ws://<your-app>/v1/graphql", // use wss for a secure endpoint
options: {
reconnect: true
}

View File

@@ -43,7 +43,7 @@ Execute the following command. For the endpoint referred here, let's say you've
deployed the GraphQL engine on Heroku, then this endpoint is:
``https://my-graphql.herokuapp.com``. In case you've deployed this using Docker,
the URL might be ``http://xx.xx.xx.xx:8080``. This endpoint should not contain
the ``v1alpha1/graphql`` API path. It should just be the hostname and any
the ``v1/graphql`` API path. It should just be the hostname and any
sub-path if it is configured that way.
.. code-block:: bash

View File

@@ -44,7 +44,7 @@ Execute the following command. For the endpoint referred here, let's say you've
deployed the GraphQL engine on Heroku, then this endpoint is:
``https://my-graphql.herokuapp.com``. In case you've deployed this using Docker,
the URL might be ``http://xx.xx.xx.xx:8080``. This endpoint should not contain
the ``v1alpha1/graphql`` API path. It should just be the hostname and any
the ``v1/graphql`` API path. It should just be the hostname and any
sub-path if it is configured that way.
.. code-block:: bash

View File

@@ -108,7 +108,7 @@ Step 3: Make queries to the remote server from Hasura
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Now you can head to the ``GraphiQL`` tab and make queries to your remote server from Hasura.
You can query your remote server by making requests to the Hasura GraphQL endpoint (``/v1alpha1/graphql``).
You can query your remote server by making requests to the Hasura GraphQL endpoint (``/v1/graphql``).
Points to remember
------------------

View File

@@ -20,12 +20,12 @@ GraphQL schema:
.. code-block:: bash
# If the GraphQL engine is running at https://my-graphql-engine.com/v1alpha1/graphql,
# If the GraphQL engine is running at https://my-graphql-engine.com/v1/graphql,
# without an admin secret
gq https://my-graphql-engine.com/v1alpha1/graphql --introspect > schema.graphql
gq https://my-graphql-engine.com/v1/graphql --introspect > schema.graphql
# If Hasura GraphQL Engine is running with an admin secret
gq https://my-graphql-engine.com/v1alpha1/graphql -H 'X-Hasura-Admin-Secret: adminsecretkey' --introspect > schema.graphql
gq https://my-graphql-engine.com/v1/graphql -H 'X-Hasura-Admin-Secret: adminsecretkey' --introspect > schema.graphql
By default, it downloads the schema in ``.graphql`` format. If you want it in JSON format, you can use an additional
flag ``--format json``:
@@ -33,7 +33,7 @@ flag ``--format json``:
.. code-block:: bash
# Getting the schema in .json format
gq https://my-graphql-engine.com/v1alpha1/graphql --introspect --format json > schema.json
gq https://my-graphql-engine.com/v1/graphql --introspect --format json > schema.json
Using **Apollo CLI**
--------------------
@@ -44,12 +44,12 @@ Run ``npm install -g apollo`` to install the Apollo CLI. You can then run the fo
.. code-block:: bash
# If the GraphQL engine is running at https://my-graphql-engine.com/v1alpha1/graphql,
# If the GraphQL engine is running at https://my-graphql-engine.com/v1/graphql,
# without an admin secret
apollo schema:download --endpoint https://my-graphql-engine.com/v1alpha1/graphql
apollo schema:download --endpoint https://my-graphql-engine.com/v1/graphql
# If Hasura GraphQL Engine is running with an admin secret
apollo schema:download --endpoint https://my-graphql-engine.com/v1alpha1/graphql --header 'X-Hasura-Admin-Secret: adminsecretkey'
apollo schema:download --endpoint https://my-graphql-engine.com/v1/graphql --header 'X-Hasura-Admin-Secret: adminsecretkey'
Note that ``apollo schema:download`` is an alias of the command `apollo service:download <https://github.com/apollographql/apollo-tooling#apollo-servicedownload-output>`__.

View File

@@ -15,7 +15,7 @@ This Docker Compose setup runs [Hasura GraphQL Engine](https://github.com/hasura
- Edit `docker-compose.yaml` and change `HASURA_GRAPHQL_ADMIN_SECRET` to something secure
- `docker-compose up -d`
GraphQL endpoint will be `https://<your-domain.com>/v1alpha1/graphql`
GraphQL endpoint will be `https://<your-domain.com>/v1/graphql`
Console will be available on `https://<your-domain.com>/console`
## Connecting to External Postgres

View File

@@ -24,7 +24,7 @@ This Docker Compose setup runs [Hasura GraphQL Engine](https://github.com/hasura
## Important endpoints
- GraphQL endpoint will be `http://localhost:8080/v1alpha1/graphql`
- GraphQL endpoint will be `http://localhost:8080/v1/graphql`
- Hasura Console will be available on `http://localhost:8080/console`
- pgAdmin will be available on `http://localhost:5050`

View File

@@ -14,7 +14,7 @@ See [this blog post for a tutorial](https://blog.hasura.io/graphql-and-geo-locat
- Clone this repo on a machine where you'd like to deploy graphql engine
- `docker-compose up -d`
GraphQL endpoint will be `https://<your-domain.com>/v1alpha1/graphql`
GraphQL endpoint will be `https://<your-domain.com>/v1/graphql`
Console will be available on `https://<your-domain.com>/console`
## Connecting to External Postgres

View File

@@ -12,7 +12,7 @@ This Docker Compose setup runs [Hasura GraphQL Engine](https://github.com/hasura
- Clone this repo on a machine where you'd like to deploy graphql engine
- `docker-compose up -d`
GraphQL endpoint will be `https://<your-domain.com>/v1alpha1/graphql`
GraphQL endpoint will be `https://<your-domain.com>/v1/graphql`
Console will be available on `https://<your-domain.com>/console`
## Connecting to External Postgres

View File

@@ -36,6 +36,7 @@ import qualified Hasura.GraphQL.Transport.WebSocket.Server as WS
import qualified Hasura.Logging as L
import Hasura.Prelude
import Hasura.RQL.Types
import Hasura.RQL.Types.Error (Code (StartFailed))
import Hasura.Server.Auth (AuthMode,
getUserInfo)
import Hasura.Server.Cors
@@ -48,6 +49,11 @@ newtype WsHeaders
= WsHeaders { unWsHeaders :: [H.Header] }
deriving (Show, Eq)
data ErrRespType
= ERTLegacy
| ERTGraphqlCompliant
deriving (Show)
data WSConnState
-- headers from the client for websockets
= CSNotInitialised !WsHeaders
@@ -58,11 +64,12 @@ data WSConnState
data WSConnData
= WSConnData
-- the role and headers are set only on connection_init message
{ _wscUser :: !(IORef.IORef WSConnState)
{ _wscUser :: !(IORef.IORef WSConnState)
-- we only care about subscriptions,
-- the other operations (query/mutations)
-- are not tracked here
, _wscOpMap :: !OperationMap
, _wscOpMap :: !OperationMap
, _wscErrRespTy :: !ErrRespType
}
type WSServer = WS.WSServer WSConnData
@@ -127,22 +134,23 @@ data WSServerEnv
onConn :: L.Logger -> CorsPolicy -> WS.OnConnH WSConnData
onConn (L.Logger logger) corsPolicy wsId requestHead = do
res <- runExceptT $ do
checkPath
errType <- checkPath
let reqHdrs = WS.requestHeaders requestHead
headers <- maybe (return reqHdrs) (flip enforceCors reqHdrs . snd) getOrigin
return $ WsHeaders $ filterWsHeaders headers
either reject accept res
return (WsHeaders $ filterWsHeaders headers, errType)
either reject (uncurry accept) res
where
keepAliveAction wsConn = forever $ do
sendMsg wsConn SMConnKeepAlive
threadDelay $ 5 * 1000 * 1000
accept hdrs = do
accept hdrs errType = do
logger $ WSLog wsId Nothing EAccepted Nothing
connData <- WSConnData
<$> IORef.newIORef (CSNotInitialised hdrs)
<*> STMMap.newIO
<*> pure errType
let acceptRequest = WS.defaultAcceptRequest
{ WS.acceptSubprotocol = Just "graphql-ws"}
return $ Right (connData, acceptRequest, Just keepAliveAction)
@@ -154,9 +162,11 @@ onConn (L.Logger logger) corsPolicy wsId requestHead = do
(H.statusMessage $ qeStatus qErr) []
(BL.toStrict $ J.encode $ encodeGQLErr False qErr)
checkPath =
when (WS.requestPath requestHead /= "/v1alpha1/graphql") $
throw404 "only /v1alpha1/graphql is supported on websockets"
checkPath = case WS.requestPath requestHead of
"/v1alpha1/graphql" -> return ERTLegacy
"/v1/graphql" -> return ERTGraphqlCompliant
_ ->
throw404 "only '/v1/graphql', '/v1alpha1/graphql' are supported on websockets"
getOrigin =
find ((==) "Origin" . fst) (WS.requestHeaders requestHead)
@@ -199,18 +209,18 @@ onStart serverEnv wsConn (StartMsg opId q) msgRaw = catchAndIgnore $ do
opM <- liftIO $ STM.atomically $ STMMap.lookup opId opMap
when (isJust opM) $ withComplete $ sendConnErr $
when (isJust opM) $ withComplete $ sendStartErr $
"an operation already exists with this id: " <> unOperationId opId
userInfoM <- liftIO $ IORef.readIORef userInfoR
(userInfo, reqHdrs) <- case userInfoM of
CSInitialised userInfo reqHdrs -> return (userInfo, reqHdrs)
CSInitError initErr -> do
let connErr = "cannot start as connection_init failed with : " <> initErr
withComplete $ sendConnErr connErr
let e = "cannot start as connection_init failed with : " <> initErr
withComplete $ sendStartErr e
CSNotInitialised _ -> do
let connErr = "start received before the connection is initialised"
withComplete $ sendConnErr connErr
let e = "start received before the connection is initialised"
withComplete $ sendStartErr e
(sc, scVer) <- liftIO $ IORef.readIORef gCtxMapRef
execPlanE <- runExceptT $ E.getResolvedExecPlan pgExecCtx
@@ -265,28 +275,40 @@ onStart serverEnv wsConn (StartMsg opId q) msgRaw = catchAndIgnore $ do
WSServerEnv logger pgExecCtx lqMap gCtxMapRef httpMgr _
sqlGenCtx planCache _ = serverEnv
WSConnData userInfoR opMap = WS.getData wsConn
WSConnData userInfoR opMap errRespTy = WS.getData wsConn
logOpEv opDet =
logWSEvent logger wsConn $ EOperation opId (_grOperationName q) opDet
sendConnErr connErr = do
sendMsg wsConn $ SMErr $ ErrorMsg opId $ J.toJSON connErr
logOpEv $ ODProtoErr connErr
getErrFn errTy =
case errTy of
ERTLegacy -> encodeQErr
ERTGraphqlCompliant -> encodeGQLErr
sendStartErr e = do
let errFn = getErrFn errRespTy
sendMsg wsConn $ SMErr $ ErrorMsg opId $ errFn False $
err400 StartFailed e
logOpEv $ ODProtoErr e
sendCompleted = do
sendMsg wsConn $ SMComplete $ CompletionMsg opId
logOpEv ODCompleted
postExecErr qErr = do
let errFn = getErrFn errRespTy
logOpEv $ ODQueryErr qErr
sendMsg wsConn $ SMData $ DataMsg opId $
GQExecError $ pure $ encodeQErr False qErr
GQExecError $ pure $ errFn False qErr
-- why wouldn't pre exec error use graphql response?
preExecErr qErr = do
let errFn = getErrFn errRespTy
logOpEv $ ODQueryErr qErr
sendMsg wsConn $ SMErr $ ErrorMsg opId $ encodeQErr False qErr
let err = case errRespTy of
ERTLegacy -> errFn False qErr
ERTGraphqlCompliant -> J.object ["errors" J..= [errFn False qErr]]
sendMsg wsConn $ SMErr $ ErrorMsg opId err
sendSuccResp encJson =
sendMsg wsConn $ SMData $ DataMsg opId $ GQSuccess $ encJToLBS encJson
@@ -350,7 +372,7 @@ logWSEvent (L.Logger logger) wsConn wsEv = do
_ -> Nothing
liftIO $ logger $ WSLog wsId userInfoM wsEv Nothing
where
WSConnData userInfoR _ = WS.getData wsConn
WSConnData userInfoR _ _ = WS.getData wsConn
wsId = WS.getWSId wsConn
onConnInit

View File

@@ -40,12 +40,12 @@ module Hasura.RQL.Types.Error
import Data.Aeson
import Data.Aeson.Internal
import Data.Aeson.Types
import qualified Database.PG.Query as Q
import qualified Database.PG.Query as Q
import Hasura.Prelude
import Text.Show (Show (..))
import Text.Show (Show (..))
import qualified Data.Text as T
import qualified Network.HTTP.Types as N
import qualified Data.Text as T
import qualified Network.HTTP.Types as N
data Code
= PermissionDenied
@@ -83,6 +83,8 @@ data Code
-- Remote schemas
| RemoteSchemaError
| RemoteSchemaConflicts
-- Websocket/Subscription errors
| StartFailed
deriving (Eq)
instance Show Code where
@@ -119,6 +121,7 @@ instance Show Code where
JWTInvalidKey -> "invalid-jwt-key"
RemoteSchemaError -> "remote-schema-error"
RemoteSchemaConflicts -> "remote-schema-conflicts"
StartFailed -> "start-failed"
data QErr
= QErr

View File

@@ -220,10 +220,11 @@ logError userInfoM req reqBody sc qErr =
mkSpockAction
:: (MonadIO m)
=> (Bool -> QErr -> Value)
-> (QErr -> QErr)
-> ServerCtx
-> Handler APIResp
-> ActionT m ()
mkSpockAction qErrEncoder serverCtx handler = do
mkSpockAction qErrEncoder qErrModifier serverCtx handler = do
req <- request
reqBody <- liftIO $ strictRequestBody req
let headers = requestHeaders req
@@ -236,13 +237,15 @@ mkSpockAction qErrEncoder serverCtx handler = do
let handlerState = HandlerCtx serverCtx reqBody userInfo headers
t1 <- liftIO getCurrentTime -- for measuring response time purposes
eResult <- liftIO $ runReaderT (runExceptT handler) handlerState
result <- liftIO $ runReaderT (runExceptT handler) handlerState
t2 <- liftIO getCurrentTime -- for measuring response time purposes
-- apply the error modifier
let modResult = fmapL qErrModifier result
-- log result
logResult (Just userInfo) req reqBody serverCtx (apiRespToLBS <$> eResult) $ Just (t1, t2)
either (qErrToResp $ userRole userInfo == adminRole) resToResp eResult
logResult (Just userInfo) req reqBody serverCtx (apiRespToLBS <$> modResult) $ Just (t1, t2)
either (qErrToResp $ userRole userInfo == adminRole) resToResp modResult
where
logger = scLogger serverCtx
@@ -256,14 +259,13 @@ mkSpockAction qErrEncoder serverCtx handler = do
logError Nothing req reqBody serverCtx qErr
qErrToResp includeInternal qErr
resToResp eResult = do
case eResult of
JSONResp j -> do
uncurry setHeader jsonHeader
lazyBytes $ encJToLBS j
RawResp ct b -> do
setHeader "content-type" ct
lazyBytes b
resToResp = \case
JSONResp j -> do
uncurry setHeader jsonHeader
lazyBytes $ encJToLBS j
RawResp ct b -> do
setHeader "content-type" ct
lazyBytes b
v1QueryHandler :: RQLQuery -> Handler EncJSON
v1QueryHandler query = do
@@ -305,6 +307,9 @@ v1Alpha1GQHandler query = do
GH.runGQ pgExecCtx userInfo sqlGenCtx planCache
sc scVer manager reqHeaders query reqBody
v1GQHandler :: GH.GQLReqUnparsed -> Handler EncJSON
v1GQHandler = v1Alpha1GQHandler
gqlExplainHandler :: GE.GQLExplain -> Handler EncJSON
gqlExplainHandler query = do
onlyAdmin
@@ -414,13 +419,9 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do
-- Health check endpoint
get "healthz" $ do
sc <- liftIO $ getSCFromRef $ scCacheRef serverCtx
let reportOK = do
setStatus N.status200
lazyBytes "OK"
reportError = do
setStatus N.status500
lazyBytes "ERROR"
bool reportError reportOK $ null $ scInconsistentObjs sc
if null $ scInconsistentObjs sc
then setStatus N.status200 >> lazyBytes "OK"
else setStatus N.status500 >> lazyBytes "ERROR"
get "v1/version" $ do
uncurry setHeader jsonHeader
@@ -432,42 +433,46 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do
put ("v1/template" <//> var) tmpltPutOrPostH
delete ("v1/template" <//> var) tmpltGetOrDeleteH
post "v1/query" $ mkSpockAction encodeQErr serverCtx $ mkAPIRespHandler $ do
post "v1/query" $ mkSpockAction encodeQErr id serverCtx $ mkAPIRespHandler $ do
query <- parseBody
v1QueryHandler query
post ("api/1/table" <//> var <//> var) $ \tableName queryType ->
mkSpockAction encodeQErr serverCtx $ mkAPIRespHandler $
mkSpockAction encodeQErr id serverCtx $ mkAPIRespHandler $
legacyQueryHandler (TableName tableName) queryType
when enablePGDump $
post "v1alpha1/pg_dump" $ mkSpockAction encodeQErr serverCtx $ do
post "v1alpha1/pg_dump" $ mkSpockAction encodeQErr id serverCtx $ do
query <- parseBody
v1Alpha1PGDumpHandler query
when enableGraphQL $ do
post "v1alpha1/graphql/explain" $ mkSpockAction encodeQErr serverCtx $
mkAPIRespHandler $ do
expQuery <- parseBody
gqlExplainHandler expQuery
post "v1alpha1/graphql/explain" gqlExplainAction
post "v1alpha1/graphql" $ mkSpockAction GH.encodeGQErr serverCtx $
post "v1alpha1/graphql" $ mkSpockAction GH.encodeGQErr id serverCtx $
mkAPIRespHandler $ do
query <- parseBody
v1Alpha1GQHandler query
post "v1/graphql/explain" gqlExplainAction
post "v1/graphql" $ mkSpockAction GH.encodeGQErr allMod200 serverCtx $
mkAPIRespHandler $ do
query <- parseBody
v1GQHandler query
when (isDeveloperAPIEnabled serverCtx) $ do
get "dev/plan_cache" $ mkSpockAction encodeQErr serverCtx $
get "dev/plan_cache" $ mkSpockAction encodeQErr id serverCtx $
mkAPIRespHandler $ do
onlyAdmin
respJ <- liftIO $ E.dumpPlanCache $ scPlanCache serverCtx
return $ encJFromJValue respJ
get "dev/subscriptions" $ mkSpockAction encodeQErr serverCtx $
get "dev/subscriptions" $ mkSpockAction encodeQErr id serverCtx $
mkAPIRespHandler $ do
onlyAdmin
respJ <- liftIO $ EL.dumpLiveQueriesState False $ scLQState serverCtx
return $ encJFromJValue respJ
get "dev/subscriptions/extended" $ mkSpockAction encodeQErr serverCtx $
get "dev/subscriptions/extended" $ mkSpockAction encodeQErr id serverCtx $
mkAPIRespHandler $ do
onlyAdmin
respJ <- liftIO $ EL.dumpLiveQueriesState True $ scLQState serverCtx
@@ -478,17 +483,25 @@ httpApp corsCfg serverCtx enableConsole enableTelemetry = do
raiseGenericApiError qErr
where
-- all graphql errors should be of type 200
allMod200 qe = qe { qeStatus = N.status200 }
gqlExplainAction =
mkSpockAction encodeQErr id serverCtx $ mkAPIRespHandler $ do
expQuery <- parseBody
gqlExplainHandler expQuery
enableGraphQL = isGraphQLEnabled serverCtx
enableMetadata = isMetadataEnabled serverCtx
enablePGDump = isPGDumpEnabled serverCtx
tmpltGetOrDeleteH tmpltName = do
tmpltArgs <- tmpltArgsFromQueryParams
mkSpockAction encodeQErr serverCtx $ mkAPIRespHandler $
mkSpockAction encodeQErr id serverCtx $ mkAPIRespHandler $
mkQTemplateAction tmpltName tmpltArgs
tmpltPutOrPostH tmpltName = do
tmpltArgs <- tmpltArgsFromQueryParams
mkSpockAction encodeQErr serverCtx $ mkAPIRespHandler $ do
mkSpockAction encodeQErr id serverCtx $ mkAPIRespHandler $ do
bodyTmpltArgs <- parseBody
mkQTemplateAction tmpltName $ M.union bodyTmpltArgs tmpltArgs

View File

@@ -157,7 +157,7 @@ def evts_webhook(request):
@pytest.fixture(scope='class')
def ws_client(request, hge_ctx):
client = GQLWsClient(hge_ctx)
client = GQLWsClient(hge_ctx, '/v1/graphql')
time.sleep(0.1)
yield client
client.teardown()

View File

@@ -26,14 +26,13 @@ import graphql
class HGECtxError(Exception):
pass
class GQLWsClient:
class GQLWsClient():
def __init__(self, hge_ctx):
def __init__(self, hge_ctx, endpoint):
self.hge_ctx = hge_ctx
self.ws_queue = queue.Queue(maxsize=-1)
self.ws_url = urlparse(hge_ctx.hge_url)
self.ws_url = self.ws_url._replace(scheme='ws')
self.ws_url = self.ws_url._replace(path='/v1alpha1/graphql')
self.ws_url = urlparse(hge_ctx.hge_url)._replace(scheme='ws',
path=endpoint)
self.create_conn()
def create_conn(self):
@@ -94,11 +93,10 @@ class GQLWsClient:
self.ws_active_query_ids.discard(query_id)
def gen_id(self, size=6, chars=string.ascii_letters + string.digits):
newId = ''.join(random.choice(chars) for _ in range(size))
if newId in self.ws_active_query_ids:
return gen_id(self,size,chars)
else:
return newId
new_id = ''.join(random.choice(chars) for _ in range(size))
if new_id in self.ws_active_query_ids:
return self.gen_id(size, chars)
return new_id
def send_query(self, query, query_id=None, headers={}, timeout=60):
graphql.parse(query['query'])
@@ -254,7 +252,7 @@ class HGECtx:
self.hge_scale_url = hge_scale_url
self.ws_client = GQLWsClient(self)
self.ws_client = GQLWsClient(self, '/v1/graphql')
result = subprocess.run(['../../scripts/get-version.sh'], shell=False, stdout=subprocess.PIPE, check=True)
self.version = result.stdout.decode('utf-8').strip()

View File

@@ -1,5 +1,5 @@
description: GraphQL introspection query
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
query:
query: |

View File

@@ -1,5 +1,5 @@
description: GraphQL introspection query which returns the kind of queryType. This output should be the same across any GraphQL implementation
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:

View File

@@ -1,5 +1,5 @@
description: GraphQL introspection query as user role
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
headers:
X-Hasura-Role: user

View File

@@ -1,5 +1,5 @@
description: Delete mutation on article
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:

View File

@@ -1,5 +1,5 @@
description: Delete mutation on article with returning
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:

View File

@@ -1,5 +1,5 @@
description: Delete mutation on article with returning columns and author
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:

View File

@@ -1,6 +1,6 @@
description: delete from author table (Foreign Key Violation Error)
url: /v1alpha1/graphql
status: 400
url: /v1/graphql
status: 200
query:
query: |
mutation {

View File

@@ -1,5 +1,5 @@
description: A user can delete his articles
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
headers:
X-Hasura-Role: user

View File

@@ -1,5 +1,5 @@
description: A user cannot delete other users articles
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
headers:
X-Hasura-Role: user

View File

@@ -1,6 +1,6 @@
description: Delete a row in resident table where id = 1 (Error)
url: /v1alpha1/graphql
status: 400
url: /v1/graphql
status: 200
headers:
X-Hasura-Role: user
X-Hasura-User-Id: '1'

View File

@@ -1,6 +1,6 @@
#Inserting author data
- description: Inserts author data via GraphQL mutation
url: /v1alpha1/graphql
url: /v1/graphql
response:
data:
insert_author:
@@ -32,7 +32,7 @@
#Inserting empty objects
- description: Inserts empty objects via GraphQL mutation
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:
@@ -55,7 +55,7 @@
#Inserting article data
- description: Inserts article data via GraphQL mutation
url: /v1alpha1/graphql
url: /v1/graphql
response:
data:
insert_article:

View File

@@ -1,6 +1,6 @@
#Inserting data into test_types table
- description: Inserts Array into an Array column
url: /v1alpha1/graphql
url: /v1/graphql
response:
data:
insert_test_types:

View File

@@ -1,6 +1,6 @@
#Inserting data into test_types table
- description: Inserts data into test_types table with various postgres types
url: /v1alpha1/graphql
url: /v1/graphql
response:
data:
insert_test_types:

View File

@@ -1,5 +1,5 @@
- description: Insert into order table with a null value
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
query:
query: |

View File

@@ -1,5 +1,5 @@
- description: Inserts person data via GraphQL mutation (without Variable)
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:

View File

@@ -1,5 +1,5 @@
- description: Inserts persons data via GraphQL mutation (without variables)
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
response:
data:

View File

@@ -1,5 +1,5 @@
- description: Inserts person data via GraphQL mutation
url: /v1alpha1/graphql
url: /v1/graphql
status: 200
query:
variables:

Some files were not shown because too many files have changed in this diff Show More