5

So che ci sono già alcune domande e anche this is a open issue regarding AMS not handling namespaces too efficiently (che viene utilizzato da questo approccio di versioning) ma volevo essere sicuro di essere nella giusta direzione all'interno dei vincoli attuali.Modo corretto per implementare il versioning dell'API con active_model_serializers

In questo momento sto usando Rails 5 e AMS 0.10.1, così ho fatto la seguente:

# config/initializers/active_model_serializer.rb 
ActiveModelSerializers.config.serializer_lookup_enabled = false 

per disabilitare ricerca predefinito serializzatore (che non ha funzionato in ogni caso); e

# app/controllers/application_controller.rb 
class ApplicationController < ActionController::API 
    def get_serializer(resource, options = {}) 
    unless options[:each_serializer] || options[:serializer] then 
     serializer = (self.class.name.gsub("Controller","").singularize + "Serializer").constantize 
     resource.respond_to?(:to_ary) ? options[:each_serializer] = serializer : options[:serializer] = serializer 
    end 
    super(resource, options) 
    end 
end 

per sovrascrivere il modo in cui i serializzatori vengono trovati per impostazione predefinita; i miei controllori e serializzatore sono come questo:

# app/controllers/api/v2/api_controller.rb 
module Api::V2 
    class ApiController < ApplicationController 
    ... 

# app/controllers/api/v2/users_controller.rb 
module Api::V2 
    class UsersController < ApiController 
    ... 

e

# app/serializers/api/v2/user_serializer.rb 
module Api::V2 
    class UserSerializer < ActiveModel::Serializer 
    ...  

Ora, le cose come ActiveModel::Serializer.serializer_for(object) non funziona, quindi ho dovuto anche scimmia Patch My richiesta specifiche utilizzando example.metadata[:api_version] per impostare la versione API prima di ogni test e innalzamento e errore se l'esempio non l'ha impostato.

Quindi:

  1. c'è un modo meglio documentate?
  2. È tutto vicino ad essere corretto?
  3. Avrò problemi con questo approccio?
  4. Come può essere migliorato?

risposta

0

visto che non ho trovato un modo migliore, né documentata né da nessuna parte, ma sembra anche essere corretta e non ho dovuto affrontare problemi dopo un po 'di usarlo, questo appare essere un buon approccio per il versioning delle API.

Ad ogni modo, suggerisco cautela utilizzando questo approccio per non modificare il comportamento delle versioni supportate precedenti per la propria API. Esegui un test accurato e notificalo ai clienti per la rimozione e supporto della rimozione per le versioni precedenti.

5

Penso che quello che hai qui sia okay. Sto usando lo stesso approccio e funziona bene per la mia applicazione. Ho preso l'idea originale qui da Ryan Bates dove ha fatto spiega approccio molto simile

http://railscasts.com/episodes/350-rest-api-versioning

Questo è quello che uso per specificare diversi serializzatori per ogni risorsa:

module API 
    module V3 
    class AssetController < API::V3::ApiController 
     def index 
     render json: assets, status: :ok, each_serializer: API::V3::Serializers::AssetSerializer 
     end 
    end 
end 

Nella mia implementazione Sono utilizzando serializzatori all'interno di api/controller/api/v3/serializzatori. Così si sono versioning classi serializzatori e classi controller

Non sono sicuro che si ha realmente bisogno di avere get_serializer dal momento che questo è più esplicito, ma non un grande affare

Se si dispone di un sacco di endpoint api cercare di organizzarli in risorse . Nel mio config/routes.rb Ho circa 700 risorse così li ho diviso in file separati config/api/v1/routes.rb ...

namespace :api, defaults: {format: 'json'} do 
    namespace :v1 
    resources :assets 
    end 
end 

Inoltre è utile per fare all'interno inflections.rb initializer

Per me direi che il problema più importante è avere una buona copertura di test. Preferisco le specifiche e controllo i codici di stato corretti 200, 201, ...ecc. e l'output figlio corretto utilizzando json_schema

Se è necessario fare auth, suggerirei di utilizzare l'autenticazione basata su token e JWT - Token Web JSON. Nella mia implementazione sto usando due token. Un token per la lettura e un diverso token quando si esegue POST e PATCH (non è sicuro che sia necessario forse). così all'interno del controller API qualcosa di simile

class ApiController < ActionController::Base 
    skip_before_action :verify_authenticity_token, if: :json_request? 
    before_action :authenticate 

    protected 
    def json_request? 
    request.format.json? 
    end 
    if request.headers['X-Authorization'] 
    token = request.headers['X-Authorization'] 
    payload = JWT.decode(token, 'my_custom_key_to_check_if_key_has_been_tempered d_on_client_side')[0] 
    end 
end 
+0

Grazie per l'input! L'ho fatto per ASCIUGARE un po 'le cose. 'get_serializer' è sempre chiamato da AMS e ho solo bisogno di usare' render json: @object, serializer: Namespaced :: Unconventional :: ObjectSerializer' se non segue la convenzione definita. –