Lendo o endpoint de Comics

A Marvel API nos disponibiliza alguns recursos legais, como obter personagens, historias em quadrinho, eventos, séries, entre outros.

Para ver todos os endpoints, só acessar o link da documentação e teremos ali uma lista completa dos recursos e como devemos montar nossas requisições.

Em nosso estudo, utilizarei a listagem de Comics (revistas em quadrinhos)

Vamos extrair as informações para conseguir realizar a requisição igual como fizemos em nosso serviço de cafés quentes.

Olhando apenas o básico temos essa estrutura

GET https://<url_base>/v1/public/comics

Temos aqui

Verbo

GET

Recurso

/v1/public/comics

URL base

?

Mas esta faltando a URL base de nossa requisição. Para essa informação, podemos acessar o General API Information. e veremos que nossa base é https://gateway.marvel.com/

Verbo

GET

Recurso

/v1/public/comics

URL base

https://gateway.marvel.com

Podemos agora montar nossa requisição e testala com o Tesla.

GET https://gateway.marvel.com/v1/public/comics

Convertendo

Tesla.get("https://gateway.marvel.com/v1/public/comics")

Podemos acessar nosso terminal iterativo e testar a requisição

iex -S mix   
Tesla.get("https://gateway.marvel.com/v1/public/comics")
iex(1)> Tesla.get("https://gateway.marvel.com/v1/public/comics")
{:ok,
 %Tesla.Env{
   method: :get,
   url: "https://gateway.marvel.com/v1/public/comics",
   query: [],
   headers: [
     {"connection", "keep-alive"},
     {"date", "Wed, 08 May 2024 17:57:08 GMT"},
     {"content-length", "68"},
     {"content-type", "application/json; charset=utf-8"}
   ],
   body: "{\"code\":\"MissingParameter\",\"message\":\"You must provide a user key.\"}",
   status: 409,
   opts: [],
   __module__: Tesla,
   __client__: %Tesla.Client{fun: nil, pre: [], post: [], adapter: nil}
 }}

Aqui temos nosso primeiro problema. Mesmo a API sendo publica, temos controle de quem está acessando. Nesse caso ele avisa que precisamos de um chave de usuário. E foi para isso que criamos uma conta na Marvel.

Acesse sua conta de desenvolvedor e iremos encontrar a chave necessária. Sua API Key é sua chave pública. Marquei de amarelo.

Vou nomear a minha como 12345, para facilitar o entendimento.

Verbo

GET

Recurso

/v1/public/comics

URL base

https://gateway.marvel.com

Api Key

12345

Vamos atualizar nossa chamada com o Tesla. Para passar esse dado, utilizaremos query params.

Tesla.get("https://gateway.marvel.com/v1/public/comics?apikey=12345")
iex(3)> Tesla.get("https://gateway.marvel.com/v1/public/comics?apikey=d3f934e3c9ccb6de467674e4fc7a3ead")
{:ok,
 %Tesla.Env{
   method: :get,
   url: "https://gateway.marvel.com/v1/public/comics?apikey=d3f934e3c9ccb6de467674e4fc7a3ead",
   query: [],
   headers: [
     {"connection", "keep-alive"},
     {"date", "Wed, 08 May 2024 18:06:59 GMT"},
     {"content-length", "64"},
     {"content-type", "application/json; charset=utf-8"}
   ],
   body: "{\"code\":\"MissingParameter\",\"message\":\"You must provide a hash.\"}",
   status: 409,
   opts: [],
   __module__: Tesla,
   __client__: %Tesla.Client{fun: nil, pre: [], post: [], adapter: nil}
 }}

Passamos do problema da user key. Mas caímos agora no problema do hash.

O hash na API da Marvel é uma encriptação simples usando MD5 que utiliza os dados

NomeDescrição

TS

Uma string que servirá para termos unicidade nas requisições. Cada requisição deve ter um valor diferente.

Chave Publica

Que chamamos acima de api key

Chave privada

Uma chave extra para realizar a decrypt. Basicamente, a chave para abrir.

As chaves encontramos na conta de de desenvolvedor.

Marquei em amarelo a publica e rosa a privada.

Utilizaremos como TS, por hora, o numero 1. Simplesmente para seguir com os estudos.

Como chave privada, demonstrarei como 88888.

A regra para o hash é:

<TS>+<chave_privada>+<chave_publica>

Podemos criar isso pelo elixir, entrando no modo iterativo

:crypto.hash(:md5, "11234588888") |> Base.encode16()
iex(1)> :crypto.hash(:md5, "11234588888") |> Base.encode16()
"7EE341DFFE88E697114117AA51E1A210"

Vamos agora pegar esse valor e adicionar a nossa query param. Também devemos colocar o valor de TS em nosso query o mesmo informado na criação do hash.

Tesla.get("https://gateway.marvel.com/v1/public/comics?apikey=12345&hash=7EE341DFFE88E697114117AA51E1A210&ts=1")
iex(1)> Tesla.get("https://gateway.marvel.com/v1/public/comics?apikey=12345&hash=7EE341DFFE88E697114117AA51E1A210&ts=1")
{:ok,
 %Tesla.Env{
   method: :get,
   url: "https://gateway.marvel.com/v1/public/comics?apikey=d3f934e3c9ccb6de467674e4fc7a3ead&ts=1&hash=1d49870a0631827587878fcff98fa267",
   query: [],
   headers: [
     {"connection", "keep-alive"},
     {"date", "Wed, 08 May 2024 18:21:51 GMT"},
     {"etag", "60ddd4a67c6e3242fa2560dbb0035b3925d666ef"},
     {"content-length", "66553"},
     {"content-type", "application/json; charset=utf-8"}
   ],
   body: "{\"code\":200,\"status\":\"Ok\",\"copyright\":\"© 2024 MARVEL\",\"attributionText\":\"Data provided by Marvel. © 2024 MARVEL\",\"attributionHTML\":\"<a href=\\\"http://marvel.com\\\">Data provided by Marvel. © 2024 MARVEL</a>\",\"etag\":\"60ddd4a67c6e3242fa2560dbb0035b3925d666ef\",\"data\":{\"offset\":0,\"limit\":20,\"total\":60239,\"count\":20,\"results\":[{\"id\":82967,\"digitalId\":0,\"title\":\"Marvel Previews (2017)\",\"issueNumber\":0,\"variantDescription\":\"\",\"description\":\"\",\"modified\":\"2019-11-07T08:46:15-0500\",\"isbn\":\"\",\"upc\":\"75960608839302811\",\"diamondCode\":\"\",\"ean\":\"\",\"issn\":\"\",\"format\":\"\",\"pageCount\":112,\"textObjects\":[],\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/82967\",\"urls\":[{\"type\":\"detail\",\"url\":\"http://marvel.com/comics/issue/82967/marvel_previews_2017?utm_campaign=apiRef&utm_source=25a07f7adccf7328d3153451c26bd992\"}],\"series\":{\"resourceURI\":\"http://gateway.marvel.com/v1/public/series/23665\",\"name\":\"Marvel Previews (2017 - Present)\"},\"variants\":[{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/82965\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/82970\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/82969\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/74697\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/72736\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/75668\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/65364\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/65158\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/65028\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/75662\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/74320\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/73776\",\"name\":\"Marvel Previews (2017)\"}],\"collections\":[],\"collectedIssues\":[],\"dates\":[{\"type\":\"onsaleDate\",\"date\":\"2099-10-30T00:00:00-0500\"},{\"type\":\"focDate\",\"date\":\"2019-10-07T00:00:00-0400\"}],\"prices\":[{\"type\":\"printPrice\",\"price\":0}],\"thumbnail\":{\"path\":\"http://i.annihil.us/u/prod/marvel/i/mg/b/40/image_not_available\",\"extension\":\"jpg\"},\"images\":[],\"creators\":{\"available\":1,\"collectionURI\":\"http://gateway.marvel.com/v1/public/comics/82967/creators\",\"items\":[{\"resourceURI\":\"http://gateway.marvel.com/v1/public/creators/10021\",\"name\":\"Jim Nausedas\",\"role\":\"editor\"}],\"returned\":1},\"characters\":{\"available\":0,\"collectionURI\":\"http://gateway.marvel.com/v1/public/comics/82967/characters\",\"items\":[],\"returned\":0},\"stories\":{\"available\":2,\"collectionURI\":\"http://gateway.marvel.com/v1/public/comics/82967/stories\",\"items\":[{\"resourceURI\":\"http://gateway.marvel.com/v1/public/stories/183698\",\"name\":\"cover from Marvel Previews (2017)\",\"type\":\"cover\"},{\"resourceURI\":\"http://gateway.marvel.com/v1/public/stories/183699\",\"name\":\"story from Marvel Previews (2017)\",\"type\":\"interiorStory\"}],\"returned\":2},\"events\":{\"available\":0,\"collectionURI\":\"http://gateway.marvel.com/v1/public/comics/82967/events\",\"items\":[],\"returned\":0}},{\"id\":82965,\"digitalId\":0,\"title\":\"Marvel Previews (2017)\",\"issueNumber\":0,\"variantDescription\":\"\",\"description\":\"\",\"modified\":\"2019-08-21T17:11:27-0400\",\"isbn\":\"\",\"upc\":\"75960608839302611\",\"diamondCode\":\"JUL190068\",\"ean\":\"\",\"issn\":\"\",\"format\":\"\",\"pageCount\":152,\"textObjects\":[],\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/82965\",\"urls\":[{\"type\":\"detail\",\"url\":\"http://marvel.com/comics/issue/82965/marvel_previews_2017?utm_campaign=apiRef&utm_source=25a07f7adccf7328d3153451c26bd992\"}],\"series\":{\"resourceURI\":\"http://gateway.marvel.com/v1/public/series/23665\",\"name\":\"Marvel Previews (2017 - Present)\"},\"variants\":[{\"resourceURI\":\"http://gateway.marvel.com/v1/public/comics/82967\",\"name\":\"Marvel Previews (2017)\"},{\"resourceURI\":\"http://gateway.marvel.co" <> ...,
   status: 200,
   opts: [],
   __module__: Tesla,
   __client__: %Tesla.Client{fun: nil, pre: [], post: [], adapter: nil}
 }}

Pronto, estamos com todo acesso necessário para utilizar a API da Marvel. Bora escrever nosso cliente.

Atualizado