Como construir uma API REST que leva uma série de ids para os recursos

103

Estou construindo uma API REST para meu projeto. A API para obter as INFORMAÇÕES de um determinado usuário é:

api.com/users/[USER-ID]

Também gostaria de permitir que o cliente passe uma lista de IDs de usuário. Como posso construir a API de modo que seja RESTful e tenha uma lista de IDs de usuário?

uclajatt
fonte
A resposta mais genérica é dada por @Shuja, porque outras respostas do carteiro não funcionaram e dependem do backend do banco de dados. No entanto, você pode ter um ponto de extremidade de API para solicitar vários IDs.
Eswar

Respostas:

97

Se você estiver passando todos os seus parâmetros no URL, provavelmente valores separados por vírgulas seriam a melhor escolha. Então você teria um modelo de URL como o seguinte:

api.com/users?id=id1,id2,id3,id4,id5
Florin Dumitrescu
fonte
7
@uclajatt, REST é um modelo de arquitetura e não um protocolo e se você estudar as principais APIs REST disponíveis hoje, verá que existem várias maneiras de implementá-lo. A abordagem que estou sugerindo é provavelmente uma das mais próximas do conceito, já que cumpre todas as restrições descritas aqui: en.wikipedia.org/wiki/… . Você só usaria CSV para representar matrizes em solicitações, enquanto as respostas de serviço deveriam ser serializadas usando XML ou JSON. Há algum motivo específico pelo qual você não considera minha abordagem REST?
Florin Dumitrescu
10
Por que não isso? api.com/users?id=id1&id=id2&id=id3&id=id4&id=id5
senfo
7
@senfo, prefiro id = id1, id2, id3 porque torna o URI mais curto e fácil de ler (por um ser humano, durante uma operação de depuração, por exemplo). Parâmetros individuais para cada valor tornariam o URI especialmente mais difícil de seguir se houver outros parâmetros entre os ids: api.com/users?id=id1&id=id2&joined-after=2013-01-01&id=id3
Florin Dumitrescu
12
No entanto, a maioria dos servidores web suporta o comprimento de URL de cerca de 2.000 bytes. Como fazer minha API suportar até 5.000 ids?
nicky_zs
6
@senfo Em URLs como …?id=1&id=2&id=3, não há garantia de que parâmetros de consulta duplicados serão combinados em um array. Com a string de consulta acima, o PHP diz que idé igual [1, 2, 3], mas Ruby on Rails diz que é igual 3, e outras estruturas também podem agir de forma diferente, por exemplo, dizer idigual 1. URLs como …?id=1,2,3evitam esse potencial de confusão.
Rory O'Kane de
33
 api.com/users?id=id1,id2,id3,id4,id5
 api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

IMO, as chamadas acima não parecem RESTful, no entanto, essas são soluções alternativas rápidas e eficientes (y). Mas o comprimento da URL é limitado pelo servidor da web, por exemplo, tomcat .

Tentativa RESTful:

POST http://example.com/api/batchtask

   [
    {
      method : "GET",
      headers : [..],
      url : "/users/id1"
    },
    {
      method : "GET",
      headers : [..],
      url : "/users/id2"
    }
   ]

O servidor responderá ao URI do recurso batchtask recém-criado .

201 Created
Location: "http://example.com/api/batchtask/1254"

Agora o cliente pode buscar a resposta em lote ou o progresso da tarefa por meio de sondagem

GET http://example.com/api/batchtask/1254


Esta é a forma como outras pessoas tentaram resolver este problema:

Nilesh
fonte
7
A solicitação POST para obter vários resultados não é RESTful. Seu exemplo mostra a criação de um recurso, onde é apropriado para POST, mas esse é um caso totalmente diferente da pergunta original
Anentrópico
2
Criar recurso temporário é RESTful, não é? E estou obtendo recursos usando GET, novamente RESTful.
Nilesh
sim, mas nada disso estava na pergunta original, que apenas pergunta sobre como obter informações para vários IDs de usuário
Anentrópico
1
Obrigado @Anentropic por apontar. Eu li a pergunta novamente, ele pergunta como construir uma API REST que leva uma matriz de id para os recursos? e eu concordo, minha resposta é diferente. Desculpe por não entender seu ponto.
Nilesh
Gosto dessa resposta, pois a maneira RESTful de obter vários usuários é por meio desse mecanismo.
Shane Courtrille
20

Encontro outra maneira de fazer a mesma coisa usando @PathParam. Aqui está o exemplo de código.

@GET
@Path("data/xml/{Ids}")
@Produces("application/xml")
public Object getData(@PathParam("zrssIds") String Ids)
{
  System.out.println("zrssIds = " + Ids);
  //Here you need to use String tokenizer to make the array from the string.
}

Ligue para o serviço usando o seguinte url.

http://localhost:8080/MyServices/resources/cm/data/xml/12,13,56,76

Onde

http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76
Shuja
fonte
5
Eu gosto deste porque o GET é consistente. Você pode usar um número ou muitos neste exemplo. E não é realmente uma pesquisa (parâmetros), já que você está fornecendo ao backend os ids exatos que deseja.
markthegrea
1
Vejo que a resposta mais votada não funciona e sua resposta é provavelmente a mais genérica. Deve ser aceita como resposta.
Eswar
18

Por mais que eu prefira essa abordagem: -

    api.com/users?id=id1,id2,id3,id4,id5

A maneira correta é

    api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

ou

    api.com/users?ids=id1&ids=id2&ids=id3&ids=id4&ids=id5

É assim que o rack faz. É assim que o php faz. É assim que o node também faz ...

Kyristopher
fonte
19
Não tenho certeza se referenciar os padrões do PHP como uma diretriz a seguir seja o melhor conselho. eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design
trebor
Não é assim que o Flask faz.
jscul
0

Você pode construir uma API Rest ou um projeto restful usando ASP.NET MVC e retornar dados como JSON. Um exemplo de função de controlador seria:

        public JsonpResult GetUsers(string userIds)
        {
           var values = JsonConvert.DeserializeObject<List<int>>(userIds);

            var users = _userRepository.GetAllUsersByIds(userIds);

            var collection = users.Select(user => new { id = user.Id, fullname = user.FirstName +" "+ user.LastName });
            var result = new { users = collection };

            return this.Jsonp(result);
        }
        public IQueryable<User> GetAllUsersByIds(List<int> ids)
        {
            return _db.Users.Where(c=> ids.Contains(c.Id));
        }

Em seguida, basta chamar a função GetUsers por meio de uma função AJAX regular fornecendo o array de Ids (neste caso, estou usando o jQuery stringify para enviar o array como string e desmaterializá-lo de volta no controlador, mas você pode apenas enviar o array de ints e receber como uma matriz de int no controlador). Eu construí uma API Restful inteira usando ASP.NET MVC que retorna os dados como json de domínio cruzado e que pode ser usada a partir de qualquer aplicativo. Isso, claro, se você puder usar a ASP.NET MVC.

function GetUsers()
    {
           var link = '<%= ResolveUrl("~")%>users?callback=?';
           var userIds = [];
            $('#multiselect :selected').each(function (i, selected) {
                userIds[i] = $(selected).val();
            });

            $.ajax({
                url: link,
                traditional: true,
                data: { 'userIds': JSON.stringify(userIds) },
                dataType: "jsonp",
                jsonpCallback: "refreshUsers"
            });
    }
Vasile Laur
fonte
3
Desculpe, eu não estava perguntando como implementar a API. Eu estava perguntando como construir o URI da API para que o cliente possa acessar informações sobre uma matriz de usuários. Posso passar id's via parâmetros de consulta, mas acredito que não será muito tranquilo.
uclajatt
@uclajatt Por que você acha que não é RESTful?
Darrel Miller
1
Acredito que passar ids ou quaisquer outros valores por meio de parâmetros de consulta é realmente uma abordagem tranquila de interação com um sistema. Como você constrói seu Uri é com você. Seja usuários / todos, usuários / matriz, matriz / usuários ou qualquer outra convenção de nomenclatura que você sinta que faz sentido. Levando em consideração como o framework MVC funciona, é muito fácil usá-lo para construir uma API repousante, já que você pode organizar e construir seus Uris conforme necessário. Uma vez que você tenha seu Uris, você pode passar parâmetros usando AJAX como uma string, ou como valores múltiplos se você estiver usando um formulário e postando em uma ação MVC.
Vasile Laur
1
@uclajatt Já foi duas vezes perguntado a você neste post por que você acha que passar uma lista separada por vírgulas em um parâmetro de consulta não é RESTful e você nem se preocupa em responder, muito menos aceitar qualquer uma dessas soluções muito plausíveis !? ! Não é legal.
samis