Skip to content

Commit

Permalink
Merge pull request #24 from nulogy/generate-schema-regardless-of-visi…
Browse files Browse the repository at this point in the history
…bility

Generate schema regardless of visibility
  • Loading branch information
github-actions[bot] authored May 29, 2024
2 parents 762a303 + 96dda53 commit ab08f5f
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 78 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
/pkg/
/spec/reports/
/tmp/
/spec/dummy/tmp/local_secret.txt
/spec/dummy/db/test.sqlite3*

# rspec failure tracking
.rspec_status
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@

_none_

## 4.0.0 (2024-05-28)

**Changes**

* Remove the `schema_generation_context?` attribute to the GraphQL `context` when generating the schema. Use the
already available `GraphQL::Schema::AlwaysVisible` plugin instead.
* **(Breaking)** Remove the `NulogyGraphqlApi::Schema::BaseMutation` class which introduced a new API for the
`visible?` method that took a block. This introduced a deviation from the ruby graphql gem's API only for
Mutations and so it was removed. Please ensure that any invocations of `visible?` do not take a block and use
`GraphQL::Schema::Mutation` instead.
* **(Breaking)** Change the `NulogyGraphqlApi::Tasks::SchemaGenerator#generate_schema` method to output the
stringified version of the schema instead of checking it for changes and writing it to a file.
* Expose the `#check_changes` and `#write_schema_to_file` methods on the
`NulogyGraphqlApi::Tasks::SchemaGenerator` to give the user more control over how to build their
tooling.
* Allow the user to be specified for the `request_graphql` test helper.

## 3.0.1 (2024-01-30)

* Add `include_graphql_error` RSpec matcher
Expand Down
46 changes: 2 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ end

There is a Rake task to generate the `schema.graphql` file. You need to provide the `schema_file_path` and the schema class so that the task can detect breaking changes and generate the file. If you don't have a schema file because it's your first time generating it then the rake task will just create one for you in the path provided.

There is also a third argument `context`. You'll have to configure it to be able to generate the SDL of fields or types that are only visible for more privileged users.

```ruby
namespace :graphql_api do
desc "Generate the graphql schema of the api."
Expand All @@ -142,47 +140,7 @@ namespace :graphql_api do

NulogyGraphqlApi::Tasks::SchemaGenerator
.new(schema_file_path, schema)
.generate_schema
end
end
```

### Node visibility

When you customize the visibility of parts of your graph you have to make sure that all nodes are visible when the schema is being generated by the rake task. You can do so by using the `schema_generation_context?` attribute that is added to the context by the `SchemaGenerator` mentioned in the previous section.

Here is how to use it:

##### On fields
```ruby
field :entity, MyApp::EntityType, null: false do
description "Find an entity by ID"
argument :id, ID, required: true

def visible?(context)
context[:schema_generation_context?] || context[:current_user].superuser?
end
end
```


##### On mutations

In this case the `schema_generation_context?` attribute is checked by the `BaseMutation` class. All you have to do is inheriting from it and override `visible?` passing a block to the base method.

```ruby
module MyApp
class CreateEntity < NulogyGraphqlApi::Schema::BaseMutation
field :entity, MyApp::EntityType, null: false
field :errors, [NulogyGraphqlApi::Types::UserErrorType], null: false

def self.visible?(context)
super { context[:current_user].super_user? }
end

def resolve(args)
# ...
end
.write_schema_to_file
end
end
```
Expand Down Expand Up @@ -237,7 +195,7 @@ The `request_graphql` helper issues a POST request against the provided URL. Thi
```ruby
RSpec.describe MyApp::Graphql::Query, :graphql, type: :request do
it "returns 401 Unauthorized given an unauthenticated request" do
gql_response = request_graphql(url, <<~GRAPHQL, headers: { "HTTP_AUTHORIZATION" => nil })
gql_response = request_graphql(url, <<~GRAPHQL, headers: { "HTTP_AUTHORIZATION" => nil }, user: default_user)
query {
entities {
id
Expand Down
1 change: 0 additions & 1 deletion lib/nulogy_graphql_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
require "nulogy_graphql_api/error_handling"
require "nulogy_graphql_api/graphql_executor"
require "nulogy_graphql_api/graphql_response"
require "nulogy_graphql_api/schema/base_mutation"
require "nulogy_graphql_api/transaction_service"
require "nulogy_graphql_api/tasks/schema_changes_checker"
require "nulogy_graphql_api/tasks/schema_generator"
Expand Down
6 changes: 4 additions & 2 deletions lib/nulogy_graphql_api/rspec/graphql_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module NulogyGraphqlApi
module GraphqlHelpers
# Prefer the `request_graphql` method over this one because it exercises more of the stack but doesn't run
# much slower.
def execute_graphql(query, schema, variables: {}, context: {})
camelized_variables = variables.deep_transform_keys! { |key| key.to_s.camelize(:lower) } || {}

Expand All @@ -13,11 +15,11 @@ def execute_graphql(query, schema, variables: {}, context: {})
response.to_h.deep_symbolize_keys
end

def request_graphql(url, query, variables: {}, headers: {})
def request_graphql(url, query, variables: {}, headers: {}, user: nil)
params = { query: query, variables: variables }.to_json
default_headers = {
CONTENT_TYPE: "application/json",
HTTP_AUTHORIZATION: basic_auth_token(default_user.login)
HTTP_AUTHORIZATION: basic_auth_token((user || default_user).login)
}

post url, params: params, headers: default_headers.merge(headers)
Expand Down
12 changes: 0 additions & 12 deletions lib/nulogy_graphql_api/schema/base_mutation.rb

This file was deleted.

29 changes: 12 additions & 17 deletions lib/nulogy_graphql_api/tasks/schema_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,32 @@ class SchemaGenerator
def initialize(schema_output_path, schema, context: {})
@schema_output_path = schema_output_path
@schema = schema
@context = context.merge(
schema_generation_context?: true
)
@context = context
end

def generate_schema
check_changes
write_schema_to_file
visible_schema = Class.new(@schema)
visible_schema.use(GraphQL::Schema::AlwaysVisible)
visible_schema.to_definition(context: @context)
end

private

def check_changes
return if old_schema.blank?

SchemaChangesChecker.new.check_changes(old_schema, @schema)
end

def old_schema
return unless File.exist?(@schema_output_path)

File.read(@schema_output_path)
SchemaChangesChecker.new.check_changes(old_schema, generate_schema)
end

def write_schema_to_file
File.write(@schema_output_path, schema_definition)
File.write(@schema_output_path, generate_schema)
puts Rainbow("\nSuccessfully updated #{@schema_output_path}").green
end

def schema_definition
GraphQL::Schema::Printer.print_schema(@schema, context: @context)
private

def old_schema
return unless File.exist?(@schema_output_path)

File.read(@schema_output_path)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/nulogy_graphql_api/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module NulogyGraphqlApi
VERSION = "3.0.1"
VERSION = "4.0.0"
end
2 changes: 1 addition & 1 deletion spec/dummy/config/initializers/assets.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.

# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
# Rails.application.config.assets.version = '1.0'

# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
Expand Down
Binary file modified spec/dummy/db/test.sqlite3
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class VisibleQuery < GraphQL::Schema::Object
field :test, String, null: false
end

class InvisibleQuery < GraphQL::Schema::Object
field :test, String, null: false

def self.visible?(_context)
false
end
end

RSpec.describe NulogyGraphqlApi::Tasks::SchemaGenerator do
it "stringifies the schema" do
fake_schema = Class.new(GraphQL::Schema) do
query VisibleQuery
end
task = NulogyGraphqlApi::Tasks::SchemaGenerator.new("schema_output_path", fake_schema)

result = task.generate_schema

expect(result).to eq(<<~GQL)
schema {
query: VisibleQuery
}
type VisibleQuery {
test: String!
}
GQL
end

it "stringifies invisible parts of the schema" do
fake_schema = Class.new(GraphQL::Schema) do
query InvisibleQuery
end
task = NulogyGraphqlApi::Tasks::SchemaGenerator.new("schema_output_path", fake_schema)

result = task.generate_schema

expect(result).to eq(<<~GQL)
schema {
query: InvisibleQuery
}
type InvisibleQuery {
test: String!
}
GQL
end

it "does not alter the given schema" do
fake_schema = Class.new(GraphQL::Schema)
old_warden = fake_schema.warden_class
task = NulogyGraphqlApi::Tasks::SchemaGenerator.new("schema_output_path", fake_schema)

task.generate_schema

expect(fake_schema.warden_class).to eq(old_warden)
end
end

0 comments on commit ab08f5f

Please sign in to comment.