Va bene avere più metodi di azione get nel controller ASP .Net Web API in base ai vincoli RESTful API?

6

Ho la seguente interfaccia nel mio livello aziendale

    public interface IUserService
    {
        void CreateUser(User user);
        List<User> FindUsersByName(string searchedString);
        User GetUserById(int userId);
        User GetUserByCredentials(string login, string password);
        void UpdateUser(User user);
        void UpdateUserPassword(int userId, string oldPassword, string newPassword);
    }

Ora voglio fornire API Web per questa interfaccia. Come puoi vedere questa interfaccia ha più get metodi che restituiscono un elemento GetUserById e GetUserByCredentials , ha anche più metodi di aggiornamento UpdateUser e UpdateUserPassword , in futuro potrei voler aggiungere un ulteriore metodo get che ritorna una collezione, ad esempio GetAllUsers , per esempio.

La soluzione ovvia era incapsulare questa funzionalità in un controller. Quindi, cosa ho fatto prima, in WebApiConfig ho cambiato la configurazione dei percorsi in

config.Routes.MapHttpRoute(
                name: "DefaultApi",
                //as you can see I added {action} to the path so that, it will be possible to differentiate between different get/put requests
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            ); 

Poi ho creato un UsersController che assomiglia a questo

public class UsersController : ApiController
    {
        private readonly IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        // POST api/users/createuser
        [HttpPost]
        public IHttpActionResult CreateUser(User user)
        {
            //some code
        }

        // GET api/users/getuserbyid?id=1
        [HttpGet]
        public IHttpActionResult GetUserById(int id)
        {
            //some code
        }

        // GET api/users/getuserbycredentials?login=log&password=pass
        [HttpGet]
        public IHttpActionResult GetUserByCredentials(string login, string password)
        {
            //some code
        }


        // GET api/users/findusersbyname?searchedString=jack
        [HttpGet]
        public IHttpActionResult FindUsersByName(string searchedString)
        {
            //some code
        }

        // PUT api/users/updateuser
        [HttpPut]
        public IHttpActionResult UpdateUser(UserBase user)
        {
            //some code
        }

        // PUT api/users/updateuserpassword?userId=1&oldPassword=123&newPassword=1234
        [HttpPut]
        public IHttpActionResult UpdateUserPassword(int userId, string oldPassword, string newPassword)
        {
            //some code
        }
    }

Come puoi vedere dal codice precedente, ho URI diversi per ogni metodo di azione, ad es. per GetUserById - api/users/getuserbyid?id=1 , per GetUserByCredentials - api/users/getuserbycredentials?login=log&password=pass e così via. Questa soluzione funziona bene finora, ma il problema è che, per quanto ne so, non è possibile avere più risultati secondo REST, quindi questa soluzione è ancora conforme ai vincoli per un servizio RESTful? E se no, come posso renderlo veramente riposante? L'idea di dividere questa interfaccia in controller diversi mi sembra un po 'strana, perché in futuro potrei voler aggiungere alcuni nuovi metodi alla mia interfaccia, ad esempio GetUsersByGender , GetUsersByDateOfBirthday e così via (se sto andando per creare un nuovo controller ogni volta, non mi sembra corretto)

    
posta Mykhailo Seniutovych 16.05.2017 - 20:15
fonte

3 risposte

5

I know you cannot have multiple gets according to REST

Non proprio. REST e la modellazione API sono argomenti diversi. Le API REST sono pensate per essere una strategia di integrazione, basata sulle premesse introdotte da Fielding nella sua tesi di laurea sugli stili architettonici distribuiti. Queste premesse non hanno nulla a che fare con il modo in cui vengono modellate le API, quante risorse, gli URI e la semantica forniamo.

Ad esempio:

/api/users-living-in-courscant
/api/users-not-living-in-courscant
/api/users?q=living:coruscant
/api/users?q=id:12345
/api/user/12345
/api/me

Alcuni degli URI sopra riportati potrebbero riferirsi alle stesse risorse, la differenza principale (e il punto chiave) risiede nella loro semantica rispettiva.

so does this solution still comply with the constraints for a RESTful service?

Secondo me, il tuo approccio è più vicino a un servizio web simile a RPC che a un REST API. Dai un'occhiata all'articolo di Martin Fowler su Richardson Maturity Model .

Se leggiamo attentamente il post di Martin, scopriamo che Martin non sta introducendo tecniche di modellazione API o best practice. Si concentra su come rendere la comunicazione client-server correttamente secondo la semantica HTTP . Come rappresentare e scoprire risorse.

Ma non menziona come identificare queste risorse. Non menziona come modellare gli URI.

And if not how can I make it truly RESTful?

Se rendere l'API totalmente RESTful è la preoccupazione, suggerirei di leggere prima la tesi Fielding. Una volta assimilato il significato di REST, vorrei cercare la documentazione relativa alla modellazione API. Non appena l'ultimo concordato con il primo, dovresti essere sulla buona strada.

Qui 2 link per iniziare a lavorare:

I collegamenti sopra riportati seguono un ordine deliberato. Penso che sia un ordine naturale che va dalle basi ai concetti avanzati. Da zero.

Ho sottolineato la parola convenzioni intenzionalmente. Questi possono essere ignorati o interpretati se li ritieni inadeguati alle tue esigenze.

Ulteriori letture

Se sei interessato all'argomento, ho trovato i seguenti libri perfetti.

  • Regolamento del progetto API : si concentra principalmente sulla modellazione API. Troverai una breve introduzione all'architettura web e ai principi REST.

  • Riposo in pratica : ritengo che questo sia più avanzato. Piuttosto focalizzato sui vantaggi di REST come integrazione rispetto alla modellazione API.

risposta data 16.05.2017 - 23:26
fonte
4

REST non limita il numero di metodi. Puoi usarne quanti ne hai bisogno. L'API e la tua implementazione sono 2 cose diverse. Se vuoi che la tua API segua l'architettura REST, allora si tratta di scambiare risorse. Spetta a te gestire il tuo codice.

Il tuo codice tratta gli utenti. Ma l'URI assomiglia alle azioni, non alle risorse. Prendi in considerazione uno schema come questo:

GET  /users      - returns the collection of users
GET  /users/{id} - return the user with a specific ID
POST /users      - add a user to the collection

searching based on criteria could look like this:
GET  /users?country={country-code}&city={city} 

Questo espone gli utenti a risorse e utilizza i metodi del protocollo HTTP per identificare l'azione da eseguire su queste risorse.

Le persone hanno idee diverse su cosa rende un'API API REST. La maggior parte delle API di cui ho letto o visto negli esempi sono limitate. Non sono esposti su scala web con un gran numero di implementazioni client.

Anche l'uso di tipi MIME espliciti per identificare le risorse trasferite e un modo strutturato per definire i collegamenti tra risorse spesso non è incluso.

Quindi, pensa a cosa vuoi che sia la tua API, una "vera" API REST o qualcosa di più semplice che usi l'URI logico, i metodi HTTP e i codici di risposta HTTP per comunicare.

    
risposta data 17.05.2017 - 00:16
fonte
3

as far as I know you cannot have multiple gets according to REST

No, non proprio. Quello che non puoi avere è stato. Ad esempio, se hai un'API come:

POST /set-current-user/[id]
GET /user-info
GET /user-avatar
POST /change-password

che significa che per ottenere l'immagine del profilo dell'utente, dovresti prima chiamare set-current-user , non sei RESTful.

A parte questo, sei libero di avere quante azioni GET o non GET nel tuo controller, se necessario, dal momento che sei vincoli architettonici , non esiste alcun vincolo che ti dice di non avere più di un'azione per controller.

Inoltre, non posso evitare di evidenziare uno dei tuoi esempi:

GET api/users/getuserbycredentials?login=log&password=pass

Se questo è il percorso effettivo che hai usato, non farlo. Anche con HTTPS (e tu hai per usare HTTPS, dato che stai manipolando qui i dati sensibili degli utenti), questo ha un enorme difetto di sicurezza nell'inviare le password in chiaro nei log del server. Anche se sei assolutamente sicuro che i registri siano crittografati e il traffico dal server delle applicazioni ai registri sia fatto con un protocollo sicuro, il solo fatto di archiviare le password degli utenti in testo semplice è terribile in termini di sicurezza. Non farlo. Mai.

    
risposta data 16.05.2017 - 22:04
fonte

Leggi altre domande sui tag