Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions app/controllers/graphql_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@

skip_before_action :authenticate_user!, only: [:execute]

def content
execute_in_read_replica do
schema_name = Edition.live.where(base_path:).pick(:schema_name)

# TODO: handle unsupported schema_name
if schema_name && (class_name = "queries/graphql/#{schema_name}_query".camelize.constantize)

Check warning

Code scanning / Brakeman

Unsafe reflection method constantize called on model attribute. Warning

Unsafe reflection method constantize called on model attribute.
query = class_name.query(base_path:)
result = PublishingApiSchema.execute(query).to_hash
process_graphql_result(result)
# TODO: handle 404s

render json: result.dig("data", "edition")
end
rescue StandardError => e
raise e unless Rails.env.development?

handle_error_in_development(e)
end
end

def execute
execute_in_read_replica do
variables = prepare_variables(params[:variables])
Expand All @@ -24,15 +44,7 @@
operation_name:,
).to_hash

set_prometheus_labels(result.dig("data", "edition")&.slice("document_type", "schema_name"))

if result.key?("errors")
logger.warn("GraphQL query result contained errors: #{result['errors']}")
set_prometheus_labels("contains_errors" => true)
else
logger.debug("GraphQL query result: #{result}")
set_prometheus_labels("contains_errors" => false)
end
process_graphql_result(result)

render json: result
rescue StandardError => e
Expand All @@ -44,6 +56,22 @@

private

def base_path
"/#{params[:path_without_root]}"
end

def process_graphql_result(result)
set_prometheus_labels(result.dig("data", "edition")&.slice("document_type", "schema_name"))

if result.key?("errors")
logger.warn("GraphQL query result contained errors: #{result['errors']}")
set_prometheus_labels("contains_errors" => true)
else
logger.debug("GraphQL query result: #{result}")
set_prometheus_labels("contains_errors" => false)
end
end

def execute_in_read_replica(&block)
if Rails.env.production_replica?
ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do
Expand Down
11 changes: 11 additions & 0 deletions app/graphql/types/edition_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,31 @@ class WhipOrganisation < Types::BaseObject
field :sort_order, Integer
end

field :acronym, String
field :body, String
field :brand, String
field :change_history, GraphQL::Types::JSON
field :change_notes, GraphQL::Types::JSON
field :child_section_groups, GraphQL::Types::JSON
field :current, Boolean
field :default_news_image, Image
field :display_date, Types::ContentApiDatetime
field :emphasised_organisations, GraphQL::Types::JSON
field :end_date, Types::ContentApiDatetime
field :ended_on, Types::ContentApiDatetime
field :first_public_at, Types::ContentApiDatetime
field :image, Image
field :international_delegations, [EditionType], null: false
field :logo, Logo
field :ordered_featured_documents, GraphQL::Types::JSON
field :organisation_govuk_status, GraphQL::Types::JSON
field :political, Boolean
field :privy_counsellor, Boolean
field :reshuffle, GraphQL::Types::JSON
field :role_payment_type, String
field :seniority, Integer
field :social_media_links, GraphQL::Types::JSON
field :start_date, Types::ContentApiDatetime
field :started_on, Types::ContentApiDatetime
field :supports_historical_accounts, Boolean
field :url_override, String
Expand All @@ -170,6 +178,8 @@ class WhipOrganisation < Types::BaseObject

field :active, Boolean, null: false
field :analytics_identifier, String
field :api_path, String
field :api_url, String
field :base_path, String
field :change_history, GraphQL::Types::JSON
field :content_id, ID
Expand Down Expand Up @@ -198,6 +208,7 @@ class WhipOrganisation < Types::BaseObject
field :title, String, null: false
field :updated_at, Types::ContentApiDatetime
field :web_url, String
field :withdrawn, Boolean
field :withdrawn_notice, WithdrawnNotice

def details(lookahead:)
Expand Down
1 change: 1 addition & 0 deletions app/models/edition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def redirect?
def withdrawn?
unpublished? && unpublishing.withdrawal?
end
alias_method :withdrawn, :withdrawn?

def substitute?
unpublished? && unpublishing.substitute?
Expand Down
15 changes: 15 additions & 0 deletions app/queries/graphql/fragments/_available_translations.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fragment AvailableTranslations on Links {
available_translations {
api_path
api_url
base_path
content_id
document_type
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
48 changes: 48 additions & 0 deletions app/queries/graphql/fragments/_child_and_parent_taxons.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
fragment Taxon on Edition {
api_path
api_url
base_path
content_id
description
details {
internal_name
notes_for_editors
visible_to_departmental_editors
}
document_type
locale
phase
public_updated_at
schema_name
title
web_url
withdrawn
}

<%# The deepest nodes in GOV.UK's taxonomy are 5 levels deep (i.e. the root, plus 4 child taxons) %>
<%# For example https://www.gov.uk/api/content/transport/hs2-phase-2b %>
<%# We don't expand the whole taxonomy when looking at the root, so we only need the 4 levels. %>
<%# The first level expands the backlink to parent, but lower levels do not. %>
fragment ChildAndParentTaxons on Links {
child_taxons: links_of_type(type: parent_taxons, reverse: true) {
...Taxon
links {
child_taxons: links_of_type(type: parent_taxons, reverse: true) {
...Taxon
links {
child_taxons: links_of_type(type: parent_taxons, reverse: true) {
...Taxon
links {
child_taxons: links_of_type(type: parent_taxons, reverse: true) {
...Taxon
}
}
}
}
}
parent_taxons: links_of_type(type: parent_taxons) {
...Taxon
}
}
}
}
39 changes: 39 additions & 0 deletions app/queries/graphql/fragments/_children.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<%# TODO: this is used in ~10 places, but they all have different kinds of children so it's not really reusable %>
fragment Children on Links {
children: links_of_type(type: parent, reverse: true) {
api_path
api_url
base_path
content_id
document_type
details {
access_and_opening_times
}
links {
<%#
The back link to parent is here for compatibility with current link-expansion behaviour,
but I'm reasonably sure it's accidental and unnecessary. Why would you want to link from
a document to its child, and then back up to the parent?
%>
parent: links_of_type(type: parent) {
api_path
api_url
base_path
content_id
document_type
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
15 changes: 15 additions & 0 deletions app/queries/graphql/fragments/_content_owners.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fragment ContentOwners on Links {
content_owners: links_of_type(type: content_owners) {
api_path
api_url
base_path
content_id
document_type
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
fragment DefaultTopLevelFields on Edition {
analytics_identifier
base_path
content_id
description
document_type
first_published_at
locale
phase
public_updated_at
publishing_app
publishing_request_id
publishing_scheduled_at
rendering_app
scheduled_publishing_delay_seconds
schema_name
title
updated_at
}
37 changes: 37 additions & 0 deletions app/queries/graphql/fragments/_document_collections.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
fragment DocumentCollections on Links {
document_collections: links_of_type(type: documents, reverse: true) {
api_path
api_url
base_path
content_id
document_type
<%#
Getting all of the documents in a collection would sometimes be prohibitively expensive.
Current link expansion behaviour special cases this so that only the grandparent document
is expanded. Nobody's quite sure why this behaviour is desirable though, so I'm not going
to reimplement it until we know why it's needed.

links {
documents: links_of_type(type: documents) {
api_path
api_url
base_path
content_id
document_type
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
%>
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
17 changes: 17 additions & 0 deletions app/queries/graphql/fragments/_government.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
fragment Government on Links {
government: links_of_type(type: government) {
api_path
api_url
base_path
content_id
details {
current
ended_on
started_on
}
document_type
locale
title
web_url
}
}
37 changes: 37 additions & 0 deletions app/queries/graphql/fragments/_level_one_taxons.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
fragment LevelOneTaxons on Links {
level_one_taxons: links_of_type(type: root_taxon, reverse: true) {
api_path
api_url
base_path
content_id
description
details {
internal_name
notes_for_editors
visible_to_departmental_editors
}
document_type
links {
root_taxon: links_of_type(type: root_taxon) {
api_path
api_url
base_path
content_id
document_type
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
locale
phase
public_updated_at
schema_name
title
web_url
withdrawn
}
}
16 changes: 16 additions & 0 deletions app/queries/graphql/fragments/_mainstream_browse_pages.graphql.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
fragment MainstreamBrowsePages on Links {
mainstream_browse_pages: links_of_type(type: mainstream_browse_pages) {
api_path
api_url
base_path
content_id
description
document_type
locale
public_updated_at
schema_name
title
web_url
withdrawn
}
}
Loading
Loading