Wiki.Action (mediawiki_client v0.6.0)

View Source

Adapter to the MediaWiki Action API

To create an API client call new/2 and specify a site to connect to.

Most functions return an api session which holds the latest results and can be reused to pipe chain requests together. As an example, when getting site statistics:

Request

Wiki.Action.new(:dewiki)
|> Wiki.Action.get!(
  action: :query,
  meta: :siteinfo,
  siprop: :statistics
)

Response

%Wiki.Action.Session{
  ...
  result: %{
    "batchcomplete" => true,
    "query" => %{
      "statistics" => %{
        "activeusers" => 19393,
        "admins" => 188,
        "articles" => 2583636,
        "edits" => 211249646,
        "images" => 130213,
        "jobs" => 0,
        "pages" => 7164514,
        "queued-massmessages" => 0,
        "users" => 3716049
      }
    }
  },
  ...
}

Authentication

Log in with a bot password:

Request

authed_api = Wiki.Action.new(:enwiki)
|> Wiki.Action.authenticate!(
  Application.get_env(:example_app, :bot_username),
  Application.get_env(:example_app, :bot_password)
)

Response

%Wiki.Action.Session{
  ...
  result: %{
  "login" => %{
    "lguserid" => 2,
    "lgusername" => "Admin",
    "result" => "Success"
  },
  ...
}

Now the client can be used to get a token and make an edit:

Request

{:ok, api, token} = Wiki.Action.get_token(authed_api, :csrf)
Wiki.Action.post!(api,
  action: :edit,
  title: "Sandbox",
  assert: :user,
  token: token,
  appendtext: "~~~~ was here."
)

Response

%Wiki.Action.Session{
  ...
  result: %{
    "edit" => %{
      "contentmodel" => "wikitext",
      "new" => true,
      "newrevid" => 38,
      "newtimestamp" => "2025-11-06T13:36:43Z",
      "oldrevid" => 0,
      "pageid" => 20,
      "result" => "Success",
      "title" => "Sandbox",
      "watched" => true
    }
  },
  ...
}

Continuation

Any action that returns more items than the allowed batch size will provide one or more -continue fields which can be transparently used to stream results from multiple requests.

Request

Wiki.Action.new(:dewiki)
|> Wiki.Action.stream(
  action: :query,
  list: :recentchanges,
  rclimit: 5
)
|> Stream.flat_map(fn response -> response["query"]["recentchanges"] end)
|> Stream.map(fn rc -> rc["timestamp"] <> " " <> rc["title"] end)
|> Stream.each(&IO.puts/1)
|> Stream.run()

Response

2025-11-06T13:46:12Z Peter Schnupp
2025-11-06T13:46:03Z Kategorie:Mitglied der Hall of Fame des deutschen Sports
2025-11-06T13:46:02Z Portal:Radsport/Qualitätssicherung
2025-11-06T13:46:02Z Kategorie:Wikipedia:DHBW/2025-Controlling
2025-11-06T13:46:02Z Öffentlicher Personennahverkehr in Wien
2025-11-06T13:45:59Z Brouchaud
2025-11-06T13:45:43Z Steingutfabrik Paetsch
2025-11-06T13:45:38Z Kriegerdenkmal Feldmoching (1923)
2025-11-06T13:45:38Z Hotel Bellevue (Ruhla)
2025-11-06T13:45:35Z Emil und die Detektive
2025-11-06T13:45:33Z Parasesarma
...

Wikibase

The Wikidata project provides structured data for other wiki projects, and can be accessed through the Action API.

Examples:

Search for entities called "alphabet",

Wiki.Action.new(:wikidatawiki)
|> Wiki.Action.get!(
    action: :wbsearchentities,
    search: "alphabet",
    language: :en
)

Search for entities with "Frank Zappa" anywhere in the description or contents,

Wiki.Action.new(:wikidatawiki)
|> Wiki.Action.get!(
    action: :wbsearchentities,
    search: "alphabet",
    language: :en
)

Retrieve all data about a specific entity with ID "Q42",

Wiki.Action.new(:wikidatawiki)
|> Wiki.Action.get!(
    action: :wbgetentities,
    ids: "Q42"
)

Defaults

A few parameters are automatically added for convenience, but can be overridden if desired:

  • The :format parameter defaults to :json.
  • :formatversion defaults to 2.

Summary

Types

  • :debug - Turn on verbose logging by setting to true
  • :plug - In testing, replace network requests with a Plug-like mock
  • :timeout - API call timeout, in seconds. Defaults to 60.0s
  • :user_agent - Override the generic, built in user-agent header string.

Can be a SiteMatrix.Spec as returned by Wiki.SiteMatrix.get, dbname as an atom like :enwiki, or raw api.php endpoint for the wiki you will connect to. For example, "https://en.wikipedia.org/w/api.php"

Functions

Make requests to authenticate a client session. This should only be done using a bot username and password, which can be created for any normal user account.

Assertive variant of authenticate

Make an API GET request

Assertive variant of get.

Helper to make a token request

Create a new client session

Make an API POST request.

Assertive variant of post.

Make a GET request and follow continuations until exhausted or the stream is closed.

Upload a file from a local path

Upload a file with content passed directly, as binary or a stream

Types

client_option()

@type client_option() ::
  {:debug, true}
  | {:plug,
     (Plug.Conn.t() -> Plug.Conn.t())
     | (Plug.Conn.t(), Plug.opts() -> Plug.Conn.t())
     | {module(), any()}}
  | {:timeout, integer()}
  | {:user_agent, binary()}

client_options()

@type client_options() :: [client_option()]
  • :debug - Turn on verbose logging by setting to true
  • :plug - In testing, replace network requests with a Plug-like mock
  • :timeout - API call timeout, in seconds. Defaults to 60.0s
  • :user_agent - Override the generic, built in user-agent header string.

site_action_handle()

@type site_action_handle() :: Wiki.SiteMatrix.Spec.t() | atom() | String.t()

Can be a SiteMatrix.Spec as returned by Wiki.SiteMatrix.get, dbname as an atom like :enwiki, or raw api.php endpoint for the wiki you will connect to. For example, "https://en.wikipedia.org/w/api.php"

Functions

authenticate(session, username, password)

Make requests to authenticate a client session. This should only be done using a bot username and password, which can be created for any normal user account.

Arguments

  • session - Base session pointing to a wiki.
  • username - Bot username, may be different than the final logged-in username.
  • password - Bot password. Protect this string, it allows others to take on-wiki actions on your behalf.

Return value

Authenticated session object.

authenticate!(session, username, password)

@spec authenticate!(Wiki.Action.Session.t(), String.t(), String.t()) ::
  Wiki.Action.Session.t()

Assertive variant of authenticate

get(session, params)

Make an API GET request

Arguments

  • session - Wiki.Action.Session object.
  • params - Keyword list of query parameters as atoms or strings.

Return value

Session object with its .result populated.

get!(session, params)

Assertive variant of get.

get_token(session, type)

@spec get_token(Wiki.Action.Session.t(), atom()) ::
  {:ok, Wiki.Action.Session.t(), token :: binary()} | {:error, any()}

Helper to make a token request

The Action API requires various tokens for login, edit actions, and so on. This function simplifies the request.

TODO: support multiple atoms

new(site, opts \\ [])

Create a new client session

Arguments

  • site - target wiki and its action endpoint
  • opts - configuration options which modify client behavior

Examples

Connect to German Wikipedia:

api = Wiki.Action.new(:dewiki)

Connect to a local development wiki:

api = Wiki.Action.new("http://dev.wiki.local.wmftest.net:8080/w/api.php")

post(session, params)

Make an API POST request.

Arguments

  • session - Wiki.Action.Session object. If credentials are required for this action, you should have created this object with the authenticate/3 function.
  • params - Keyword list of query parameters as atoms or strings.

Return value

Session object with a populated :result attribute.

post!(session, body)

Assertive variant of post.

stream(session, params)

@spec stream(
  Wiki.Action.Session.t(),
  keyword()
) :: Enumerable.t()

Make a GET request and follow continuations until exhausted or the stream is closed.

Arguments

  • session - Wiki.Action.Session object.
  • params - Keyword list of query parameters as atoms or strings.

Return value

Enumerable Stream, where each returned chunk is a raw result map, possibly containing multiple records. This corresponds to session.result from the other entry points.

upload(session, path, params \\ [])

Upload a file from a local path

Request

authed_api |> Wiki.Action.upload("/tmp/Triops_closeup.jpg")

Response

{:ok, %Wiki.Action.Session{
  ...
  result: %{
    "upload" => %{
      "filename" => "Triops_closeup.jpg",
      "imageinfo" => %{
        "bitdepth" => 8,
        "canonicaltitle" => "File:Triops closeup.jpg",
        "comment" => "",
        "commonmetadata" => [
          %{
            "name" => "Copyright",
            "value" => [%{"name" => 0, "value" => "Karsten Grabow"}]
          },
          %{
            "name" => "JPEGFileComment",
            "value" => [%{"name" => 0, "value" => "Copyright Karsten Grabow"}]
          }
        ],
        "descriptionurl" => "http://dev.wiki.local.wmftest.net:8080/wiki/File:Triops_closeup.jpg",
        "extmetadata" => %{
          "DateTime" => %{
            "hidden" => "",
            "source" => "mediawiki-metadata",
            "value" => "2025-11-07T21:31:17Z"
          },
          "ObjectName" => %{
            "source" => "mediawiki-metadata",
            "value" => "Triops closeup"
          }
        },
        "height" => 827,
        "html" => "..."
        "mediatype" => "BITMAP",
        "metadata" => [
          %{
            "name" => "Copyright",
            "value" => [%{"name" => 0, "value" => "Karsten Grabow"}]
          },
          %{
            "name" => "JPEGFileComment",
            "value" => [%{"name" => 0, "value" => "Copyright Karsten Grabow"}]
          },
          %{"name" => "MEDIAWIKI_EXIF_VERSION", "value" => 2}
        ],
        "mime" => "image/jpeg",
        "parsedcomment" => "",
        "sha1" => "12ce3375983eb929fba91bf5267ad932929e9217",
        "size" => 222944,
        "timestamp" => "2025-11-07T21:31:17Z",
        "url" => "http://dev.wiki.local.wmftest.net:8080/w/images/4/45/Triops_closeup.jpg",
        "user" => "Admin",
        "userid" => 2,
        "width" => 1280
      },
      "result" => "Success"
    }
  },
}}

Upload with additional parameters:

authed_api |> Wiki.Action.upload(
  "/tmp/Test.jpg",
  text: "This is a test file",
  comment: "Upload initial draft from Elixir",
  ignorewarnings: true
)

upload_file_content(session, filename, content, params \\ [])

@spec upload_file_content(
  Wiki.Action.Session.t(),
  filename :: binary(),
  content :: binary() | Enumerable.t(),
  keyword()
) :: Wiki.Action.Session.result()

Upload a file with content passed directly, as binary or a stream