Tornex.SpecQuery (Tornex v0.5.1)

Copy Markdown View Source

The query struct containing API request data for API v2 requests.

The Tornex.SpecQuery struct works against the OpenAPI specification for the Torn API v2. Tornex.SpecQuery can be used by Tornex.API.get/1 and Tornex.Scheduler.Bucket.enqueue/1 to make API calls. The struct stores the required information to perform the API call. To use APIv2 calls with the OpenAPI specification and an autogenerated client, you will need to add the Tornium/torngen_elixir_client library to your dependencies; this library includes the paths and schemas required to make and parse APIv2 calls. Alternatively, to make APIv2 calls without the OpenAPI specification, use Tornex.Query instead and prepend the resource with v2/ (e.g. v2/user).

Preparing Query

Create an empty query using new/0. Use put_path/2 and put_parameter!/3 to set up the query.

iex> query =
...>   Tornex.SpecQuery.new(nice: 0)
...>   |> Tornex.SpecQuery.put_key("foo")
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Bounties)
...>   |> Tornex.SpecQuery.put_parameter!(:id, 2383326)

Making Query

The SpecQuery can be executed using Tornex.API.get/1 and Tornex.Scheduler.Bucket.enqueue/1 to perform the API calls. Once the API call has been finished, the response can be parsed into schema structs and validated using parse/2.

iex> api_response = Tornex.API.get(query)
iex> parsed_response = Tornex.SpecQuery.parse(query, api_response)

Summary

Types

Path or query parameters following the paths provided to the Tornex.SpecQuery.

The fallback value for the ID of the resource.

t()

Functions

Get the base path of the query.

Merge a SpecQuery into another SpecQuery.

Initialize an empty query against the OpenAPI specification.

Parse the response of an API call against the query into schema structs.

Parse a SpecQuery to determine the base path and selections.

Add an API key to the query.

Add the owner of the API key to the query.

Add an OpenAPI parameter to the query.

Add an OpenAPI parameter to the query.

Add an OpenAPI path to the query.

Get the resource for the paths used in the query.

Get the resource ID used in the query.

Get a list of selections used in the query.

Generate and validate a URI to perform the Tornex.SpecQuery.

Types

niceness()

@type niceness() :: -20..20

parameter()

@type parameter() :: {atom(), term()}

Path or query parameters following the paths provided to the Tornex.SpecQuery.

The parameter should be of the form {:parameter_key, parameter_value}. For example, for the {crimeId} path parameter in Torngen.Client.Path.Torn.CrimeId.Subcrimes would be {:crimeId, 1} to list the subcrimes of Search for Cash.

resource_id()

@type resource_id() :: {atom(), term()} | nil

The fallback value for the ID of the resource.

This only needs to be set to {:parameter_key, parameter_value} when Tornex.Scheduler.Bucket.enqueue/1 is used. For example, Torngen.Client.User.Equipment would have a :resource_id of {:id, 2_383_326}.

t()

@type t() :: %Tornex.SpecQuery{
  key: String.t() | nil,
  key_owner: non_neg_integer(),
  nice: niceness(),
  origin: GenServer.from() | nil,
  parameters: [parameter()],
  paths: [module()],
  quarantine?: boolean(),
  resource_id: resource_id()
}

Functions

base_path!(query)

@spec base_path!(query :: t()) :: String.t()

Get the base path of the query.

merge(query, acc)

@spec merge(query :: t(), acc :: t() | Tornex.Scheduler.ExecutionUnit.t()) ::
  t() | Tornex.Scheduler.ExecutionUnit.t()

Merge a SpecQuery into another SpecQuery.

WARNING: It is assumed that it has already been validated that it is possible to merge the two SpecQuery in terms of security and how the API functions.

new(opts \\ [])

@spec new(opts :: Keyword.t()) :: t()

Initialize an empty query against the OpenAPI specification.

By default, the niceness of the request will be set to 20 and the key owner will be set to 0. The key owner of 0 is intended to be for requests where the owner of the key is not known (e.g. for determining the owner of the API key).

Options

  • :paths - list of API paths
  • :parameters - list of query/path parameters
  • :key - API key
  • :key_owner - ID of the owner of the API key (default: 0)
  • :nice - Priority of the API call between -20 and 20 (default: 20)
  • :quarantine? - Boolean to quarantine the query from the QueryRegistry (default: false)
  • :resource_id - fallback ID of the resource for use in the scheduler (default: nil)

parse(query, response)

@spec parse(query :: t(), response :: list() | map()) :: %{
  required(module()) => term()
}

Parse the response of an API call against the query into schema structs.

Using the path modules in the generated Torngen.Client library, we can parse the parts of the API response into the a map containing the parsed schema struct for each path.

path_selections!(query)

@spec path_selections!(query :: t()) :: {String.t(), [String.t()]}

Parse a SpecQuery to determine the base path and selections.

Raises RuntimeError if the SpecQuery does not contain any paths or has conflicting base paths.

Examples

iex> query = 
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Personalstats)
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Bounties)
...>   |> Tornex.SpecQuery.put_parameter(:id, 2383326)
...>   |> Tornex.SpecQuery.put_parameter(:stats, ["attackswon", "attackslost"])
iex> Tornex.SpecQuery.path_selections!()
{"user/{id}/", ["personalstats", "bounties"]}

iex> query = 
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Personalstats)
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Attacks)
...>   |> Tornex.SpecQuery.put_parameter(:id, 2383326)
...>   |> Tornex.SpecQuery.put_parameter(:stats, ["attackswon", "attackslost"])
iex> Tornex.SpecQuery.path_selections!()
** (RuntimeError) 2 base paths were added to the query **

iex> query = Tornex.SpecQuery.new()
iex> Tornex.SpecQuery.path_selections!()
** (RuntimeError) No paths were added to the query **

put_key(query, api_key)

@spec put_key(query :: t(), api_key :: String.t()) :: t()

Add an API key to the query.

put_key_owner(query, key_owner)

@spec put_key_owner(query :: t(), key_owner :: pos_integer()) :: t()

Add the owner of the API key to the query.

put_parameter(query, parameter_name, parameter_value)

This function is deprecated. Use put_parameter!/3 instead..
@spec put_parameter(query :: t(), parameter_name :: atom(), parameter_value :: term()) ::
  t()

Add an OpenAPI parameter to the query.

During the execution of the query, the parameter will be inserted as either a path or query parameter depending on the OpenAPI specifications for the paths included in the query. The parameter_value must be an implementation of the String.Chars protocol. If parameter_value is a list and the parameter_name is a query parameter, the values of the list will be joined with commas and used as the parameter value.

If the parameter name is already in the query, a RuntimeError will be raised.

Examples

iex> query = 
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Personalstats)
...>   |> Tornex.SpecQuery.put_parameter(:id, 2383326)
...>   |> |> Tornex.SpecQuery.put_parameter(:stat, ["attackswon", "attackslost"])

put_parameter!(query, parameter_name, parameter_value)

@spec put_parameter!(
  query,
  parameter_name :: atom(),
  parameter_value :: term()
) :: query
when query: t() | Tornex.Scheduler.ExecutionUnit.t()

Add an OpenAPI parameter to the query.

During the execution of the query, the parameter will be inserted as either a path or query parameter depending on the OpenAPI specifications for the paths included in the query. The parameter_value must be an implementation of the String.Chars protocol. If parameter_value is a list and the parameter_name is a query parameter, the values of the list will be joined with commas and used as the parameter value.

If the parameter name is already in the query but the existing parameter value is not equal to the value to be inserted, a RuntimeError will be raised. If the parameter value is not an implementation of the String.Chars protocol, a Protocol.UndefinedError will be raised.

Examples

iex> query = 
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Personalstats)
...>   |> Tornex.SpecQuery.put_parameter!(:id, 2383326)
...>   |> |> Tornex.SpecQuery.put_parameter!(:stat, ["attackswon", "attackslost"])

put_path(query, path)

@spec put_path(query :: t() | Tornex.Scheduler.ExecutionUnit.t(), path :: module()) ::
  t()

Add an OpenAPI path to the query.

The OpenAPI path must be an implementation of the Torngen.Client.Path behavior (originating from the torngen library). However, multiple base resources can not be combined into one query when adding paths to the query. This includes paths for the same resource type (e.g. user) but differing resource IDs such as /user/${id}/bounties.

If the path is already in the query, the path will not be added to the query.

Examples

iex> query =
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Attacks)
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Bounties)

resource!(query)

@spec resource!(query :: t()) :: String.t()

Get the resource for the paths used in the query.

resource_id!(query)

@spec resource_id!(query :: t()) :: parameter() | nil

Get the resource ID used in the query.

The resource ID is the variable path parameter in some Torn API OpenAPI specification paths. For example, the resource ID of /user/{id}/basic would be the value the {id} path parameter resolves to. Path parameters that are not {id} are less common, but would still apply to this; for example, /forum/{categoryIds}/threads would be {categoryIds}.

However, not all specification paths have a resource ID though (e.g. /faction/warfare) and these apply to the "owner" of the resource or apply to everyone. For resources such as user, the "owner" is the user themself; but for the faction resource, the "owner" is any member of the faction (typically any member of the faction with API Access permissions).

selections!(query)

@spec selections!(query :: t()) :: [String.t()]

Get a list of selections used in the query.

uri!(query)

@spec uri!(query :: t()) :: URI.t()

Generate and validate a URI to perform the Tornex.SpecQuery.

Raises RuntimeError if the SpecQuery does not contain all of the necessary path parameters or if a base path and selections cannot be determined by path_selections!/1.

Examples

iex> query = 
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Personalstats)
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.User.Id.Bounties)
...>   |> Tornex.SpecQuery.put_parameter!(:id, 2383326)
...>   |> Tornex.SpecQuery.put_parameter!(:stat, ["attackswon", "attackslost"])
iex> Tornex.SpecQuery.uri!(query)
%URI{
  scheme: "https",
  userinfo: nil,
  host: "api.torn.com",
  port: 443,
  path: "/v2/user/2383326",
  query: "selections=personalstats,bounties&stat=attackswon,attackslost",
}

iex> query = 
...>   Tornex.SpecQuery.new()
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.Faction.Id.Chain)
...>   |> Tornex.SpecQuery.put_path(Torngen.Client.Path.Faction.Id.Members)
iex> Tornex.SpecQuery.uri!(query)
** (RuntimeError) Invalid fragment "{id}" in generated URI: https://api.torn.com/v2/faction/{id}/?selections=chain,members **