Add Deprecation headers on deprecated endpoints ()

Co-authored-by: Damien Mathieu <42@dmathieu.com>
This commit is contained in:
Claire 2025-03-25 13:30:10 +01:00 committed by GitHub
parent 40bb8ec325
commit 38f5e74122
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 121 additions and 12 deletions

View file

@ -1,6 +1,10 @@
# frozen_string_literal: true
class Api::V1::Accounts::IdentityProofsController < Api::BaseController
include DeprecationConcern
deprecate_api '2022-03-30'
before_action :require_user!
before_action :set_account

View file

@ -1,6 +1,10 @@
# frozen_string_literal: true
class Api::V1::FiltersController < Api::BaseController
include DeprecationConcern
deprecate_api '2022-11-14'
before_action -> { doorkeeper_authorize! :read, :'read:filters' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write, :'write:filters' }, except: [:index, :show]
before_action :require_user!

View file

@ -1,15 +1,9 @@
# frozen_string_literal: true
class Api::V1::InstancesController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :limited_federation_mode?
skip_around_action :set_locale
class Api::V1::InstancesController < Api::V2::InstancesController
include DeprecationConcern
vary_by ''
# Override `current_user` to avoid reading session cookies unless in limited federation mode
def current_user
super if limited_federation_mode?
end
deprecate_api '2022-11-14'
def show
cache_even_if_authenticated!

View file

@ -2,6 +2,9 @@
class Api::V1::SuggestionsController < Api::BaseController
include Authorization
include DeprecationConcern
deprecate_api '2021-05-16'
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, except: :index

View file

@ -1,12 +1,16 @@
# frozen_string_literal: true
class Api::V1::Trends::TagsController < Api::BaseController
include DeprecationConcern
before_action :set_tags
after_action :insert_pagination_headers
DEFAULT_TAGS_LIMIT = 10
deprecate_api '2022-03-30', only: :index, if: -> { request.path == '/api/v1/trends' }
def index
cache_if_unauthenticated!
render json: @tags, each_serializer: REST::TagSerializer, relationships: TagRelationshipsPresenter.new(@tags, current_user&.account_id)

View file

@ -1,6 +1,16 @@
# frozen_string_literal: true
class Api::V2::InstancesController < Api::V1::InstancesController
class Api::V2::InstancesController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :limited_federation_mode?
skip_around_action :set_locale
vary_by ''
# Override `current_user` to avoid reading session cookies unless in limited federation mode
def current_user
super if limited_federation_mode?
end
def show
cache_even_if_authenticated!
render_with_cache json: InstancePresenter.new, serializer: REST::InstanceSerializer, root: 'instance'

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
module DeprecationConcern
extend ActiveSupport::Concern
class_methods do
def deprecate_api(date, sunset: nil, **kwargs)
deprecation_timestamp = "@#{date.to_datetime.to_i}"
sunset = sunset&.to_date&.httpdate
before_action(**kwargs) do
response.headers['Deprecation'] = deprecation_timestamp
response.headers['Sunset'] = sunset if sunset
end
end
end
end

View file

@ -1,4 +1,9 @@
import type { AxiosResponse, Method, RawAxiosRequestHeaders } from 'axios';
import type {
AxiosError,
AxiosResponse,
Method,
RawAxiosRequestHeaders,
} from 'axios';
import axios from 'axios';
import LinkHeader from 'http-link-header';
@ -41,7 +46,7 @@ const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => {
// eslint-disable-next-line import/no-default-export
export default function api(withAuthorization = true) {
return axios.create({
const instance = axios.create({
transitional: {
clarifyTimeoutError: true,
},
@ -60,6 +65,22 @@ export default function api(withAuthorization = true) {
},
],
});
instance.interceptors.response.use(
(response: AxiosResponse) => {
if (response.headers.deprecation) {
console.warn(
`Deprecated request: ${response.config.method} ${response.config.url}`,
);
}
return response;
},
(error: AxiosError) => {
return Promise.reject(error);
},
);
return instance;
}
type RequestParamsOrData = Record<string, unknown>;

View file

@ -15,6 +15,8 @@ RSpec.describe 'API V1 Trends Tags' do
.and not_have_http_link_header
expect(response.content_type)
.to start_with('application/json')
expect(response.headers['Deprecation'])
.to be_nil
end
end
@ -31,6 +33,8 @@ RSpec.describe 'API V1 Trends Tags' do
.and have_http_link_header(api_v1_trends_tags_url(offset: 2)).for(rel: 'next')
expect(response.content_type)
.to start_with('application/json')
expect(response.headers['Deprecation'])
.to be_nil
end
def prepare_trends

View file

@ -0,0 +1,48 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'deprecated API V1 Trends Tags' do
describe 'GET /api/v1/trends' do
context 'when trends are disabled' do
before { Setting.trends = false }
it 'returns http success' do
get '/api/v1/trends'
expect(response)
.to have_http_status(200)
.and not_have_http_link_header
expect(response.content_type)
.to start_with('application/json')
expect(response.headers['Deprecation'])
.to start_with '@'
end
end
context 'when trends are enabled' do
before { Setting.trends = true }
it 'returns http success' do
prepare_trends
stub_const('Api::V1::Trends::TagsController::DEFAULT_TAGS_LIMIT', 2)
get '/api/v1/trends'
expect(response)
.to have_http_status(200)
.and have_http_link_header(api_v1_trends_tags_url(offset: 2)).for(rel: 'next')
expect(response.content_type)
.to start_with('application/json')
expect(response.headers['Deprecation'])
.to start_with '@'
end
def prepare_trends
Fabricate.times(3, :tag, trendable: true).each do |tag|
2.times { |i| Trends.tags.add(tag, i) }
end
Trends::Tags.new(threshold: 1).refresh
end
end
end
end