Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

GraphiQL server (+ minor usability features) #112

Merged
merged 1 commit into from
Apr 20, 2018
Merged

Conversation

SudoBobo
Copy link
Contributor

@SudoBobo SudoBobo commented Apr 6, 2018

No description provided.

@SudoBobo SudoBobo requested a review from Totktonada April 6, 2018 12:22
body = json.encode({errors={{message="Body should be a valid JSON"}}})
}
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can check type(parsed) == 'table' here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

if not ok then
return {
status = 200,
body = json.encode({errors={{message=result}}})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

's/=/ = /g' (in other places too)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not get your point. Did you mean to 'a=b' -> 'a = b' ? If so, fixed. (I made it initially with no whitespaces to keep it one-line)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that was the point.

@@ -190,7 +191,7 @@ local function gql_argument_type(avro_schema)

fields[field.name] = {
name = field.name,
kind = types.nonNull(gql_field_type),
kind = gql_field_type,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will not remember why this is needed after two months.

Copy link
Contributor Author

@SudoBobo SudoBobo Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure, but it seems that current version does not need a comment, because it's quite straightforward. Previous version needed a comment because there was an additional nonNull wrapping with no obvious reason.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The field cannot be non-null here (do we need to call nullable(gql_field_type))?
  2. I would add a comment like 'accept any subset of an input object field as a filter'. Ok?

Copy link
Contributor Author

@SudoBobo SudoBobo Apr 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Do you mean, that the field can't be non-null here because we want arguments (corresponding GraphQL InputObjects) to have all fields nullable? (As we discussed it verbally) If yes, so we need to do something like nullable(gql_field_type) But I think this should be done in another branch, related to InputObjects arguments support
  2. Ok. That's what we do :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I mean that nullability of Object should no affect nullability of InputObject.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not get your point. Need to discus verbally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #127 and added comment tarantool/graphql#26 (comment)

assert_gql_query_ast('gql_compile', ast)
local operation_name = ast.definitions[1].name.value

local operation_name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How this change related to the graphiql? What a problem you fix here?

Copy link
Contributor Author

@SudoBobo SudoBobo Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this story with GraphiQL Tarantool GraphQL (as a GraphQL backend) assumed that in all incoming queries there is only one definition (an operation definition describing the query itself).
It's true if the query is simple, but in case of fragments it is not. Each fragment represented as a definition in ast.
We want to support fragments in general. And they are necessary for our GraphiQL to work as it's JS code send an introspection query with fragments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much part of #16 and #50 closed by this? Maybe we can extract it into a separate commit (before graphiql support) to fix these two issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A big part of #16 is closed (but there should be additions also). #50 is not much related to the current pull request, but can be easily (at least seems so) fixed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can mention that they are more or less related in a commit message, but leave they open.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll do so.

end
end

assert(operation_name, "there is no 'operation' in query " ..
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to have --- from yaml on its own line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got your point, fixed.

assert(type(gql) == 'table',
'use :start_server(...) instead of .start_server(...)')
gql.server = server.init(gql)
gql.server:start()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return true, 'The server started at http://127.0.0.1:8000' or kinda to improve usability from console?

Copy link
Contributor Author

@SudoBobo SudoBobo Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Added.

favored resource bundler.
-->
<link rel="stylesheet" href="/static/css/graphiql.css" />
<script src="/static/js/graphiql.js"></script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you forget to add these files into the commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Sorry. Added them.

@@ -9,6 +9,10 @@ graphql.accessor_general = accessor_general
graphql.accessor_space = accessor_space
graphql.accessor_shard = accessor_shard
graphql.new = tarantool_graphql.new
graphql.compile = tarantool_graphql.compile
graphql.execute = tarantool_graphql.execute
graphql.start_server = tarantool_graphql.start_server
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No space format at all, got:

{
  "errors": [
    {
      "message": "./graphql/core/validate.lua:223: assign to undeclared variable 'kind'"
    }
  ]
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And with format too.

Copy link
Contributor Author

@SudoBobo SudoBobo Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the case? I added a test with user-configured tarantool graphql instance + server usage and it passed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I need to try again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The problem was with global variables in grahql/core

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to track such problems: found problem with empty variables (it is converted to box.NULL and box.NULL or {} is not {}).

Copy link
Member

@Totktonada Totktonada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments I forgot to send before.

@@ -9,6 +9,10 @@ graphql.accessor_general = accessor_general
graphql.accessor_space = accessor_space
graphql.accessor_shard = accessor_shard
graphql.new = tarantool_graphql.new
graphql.compile = tarantool_graphql.compile
graphql.execute = tarantool_graphql.execute
graphql.start_server = tarantool_graphql.start_server
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And with format too.

if not ok then
return {
status = 200,
body = json.encode({errors={{message=result}}})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that was the point.

@SudoBobo SudoBobo force-pushed the sb/graphiql branch 6 times, most recently from f57a9f5 to 3e4b0d2 Compare April 17, 2018 08:21
Copy link
Member

@Totktonada Totktonada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bunch of comments.

@@ -213,4 +213,18 @@ function utils.value_in(value, array)
return false
end

function utils.deep_copy(orig)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is built-in table.deepcopy fit your needs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does. Removed.

assert_gql_query_ast('gql_compile', ast)
local operation_name = ast.definitions[1].name.value

local operation_name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much part of #16 and #50 closed by this? Maybe we can extract it into a separate commit (before graphiql support) to fix these two issues.

local operation_name
for _, definition in pairs(ast.definitions) do
if definition.kind == 'operation' then
operation_name = definition.name.value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple operation case is okay? Maybe we need to (add and) consider 'operation_name' argument mandatory in the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple operation case is okay. You define as many as you want, but can execute only one at a time, specifying it with 'operation_name' (Details)
Answering to the second question: according to the spec, we should not make it mandatory. Anyway I should check (and probably re-write) this place to satisfy GraphQL spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed it verbally, it will be done in another branch.

@@ -1223,6 +1210,15 @@ local function gql_execute(qstate, variables)
operation_name)
end

local function gql_execute(state, query, variables)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposed to use separate work for compile+execute. Maybe 'run'?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean 'separate name'. Don’t have idea why I wrote 'separate work'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems good enough, can't think of better naming. Fxd.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to change external API as well? gql_wrapper:execute() -> gql_wrapper:run()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to change, but now I think that we can proceed with API like in lrexlib-pcre where match can be called for the module with an expression as a string as well as for compiled expression.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed verbally. Internal functions renamed, external API left as it is.

execute = gql_execute,
start_server = start_server,
stop_server = stop_server,
cfg = cfg,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove it, it is in 'internal'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.


gql_wrapper:stop_server()

-- add space formats and try default instance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you test it in 'no_instance' test already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 'no_instance' I test the whole mechanism of require(graphql):do_something_cool() Here I test the http server itself.

README.md Outdated
local graphql = require('graphql').new({
schemas = schemas,
collections = collections,
accessor = accessor
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure it will work w/o indexes and service_fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it will not. Fxd readme.

README.md Outdated
graphql:stop_server()

-- as well you may do
require('graphql').start_server()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why period here, but colon for an instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not get your point. In case of require(...) we call just a function. In case of instance we want to pass this instance as a first argument.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked shard and http.client modules, they share your approach. So, I discard my proposal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed verbally, left as it is.

@@ -169,6 +170,17 @@ function simple_config.get_spaces_formats()
return spaces_formats
end

local function remove_empty_formats(spaces_formats)
local resulting_formats = utils.deep_copy(spaces_formats)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you don't need deepcopy at all, table.copy will suffer your needs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fxd. (English remark: maybe 'serve', not 'suffer'? :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I did went to say 'suit'… Don’t know what was with my wording in Tue.

@@ -190,7 +191,7 @@ local function gql_argument_type(avro_schema)

fields[field.name] = {
name = field.name,
kind = types.nonNull(gql_field_type),
kind = gql_field_type,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The field cannot be non-null here (do we need to call nullable(gql_field_type))?
  2. I would add a comment like 'accept any subset of an input object field as a filter'. Ok?

@SudoBobo SudoBobo force-pushed the sb/graphiql branch 2 times, most recently from d2dc8ed to ef2b1ac Compare April 20, 2018 07:52
@SudoBobo SudoBobo changed the title GraphiQL server (+ minor usability features) WIP PR GraphiQL server (+ minor usability features) Apr 20, 2018
@SudoBobo SudoBobo force-pushed the sb/graphiql branch 6 times, most recently from f435327 to e33a8ef Compare April 20, 2018 15:37
features

Now it is possible to use commands like
require('graphql').execute(...) or .start_server() with no manual creating
of graphql instance; close #1; changes in gql_compile is related to #16 and #50.
@SudoBobo SudoBobo merged commit ce19d43 into master Apr 20, 2018
@SudoBobo SudoBobo deleted the sb/graphiql branch May 26, 2018 18:07
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants