From 22b1dd3232aec6ea1faeeffd5aa8293967697696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Norl=C3=A9n?= Date: Fri, 10 Feb 2023 12:21:18 +0100 Subject: [PATCH] Add support for extra_fields query parameter Api now supports optional fields. These are included with the extra_fields query param. Syntax: extra_fields[type]=field1,field2 --- app/controllers/api/v1/base_controller.rb | 4 +- app/controllers/concerns/extra_fields.rb | 32 ++++++++++ config/locales/en.yml | 5 ++ .../controllers/concerns/extra_fields_spec.rb | 60 +++++++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 app/controllers/concerns/extra_fields.rb create mode 100644 spec/controllers/concerns/extra_fields_spec.rb diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index e01fe3aab3..cc62b6978f 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -106,7 +106,9 @@ module Api end def json_api_error(message, **options) - { errors: [{ detail: message }] }.merge(options) + error_options = options.delete(:error_options) || {} + + { errors: [{ detail: message }.merge(error_options)] }.merge(options) end def json_api_invalid(message, errors) diff --git a/app/controllers/concerns/extra_fields.rb b/app/controllers/concerns/extra_fields.rb new file mode 100644 index 0000000000..058e986a13 --- /dev/null +++ b/app/controllers/concerns/extra_fields.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# To be included in api controllers for handeling query params +module ExtraFields + extend ActiveSupport::Concern + + def invalid_query_param(name, status, msg) + render status: status, json: json_api_error(msg, error_options: + { + title: I18n.t("api.query_param.error.title"), + source: { parameter: name }, + status: status, + code: Rack::Utils::SYMBOL_TO_STATUS_CODE[status] + }) + end + + def extra_fields(type, available_fields) + fields = params.dig(:extra_fields, type)&.split(',')&.compact&.map(&:to_sym) + return [] if fields.blank? + + unknown_fields = fields - available_fields + + if unknown_fields.present? + invalid_query_param( + "extra_fields[#{type}]", :unprocessable_entity, + I18n.t("api.query_param.error.extra_fields", fields: unknown_fields.join(', ')) + ) + end + + fields + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 019042608e..0b0b7f4c6e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1599,6 +1599,11 @@ en: destroy_attachment_does_not_exist: "Terms and Conditions file does not exist" orders: failed_to_update: "Failed to update order" + query_param: + error: + title: Invalid query parameter + extra_fields: "Unsupported fields: %{fields}" + # Frontend views # diff --git a/spec/controllers/concerns/extra_fields_spec.rb b/spec/controllers/concerns/extra_fields_spec.rb new file mode 100644 index 0000000000..463427926b --- /dev/null +++ b/spec/controllers/concerns/extra_fields_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ExtraFields do + let(:dummy_controller) { Api::V1::BaseController.new.extend ExtraFields } + + describe "#invalid_query_param" do + it "renders error" do + allow(dummy_controller).to receive(:render) {} + dummy_controller.invalid_query_param("param", :unprocessable_entity, "error message") + expect(dummy_controller).to have_received(:render).with( + json: + { + errors: + [{ + code: 422, + detail: "error message", + source: { parameter: "param" }, + status: :unprocessable_entity, + title: "Invalid query parameter" + }] + }, + status: :unprocessable_entity + ) + end + end + + describe "#extra_fields" do + context "when fields present and available" do + it "returns extra fields" do + allow(dummy_controller).to receive(:params). + and_return({ extra_fields: { customer: "balance" } }) + expect(dummy_controller.extra_fields(:customer, [:balance])).to eq([:balance]) + end + end + + context "when fields missing" do + it "returns empty arr" do + allow(dummy_controller).to receive(:params).and_return({}) + expect(dummy_controller.extra_fields(:customer, [:balance])).to eq([]) + end + end + + context "when fields not in available fields" do + it "calls invalid_query_param" do + allow(dummy_controller).to receive(:invalid_query_param) {} + allow(dummy_controller).to receive(:params). + and_return({ extra_fields: { customer: "unknown" } }) + dummy_controller.extra_fields(:customer, [:balance]) + + expect(dummy_controller).to have_received(:invalid_query_param).with( + "extra_fields[customer]", + :unprocessable_entity, + "Unsupported fields: unknown" + ) + end + end + end +end