tesla ⚡️로 sparql ✨ 클라이언트 미들웨어 사용자 지정

Tesla 은 잘 구조화되었지만 강력한 http 클라이언트를 작성하는 것을 매우 간단하게 만드는 훌륭한 엘릭서 라이브러리입니다. Tesla를 특히 사용하기 좋게 만드는 한 가지 기능은 플러그 기반 미들웨어입니다. Phoenix.Router 과 유사하게 한 줄 plug Tesla.Middleware.JSON 을 넣으면 클라이언트가 요청 및 응답 본문의 인코딩 및 디코딩을 자동으로 처리합니다.

Tesla는 바로 사용할 수 있는 다양한 미들웨어와 함께 제공됩니다. adding headers 또는 setting a base url for all requests . 포함된 미들웨어는 매우 편리하지만 어느 시점에서 더 맞춤화된 것을 원할 가능성이 있습니다. 다행히 사용자 정의 미들웨어를 생성하여 기존 Tesla 클라이언트에 연결할 수 있습니다.

제 경우에는 쿼리 매개변수 및 응답 본문과 함께 요청을 저장하기 위해 데이터베이스 지원 로그가 필요했습니다. 공식 Tesla 문서에는 an example for custom middlewares이 포함되어 있지만 제대로 실행하려면 몇 번 시도해야 했습니다. 그래서 테슬라와 함께하는 맞춤형 미들웨어에 대한 저의 견해입니다 💫

wikidata SPARQL query api을 쿼리하는 이 간단한 클라이언트부터 시작합니다.

defmodule Wikidata.Client do
  use Tesla

  plug Tesla.Middleware.BaseUrl, "https://query.wikidata.org"
  plug Tesla.Middleware.Headers, [{"accept", "application/sparql-results+json"}]
  plug Wikidata.SaveClientResponse

  @foods_query File.read!("lib/wikidata/queries/foods.sparql")

  defp get_response() do
    with {:ok, response} <- get("/sparql", query: [query: @foods_query]) do
      {:ok, unpack_response(response.body)}
    else
      {:error, :timeout} ->
        {:error, :wikidata_client_timeout}
      error ->
        {:error, :wikidata_client_error, error}
    end
  end

  defp unpack_response(body) do
    body
    |> Jason.decode!(keys: :atoms)
    |> Map.get(:results)
    |> Map.get(:bindings)
  end
end


해당 부분에 관심이 없다면 모든 wikidata/sparql 관련 항목을 무시하십시오. 예제에 약간의 관련성을 제공하기 위해 포함했습니다(관심 있는 경우 실제 sparql 요청에 대한 게시물의 끝 부분을 확인하십시오). .

라인plug Wikidata.SaveClientResponse은 Tesla 미들웨어 파이프라인에 사용자 정의 모듈을 추가합니다. 사용자 지정 미들웨어는 다음 사양으로 호출 함수를 구현하는 모듈만큼 간단한 Tesla.Middleware behaviour을 구현해야 합니다.

@spec call(env :: Tesla.Env.t(), next :: Tesla.Env.stack(), options :: any()) :: Tesla.Env.result()


요청 데이터를 저장하기 위해 간단한 ecto 스키마ClientRequest를 사용합니다.

defmodule Wikidata.ClientRequest do
  use Ecto.Schema
  import Ecto.Changeset

  schema "wikidata_client_requests" do
    field :query, :string
    field :response_body, :string

    timestamps()
  end

  def create_changeset(attrs) do
    %__MODULE__{}
    |> cast(attrs, [:query, :response_body])
  end
end


마지막으로 요청을 가로채서 데이터베이스에 ClientRequest 로 저장하는 실제 미들웨어 구현은 다음과 같습니다.

defmodule Wikidata.SaveClientResponse do
  @behaviour Tesla.Middleware

  alias Wikidata.ClientRequest

  @impl Tesla.Middleware
  def call(env, next, _options) do
    with {:ok, env} <- Tesla.run(env, next) do
      save_request_data(env)

      {:ok, env}
    else
      result -> result
    end
  end

  defp save_request_data(%{query: [query: query], body: body}) do
    %{query: query, response_body: body}
    |> ClientRequest.create_changeset()
    |> Repo.insert()
  end
end
  defp save_request_data(_), do: nil


이 간단한 미들웨어는 각 성공적인 요청에 대해 새ClientRequest를 저장합니다. 여기에는 query라는 쿼리 매개변수가 포함되고 본문과 함께 반환되며 클라이언트의 다른 모든 요청(예: 시간 초과 요청 또는 모든 요청)을 처리합니다. query 매개변수를 포함하지 않음). 기본 서빙 제안이니 입맛에 맞게 조절해주세요🍲
즉. 요청을 보내기 전에 쿼리 매개변수에 액세스하고 싶습니까? 그런 다음 env에 전화하기 전에 Tesla.run/2에 액세스(또는 변경)해야 합니다.

[1] 실제 사용 사례에 관심이 있는 경우 설명, 사진 및 관련 음식 클래스 또는 인스턴스와 함께 모든 음식/음식 재료를 가져오는 wikidata sparql 쿼리는 다음과 같습니다.

SELECT ?item ?itemLabel ?itemDescription ?imageUrl ?instanceOf
WHERE
{
  ?item wdt:P31*/wdt:P279* wd:Q25403900.
  OPTIONAL { ?item wdt:P18 ?imageUrl }
  OPTIONAL { ?item wdt:P31 ?instanceOf }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

좋은 웹페이지 즐겨찾기