Giter VIP home page Giter VIP logo

lob-elixir's Introduction

lob_elixir

Build Status Coverage Status Module Version Hex Docs Total Download License Last Updated

Elixir library for Lob API.

Installation

The package can be installed by adding :lob_elixir to your list of dependencies in mix.exs:

def deps do
  [
    {:lob_elixir, "~> 1.5.0"}
  ]
end

Getting Started

This library implements the Lob API. Please read through the official API Documentation to get a complete sense of what to expect from each endpoint.

Registration

The library requires a valid Lob API key to work properly. To acquire an API key, first create an account at Lob.com. Once you have created an account, you can access your API Keys from the Settings Panel.

API Key Configuration

The library will by default refer to the :api_key config when making authenticated requests. If that is not present, it will look for the LOB_API_TEST_KEY environment variable.

# Configuring an API key with configs
config :lob_elixir,
  api_key: "your_api_key"

The {:system, "ENV_VAR"} syntax is also supported, allowing the API key to be fetched at runtime. For example, if the API key is stored in an environment variable named LOB_KEY, the library could be configured with:

# Configuring an API key with configs
config :lob_elixir,
  api_key: {:system, "LOB_KEY"}

Similarly, the library allows users to optionally configure the API version through the :api_version config. If that is not present, it will look for the LOB_API_VERSION environment variable.

# Configuring an API key and API version with configs
config :lob_elixir,
  api_key: "your_api_key",
  api_version: "2014-12-18"

Usage

Requests return a 2-tuple or 3-tuple, depending on the response.

# Successful response
{:ok, postcards, _headers} = Postcard.list()

# Unsuccessful response
{:error, %{message: ":nxdomain"}} = Postcard.list()

# Unsuccessful response with status code
{:error, %{message: "postcard not found", status_code: 404}} = Postcard.retrieve('nonexistent_resource')

Contributing

To contribute, please see the CONTRIBUTING.md file.

Testing

Tests are written using ExUnit, Elixir's built-in test framework.

Here's how you can run the tests:

LOB_API_TEST_KEY=YOUR_TEST_API_KEY mix test

To run tests with a coverage report:

LOB_API_TEST_KEY=YOUR_TEST_API_KEY mix coveralls.html

Then view the report at cover/excoveralls.html.

=======================

Copyright © 2021 Lob.com

Released under the MIT License, which can be found in the repository in LICENSE.txt.

lob-elixir's People

Contributors

adrianfalleiro avatar ajpawlicki avatar amaan-lob avatar ami avatar coop avatar itsachen avatar kylekwong avatar mwj8410 avatar pdgonzalez872 avatar rugyoga avatar sudoku-lord avatar thexumaker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lob-elixir's Issues

Question regarding additional components in address prefixes (e.g., APT, STE, etc...)

Hey guys, hope you are doing great!

We've been using your address verification services for a while with great success so far. The API is easy to use. Response times are impressive, and no false positives whatsoever. An absolute A+.

Now we started integrating autocomplete services with great success, too, but we ran into this particular situation:

If we make an API call using a regular address without any STE or APT "components," everything works as expected:

iex> Lob.USAutocompletion.autocomplete(%{                                           
  address_prefix: "1355 Market Street",
  city: "San Francisco",
  state: "CA"
})
{:ok,
 %{
   id: "us_auto_xxxxxxxxxxxxxxxxxxxx",
   object: "us_autocompletion",
   suggestions: [
     %{
       city: "SAN FRANCISCO",
       primary_line: "1355 MARKET ST",
       state: "CA",
       zip_code: "94103"
     }
   ]
 },
 [...]
}

However, if we include the STE number, we get no results back:

Lob.USAutocompletion.autocomplete(%{                                           
  address_prefix: "1355 Market Street STE 900",
  city: "San Francisco",
  state: "CA"
})
{:ok,
 %{
   id: "us_auto_39e96a7e68ff44199c63",
   object: "us_autocompletion",
   suggestions: []
 },
 [...]
}

At the moment, we are whipping out STE, APT, and friends from the address prefix, and everything works like a charm, but we are wondering if it'll be possible to pass those along and maybe even get them back as part of the response.

Most services don't include apartment or floor information because it's almost impossible to track, but we are curious if we are missing something obvious here. A hidden setting or something like that, maybe?

Thanks in advance, and keep up the excellent work!!

Confirming Expected Test Result

Hey Lob team - I'm seeing 5 failing tests on a clean clone, all related to filtering by metadata. I think the expected result is incorrect (test is wrong) rather than functionality is wrong, but wanted to confirm before changing.

........

  1) test list/2 filters by metadata (Lob.CheckTest)
     test/lob/check_test.exs:56
     Assertion with == failed
     code:  assert checks.count() == 1
     left:  0
     right: 1
     stacktrace:
       test/lob/check_test.exs:58: (test)

........

  2) test list/2 filters by metadata (Lob.PostcardTest)
     test/lob/postcard_test.exs:47
     Assertion with == failed
     code:  assert postcards.count() == 1
     left:  0
     right: 1
     stacktrace:
       test/lob/postcard_test.exs:49: (test)

...............

  3) test list/2 filters by metadata (Lob.LetterTest)
     test/lob/letter_test.exs:46
     Assertion with == failed
     code:  assert letters.count() == 1
     left:  0
     right: 1
     stacktrace:
       test/lob/letter_test.exs:48: (test)

.............

  4) test list/2 filters by metadata (Lob.BankAccountTest)
     test/lob/bank_account_test.exs:34
     Assertion with == failed
     code:  assert bank_accounts.count() == 1
     left:  0
     right: 1
     stacktrace:
       test/lob/bank_account_test.exs:36: (test)

.....

  5) test list/2 filters by metadata (Lob.AddressTest)
     test/lob/address_test.exs:38
     Assertion with == failed
     code:  assert addresses.count() == 1
     left:  0
     right: 1
     stacktrace:
       test/lob/address_test.exs:40: (test)

..........

Finished in 32.2 seconds
3 doctests, 61 tests, 5 failures

None of the setup test data includes metadata; e.g. when testing Postcard ...

  setup do
    sample_address = %{
      name: "TestAddress",
      email: "[email protected]",
      address_line1: "185 Berry Street",
      address_line2: "Suite 6100",
      address_city: "San Francisco",
      address_state: "CA",
      address_country: "US",
      address_zip: "94107"
    }

    sample_postcard = %{
      description: "Library Test Postcard #{DateTime.utc_now |> DateTime.to_string}",
      back: "<h1>Sample postcard back</h1>"
    }

    %{
      sample_address: sample_address,
      sample_postcard: sample_postcard
    }
  end

And then the tests to filter by metadata assert there should be 1 result. I think filtering should ensure 0 results.

    test "filters by metadata" do
      {:ok, postcards, _headers} = Postcard.list(%{metadata: %{foo: "bar"}})
      assert postcards.count == 1
    end

Please confirm. About to open a PR to this effect.

There are some failing tests in the main branch, details below:

There are a few failing tests for the main branch. I was trying to figure out why they were failing for a while and need to hop onto something else for a moment, so I decided to report it. Maybe I'm missing something silly. I focused on one of the failing tests below:

$ ~/dev/oss/lob-elixir (main)$ API_KEY=REDACTED mix test test/lob/self_mailer_test.exs:134 --trace
Excluding tags: [:test]
Including tags: [line: "134"]


Lob.SelfMailerTest [test/lob/self_mailer_test.exs]
  * test create/2 creates a self mailer with to address params (excluded) [L#90]
  * test create/2 creates a self mailer with an idempotency key (excluded) [L#168]
  * test create/2 creates a self mailer with a merge variable list (excluded) [L#195]
  * test list/2 lists self mailers (excluded) [L#32]
  * test create/2 creates a self mailer with outside and inside as urls (excluded) [L#119]
  * test create/2 creates a 12x9 self mailer with outside and inside as PDFs (excluded) [L#152]
  * test list/2 includes total count (excluded) [L#37]
  * test create/2 creates a self mailer with address_id (excluded) [L#75]
  * test list/2 filters by metadata (excluded) [L#47]
  * test list/2 lists by limit (excluded) [L#42]
  * test delete/2 deletes a self mailer (excluded) [L#224]
  * test create/2 creates a self mailer with from address params (excluded) [L#103]
  * test retrieve/2 retrieves a self mailer (excluded) [L#56]
  * test create/2 creates a self mailer with outside and inside as PDFs (3050.8ms) [L#134]

  1) test create/2 creates a self mailer with outside and inside as PDFs (Lob.SelfMailerTest)
     test/lob/self_mailer_test.exs:134
     ** (MatchError) no match of right hand side value: {:error, %{code: "unrecognized_endpoint", message: "Unrecognized request URL. Please see https://lob.com/docs or email us at [email protected].", status_code: 404}}
     code: {:ok, created_self_mailer, headers} =
     stacktrace:
       test/lob/self_mailer_test.exs:137: (test)



Finished in 3.1 seconds (0.00s async, 3.1s sync)
14 tests, 1 failure, 13 excluded

Randomized with seed 217660
$ ~/dev/oss/lob-elixir (main)$ 

Here are some details about my system:

Erlang/OTP 24 [erts-12.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit]
Interactive Elixir (1.13.1) - press Ctrl+C to exit (type h() ENTER for help)

Here is what the failing response looks like:

{:ok,                                                                                                                                                                                
 %HTTPoison.Response{                                                                                                                                                                            
   body: %{                                                                                                                                                                                      
     error: %{                                                                                                                                                                                   
       code: "unrecognized_endpoint",                                                                                                                                                            
       message: "Unrecognized request URL. Please see https://lob.com/docs or email us at [email protected].",                                                                                     
       status_code: 404                                                                                                                                                                          
     }                                                                                                                                                                                           
   },                                                                                                                                                                                            
   headers: [                                                                                                                                                                                    
     {"Connection", "keep-alive"},                                                                                                                                                               
     {"Content-Length", "204"},                                                                                                                                                                  
     {"Content-Type", "application/json; charset=utf-8"},                                                                                                                                        
     {"X-Rate-Limit-Remaining", "149"},                                                                                                                                                          
     {"X-Rate-Limit-Limit", "150"},                                                                                                                                                              
     {"X-Rate-Limit-Reset", "1646153709"},                                                                                                                                                       
     {"access-control-allow-credentials", "true"},                                                                                                                                               
     {"access-control-expose-headers", "WWW-Authenticate,Server-Authorization"},                                                                                                                 
     {"cache-control", "no-cache"},                                                                                                                                                              
     {"Accept-Ranges", "bytes"},                                                                                                                                                                 
     {"Date", "Tue, 01 Mar 2022 16:55:04 GMT"},                                                                                                                                                  
     {"Vary", "origin"},                                                                                                                                                                         
     {"Strict-Transport-Security", "max-age=300"}                                                                                                                                                
   ],                                                                                                                                                                                            
   request: %HTTPoison.Request{
     body: {:multipart,
      [
        {"description", "Library Test Self Mailer 2022-03-01 16:54:59.832273Z"},
        {"inside",
         "https://s3-us-west-2.amazonaws.com/public.lob.com/assets/templates/self_mailers/6x18_sfm_inside.pdf"},
        {"outside",
         "https://s3-us-west-2.amazonaws.com/public.lob.com/assets/templates/self_mailers/6x18_sfm_inside.pdf"},
        {"to", "adr_cb5efa0dea6422b5"}
      ]},
     headers: [{"User-Agent", "Lob/v1 ElixirBindings/1.5.0"}],
     method: :post,
     options: [
       hackney: [basic_auth: {"REDACTED", ""}],
       recv_timeout: :infinity
     ],
     params: %{},
     url: "https://api.lob.com/v1/self_mailers"
   },
   request_url: "https://api.lob.com/v1/self_mailers",
   status_code: 404
 }}

The url seems to be valid, the curl example in the docs works fine locally:

curl https://api.lob.com/v1/self_mailers \
  -u REDACTED \
  -d "description=Demo Self Mailer job" \
  -d "to[name]=Harry Zhang" \
  -d "to[address_line1]=210 King St" \
  -d "to[address_city]=San Francisco" \
  -d "to[address_state]=CA" \
  -d "to[address_zip]=94107" \
  -d "from=adr_210a8d4b0b76d77b" \
  --data-urlencode "inside=<html style='padding: 1in; font-size: 50;'>Inside HTML for {{name}}</html>" \
  --data-urlencode "outside=<html style='padding: 1in; font-size: 20;'>Outside HTML for {{name}}</html>" \
  -d "merge_variables[name]=Harry"

The Lob.Address creation right above the failing line works.

Hope this helps!

PG

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.