View Source hex_core

Build Status

Reference implementation of Hex specifications: https://github.com/hexpm/specifications.

usage

Usage

Let's use default config for now. See "Configuration" section below for customization.

Config = hex_core:default_config().

WARNING The built-in httpc-based HTTP client adapter has insecure default settings and thus it is not recommended for usage, in particular for API write operations. Use HTTP clients with secure defaults like hackney and Mint. See "Configuration" and "Wrapper Module" sections for more information on customising your usage of hex_core.

repository

Repository

Get all package names:

> hex_repo:get_names(Config).
{ok,{200, ...,
     #{packages => [
           #{name => <<"package1">>},
           #{name => <<"package2">>},
           ...]}}}

Get all package versions from repository:

> hex_repo:get_versions(Config).
{ok,{200, ...,
     #{packages => [[
           #{name => <<"package1">>, retired => [], versions => [<<"1.0.0">>]},
           #{name => <<"package2">>, retired => [], versions => [<<"0.5.0">>]},
           ...]}}}

Get package releases from repository:

> hex_repo:get_package(Config, <<"package1">>).
{ok,{200, ...,
     #{releases => [
           #{checksum => ..., version => <<"0.5.0">>, dependencies => []}],
           #{checksum => ..., version => <<"1.0.0">>, dependencies => []}],
           ...]}}}

api

API

For a full list of all parameters and returned objects for the API, check out the API docs: https://github.com/hexpm/specifications/blob/master/http_api.md.

Get package from HTTP API:

> hex_api_package:get(Config, <<"package1">>).
{ok, {200, ...,
    #{
        <<"name">> => <<"package1">>,
        <<"meta">> => #{
           <<"description">> => ...,
           <<"licenses">> => ...,
           <<"links">> => ...,
           <<"maintainers">> => ...,
        },
        ...,
        <<"releases">> => [
            #{<<"url">> => ..., <<"version">> => <<"0.5.0">>}],
            #{<<"url">> => ..., <<"version">> => <<"1.0.0">>}],
            ...
        ]
    }}}

Get package tarball:

{ok, {200, _, Tarball}} = hex_repo:get_tarball(Config, <<"package1">>, <<"1.0.0">>).

Publish package tarball:

{ok, {200, _Headers, _Body} = hex_api_package:publish(Config, Tarball).

package-tarballs

Package tarballs

Unpack package tarball:

{ok, #{outer_checksum := Checksum, contents := Contents, metadata := Metadata}} = hex_tarball:unpack(Tarball, memory).

Remember to verify the outer tarball checksum against the registry checksum returned from hex_repo:get_package(Config, Package).

Create package tarball:

{ok, #{tarball := Tarball,
       inner_checksum := InnerChecksum,
       outer_checksum := OuterChecksum}} = hex_tarball:create(Metadata, Contents).

configuration

Configuration

The default configuration, provided by hex_core:default_config/0, uses built-in httpc-based adapter and Hex.pm APIs: https://hex.pm/api and https://repo.hex.pm.

HTTP client configuration can be overridden as follows:

Config = maps:merge(hex_core:default_config(), #{
  http_adapter => {my_hackney_adapter, my_hackney_adapter_config},
  http_user_agent_fragment => <<"(my_app/0.1.0) (hackney/1.12.1) ">>
}),
hex_repo:get_names(Config).

%% my_hackney_adapter.erl
-module(my_hackney_adapter).
-behaviour(hex_http).
-exports([request/5]).

request(Method, URI, ReqHeaders, Body, AdapterConfig) ->
    %% ...

See the hex_core module for more information about the configuration.

wrapper-module

Wrapper Module

It's recommended to write a wrapper module because a lot of decisions are left to the user, e.g.: where to get configuration from, how to handle caching, failures etc.

For a sample, see: examples/myapp_hex.erl. Here's an excerpt:

-module(myapp_hex).
-export([
    get_api_package/1,
    get_repo_tarball/2,
    get_repo_versions/0
]).

%%====================================================================
%% API functions
%%====================================================================

get_api_package(Name) ->
      case hex_api_package:get(config(), Name) of
          {ok, {200, _Headers, Payload}} ->
              {ok, Payload};

          Other ->
              Other
      end.

get_repo_versions() ->
      case hex_repo:get_versions(config()) of
          {ok, {200, _Headers, Payload}} ->
              {ok, maps:get(packages, Payload)};

          Other ->
              Other
      end.

%%====================================================================
%% Internal functions
%%====================================================================

config() ->
    Config1 = hex_core:default_config(),
    Config2 = put_http_config(Config1),
    Config3 = maybe_put_api_key(Config2),
    Config3.

put_http_config(Config) ->
    maps:put(http_user_agent_fragment, <<"(myapp/1.0.0) (httpc)">>, Config).

maybe_put_api_key(Config) ->
    case os:getenv("HEX_API_KEY") of
        false -> Config;
        Key -> maps:put(api_key, Key, Config)
    end.

installation

Installation

rebar3

Rebar3

Add to rebar.config:

{deps, [
  {hex_core, "0.10.0"}
]}

mix

Mix

Add to mix.exs:

defp deps do
  [
    {:hex_core, "~> 0.10.0"}
  ]
end

development

Development

  • Run rebar3 as dev compile to re-generate protobuf files
  • Run rebar3 as test proper for property-based tests
  • Run ./docs.sh to generate documentation