ash_graphql/lib/api/api.ex
2021-05-14 12:25:43 -04:00

155 lines
3.8 KiB
Elixir

defmodule AshGraphql.Api do
@graphql %Ash.Dsl.Section{
name: :graphql,
describe: """
Global configuration for graphql
""",
examples: [
"""
graphql do
authorize? false # To skip authorization for this API
end
"""
],
schema: [
authorize?: [
type: :boolean,
doc: "Whether or not to perform authorization for this API",
default: true
],
stacktraces?: [
type: :boolean,
doc: "Whether or not to include stacktraces in generated errors",
default: false
],
debug?: [
type: :boolean,
doc: "Whether or not to log (extremely verbose) debug information",
default: false
]
]
}
@sections [@graphql]
@moduledoc """
The entrypoint for adding graphql behavior to an Ash API
# Table of Contents
#{Ash.Dsl.Extension.doc_index(@sections)}
#{Ash.Dsl.Extension.doc(@sections)}
"""
use Ash.Dsl.Extension, sections: @sections
def authorize?(api) do
Extension.get_opt(api, [:graphql], :authorize?, true)
end
def debug?(api) do
Extension.get_opt(api, [:graphql], :debug?, false)
end
def stacktraces?(api) do
Extension.get_opt(api, [:graphql], :stacktraces?, false)
end
@doc false
def queries(api, schema) do
api
|> Ash.Api.resources()
|> Enum.flat_map(&AshGraphql.Resource.queries(api, &1, schema))
end
@doc false
def mutations(api, schema) do
api
|> Ash.Api.resources()
|> Enum.filter(fn resource ->
AshGraphql.Resource in Ash.Resource.Info.extensions(resource)
end)
|> Enum.flat_map(&AshGraphql.Resource.mutations(api, &1, schema))
end
@doc false
def type_definitions(api, schema) do
resource_types =
api
|> Ash.Api.resources()
|> Enum.flat_map(fn resource ->
if AshGraphql.Resource in Ash.Resource.Info.extensions(resource) do
AshGraphql.Resource.type_definitions(resource, api, schema) ++
AshGraphql.Resource.mutation_types(resource, schema)
else
AshGraphql.Resource.no_graphql_types(resource, schema)
end
end)
resource_types
end
def global_type_definitions(schema) do
[mutation_error(schema), sort_order(schema)]
end
defp sort_order(schema) do
%Absinthe.Blueprint.Schema.EnumTypeDefinition{
module: schema,
name: "SortOrder",
values: [
%Absinthe.Blueprint.Schema.EnumValueDefinition{
module: schema,
identifier: :desc,
name: "DESC",
value: :desc
},
%Absinthe.Blueprint.Schema.EnumValueDefinition{
module: schema,
identifier: :asc,
name: "ASC",
value: :asc
}
],
identifier: :sort_order
}
end
defp mutation_error(schema) do
%Absinthe.Blueprint.Schema.ObjectTypeDefinition{
description: "An error generated by a failed mutation",
fields: error_fields(schema),
identifier: :mutation_error,
module: schema,
name: "MutationError"
}
end
defp error_fields(schema) do
[
%Absinthe.Blueprint.Schema.FieldDefinition{
description: "The human readable error message",
identifier: :message,
module: schema,
name: "message",
type: :string
},
%Absinthe.Blueprint.Schema.FieldDefinition{
description: "An error code for the given error",
identifier: :code,
module: schema,
name: "code",
type: :string
},
%Absinthe.Blueprint.Schema.FieldDefinition{
description: "The field or fields that produced the error",
identifier: :fields,
module: schema,
name: "fields",
type: %Absinthe.Blueprint.TypeReference.List{
of_type: :string
}
}
]
end
end