@ideal-postcodes/core-interface
    TypeScript icon, indicating that this package has built-in type declarations

    2.0.3 • Public • Published

    Ideal Postcodes Core Interface

    JavaScript API for api.ideal-postcodes.co.uk

    CI Cross Browser Testing Release codecov Dependency Status

    npm version npm bundle size (scoped) npm bundle size (scoped) install size

    @ideal-postcodes/core-interface is an environment agnostic implementation of the Ideal Postcodes JavaScript API client interface.

    If you are looking for the browser or Node.js client which implements this interface, please check out the downstream clients links.

    Links

    Downstream Clients

    Documentation

    Methods

    Usage

    To install, pick one of the following based on your platform

    # For browser client
    npm install @ideal-postcodes/core-browser
    
    # For node.js client
    npm install @ideal-postcodes/core-node
    
    # For generic interface (you need to supply your own HTTP agent)
    npm install @ideal-postcodes/core-interface

    Instantiate a client with

    import { Client } from "@ideal-postcodes/core-<package-type>";
    
    const client = new Client({ api_key: "iddqd" });
    
    // Only api_key is required by core-node and core-browser - all others are optional
    // The agentless interface requires explicit configuration

    Client configuration options


    Quick Methods

    The library exposes a number of simple methods to get at the most common tasks when interacting with the API

    Lookup a Postcode

    Return addresses associated with a given postcode

    Invalid postcodes (i.e. postcode not found) return an empty array []

    import { lookupPostcode } from "@ideal-postcodes/core-browser";
    
    const postcode = "id11qd";
    
    lookupPostcode({ client, postcode }).then(addresses => {
      console.log(addresses);
      {
        postcode: "ID1 1QD",
        line_1: "2 Barons Court Road",
        // ...etc...
      }
    });

    lookupPostcode docs

    Search for an Address

    Return addresses associated with a given query

    import { lookupAddress } from "@ideal-postcodes/core-browser";
    
    const query = "10 downing street sw1a";
    
    lookupAddress({ client, query }).then(addresses => {
      console.log(addresses);
      {
        postcode: "SW1A 2AA",
        line_1: "Prime Minister & First Lord Of The Treasury",
        // ...etc...
      }
    });

    lookupAddress docs

    Search for an Address by UDPRN

    Return address for a given udprn

    Invalid UDPRN will return null

    import { lookupUdprn } from "@ideal-postcodes/core-browser";
    
    const udprn = 23747771;
    
    lookupUdprn({ client, udprn }).then(address => {
      console.log(address);
      {
        postcode: "SW1A 2AA",
        line_1: "Prime Minister & First Lord Of The Treasury",
        // ...etc...
      }
    });

    lookupUdprn docs

    Search for an Address by UMPRN

    Return address for a given umprn

    Invalid UMPRN will return null

    import { lookupUmprn } from "@ideal-postcodes/core-browser";
    
    const umprn = 50906066;
    
    lookupUmprn({ client, umprn }).then(address => {
      console.log(address);
      {
        postcode: "CV4 7AL",
        line_1: "Room 1, Block 1 Arthur Vick",
        // ...etc...
      }
    });

    lookupUmprn docs

    Check Key Usability

    Check if a key is currently usable

    checkKeyUsability({ client }).then((key) => {
      console.log(key.available); // => true
    });

    checkKeyUsability docs


    Resources

    Resources defined in the API documentation are exported by the library. Each resource exposes a method (#retrieve, #list, etc) which maps to a resource action.

    These methods expose a low level interface to execute HTTP requests and observe HTTP responses. They are ideal if you have a more complex query or usecase where low level access would be useful.

    Resource methods return a promise with a HTTP response object type.

    Retrieve

    Requesting a resource by ID (e.g. a postcode lookup for postcode with ID "SW1A 2AA") maps to the #retrieve method.

    The first argument is the client object. The second is the resource ID. The last argument is an object which accepts header and query attributes that map to HTTP header and the request querystring.

    resourceName.retrieve(client, "id", {
      query: {
        api_key: "foo",
        tags: "this,that,those",
        licensee: "sk_99dj3",
      },
      header: {
        "IDPC-Source-IP": "8.8.8.8",
      },
      timeout: 5000,
    });

    List

    Requesting a resource endpoint (e.g. an address query to /addresses) maps to the #list method.

    resourceName.list(client, {
      query: {
        api_key: "foo",
        query: "10 downing street",
      },
      header: {
        "IDPC-Source-IP": "8.8.8.8",
      },
      timeout: 5000,
    });

    The first argument is the client. The second is an object which accepts header and query attributes that map to HTTP header and the request querystring.

    Custom Actions

    Some endpoints are defined as custom actions, e.g. /keys/:key/usage. These can be invoked using the name of the custom action.

    E.g. for key usage data extraction

    keys.usage(client, api_key, {
      query: {
        tags: "checkout,production",
      },
      header: {
        Authorization: 'IDEALPOSTCODES user_token="foo"',
      },
      timeout: 5000,
    });

    Resource Methods

    Listed below are the available resources exposed by the library:

    Postcodes

    Retrieve addresses for a postcode.

    import { postcodes } from "@ideal-postcodes/core-browser";
    postcodes
      .retrieve(client, "SW1A2AA", {
        header: {
          Authorization: 'IDEALPOSTCODES api_key="iddqd"',
        },
      })
      .then((response) => {
        const addresses = response.body.result;
      })
      .catch((error) => logger(error));

    Postcode resource HTTP API documentation

    Postcode resource docs

    Addresses

    Search for an address

    import { addresses } from "@ideal-postcodes/core-browser";
    
    addresses
      .list(client, {
        query: {
          query: "10 Downing street",
        },
        header: {
          Authorization: 'IDEALPOSTCODES api_key="iddqd"',
        },
      })
      .then((response) => {
        const addresses = response.body.result.hits;
      })
      .catch((error) => logger(error));

    Address resource HTTP API documentation

    Address resource client docs

    Autocomplete

    Autocomplete an address given an address partial

    import { autocomplete } from "@ideal-postcodes/core-browser";
    
    autocomplete
      .list(client, {
        query: {
          query: "10 Downing stre",
        },
        header: {
          Authorization: 'IDEALPOSTCODES api_key="iddqd"',
        },
      })
      .then((response) => {
        const suggestions = response.body.result.hits;
      })
      .catch((error) => logger(error));

    Autocomplete resource HTTP API documentation

    Autocomplete resource client docs

    UDPRN

    Retrieve an address given a UDPRN

    import { udprn } from "@ideal-postcodes/core-browser";
    
    udprn
      .retrieve(client, "12345678", {
        header: {
          Authorization: 'IDEALPOSTCODES api_key="iddqd"',
        },
      })
      .then((response) => {
        const address = response.body.result;
      })
      .catch((error) => logger(error));

    UDPRN resource HTTP API documentation

    UDPRN resource client docs

    UMPRN

    Retrieve a multiple residence premise given a UMPRN

    import { umprn } from "@ideal-postcodes/core-browser";
    
    umprn
      .retrieve(client, "87654321", {
        header: {
          Authorization: 'IDEALPOSTCODES api_key="iddqd"',
        },
      })
      .then((response) => {
        const address = response.body.result;
      })
      .catch((error) => logger(error));

    UMPRN resource HTTP API documentation

    UMPRN resource client docs

    Keys

    Find out if a key is available

    import { keys } from "@ideal-postcodes/core-browser";
    
    keys
      .retrieve(client, "iddqd", {})
      .then((response) => {
        const { available } = response.body.result;
      })
      .catch((error) => logger(error));

    Method docs

    Get private information on key (requires user_token)

    import { keys } from "@ideal-postcodes/core-browser";
    
    keys
      .retrieve(client, "iddqd", {
        header: {
          Authorization: 'IDEALPOSTCODES user_token="secret-token"',
        },
      })
      .then((response) => {
        const key = response.body.result;
      })
      .catch((error) => logger(error));

    Method docs

    Get key usage data

    import { keys } from "@ideal-postcodes/core-browser";
    
    keys
      .usage(client, "iddqd", {
        header: {
          Authorization: 'IDEALPOSTCODES user_token="secret-token"',
        },
      })
      .then((response) => {
        const key = response.body.result;
      })
      .catch((error) => logger(error));

    Method docs

    Keys resource HTTP API documentation

    Key resource client docs


    Error Handling

    This library exports a static variable errors which contains custom error constructors that wrap specific API errors. These constructors can be used to test for specific cases using the instanceof operator.

    For example:

    const { IdpcInvalidKeyError } = Client.errors;
    
    try {
      const addresses = await lookupPostcode({ client, postcode: "SW1A2AA" });
    } catch (error) {
      if (error instanceof IdpcInvalidKeyError) {
        // Handle an invalid key error
      }
    }

    Not all specific API errors will be caught. If a specific API error does not have an error constructor defined, a more generic error (determined by the HTTP status code) will be returned.

    For example:

    import {
      IdpcRequestFailedError,
      lookupPostcode,
    } from "@ideal-postcodes/core-browser";
    
    try {
      const addresses = await lookupPostcode({ client, postcode: "SW1A2AA" });
    } catch (error) {
      if (error instanceof IdpcRequestFailedError) {
        // IdpcRequestFailedError indicates a 402 response code
        // Possibly the key balance has been depleted
      }
    }

    You may view a sketch of the error prototype chain.


    Core Interface Errors

    For more advanced use cases, this core-interface library provides:

    Error Usage

    Aside from inspecting the HTTP request status code and/or JSON body response codes, you may also test for specific error instances.

    Errors that don't inherit from IdealPostcodesError would indicate some kind of error external to the API (e.g. bad network, request timeout).

    import { errors } from "@ideal-postcodes/core-browser";
    const { IdpcPostcodeNotFoundError } = errors;
    
    // Handle a specific error
    if (error instanceof IdpcPostcodeNotFoundError) {
      // You got yourself an invalid API Key
    }
    
    // Alternatively use a switch statement
    switch (true) {
      case error instanceof IdpcPostcodeNotFoundError:
      // You got yourself an invalid API Key
      default:
      // Default error handling path
    }

    Error Prototype Chain

    All errors inherit from JavaScript's Error prototype.

    Errors are grouped by HTTP status code classes.

    Specific errors may be supplied for the following reasons:

    • Convenience. They are frequently tested for (e.g. invalid postcode, postcode not found)
    • Useful for debug purposes during the implementation stages
    Prototype Chain
    
    # Parent class inherits from Javascript Error. Returned if no JSON Response body
    IdealPostcodesError < Error
    |
    |- IdpcApiError # Generic Error Class, returned if JSON response body present
       |
       |- IdpcBadRequestError          # 400 Errors
       |- IdpcUnauthorisedError        # 401 Errors
       |- IdpcRequestFailedError       # 402 Errors
       |  |- IdpcBalanceDepletedError
       |  |- IdpcLimitReachedError
       |
       |- IdpcResourceNotFoundError    # 404 Errors
       |  |- IdpcPostcodeNotFoundError
       |  |- IdpcKeyNotFoundError
       |  |- IdpcUdprnNotFoundError
       |  |- IdpcUmprnNotFoundError
       |
       |- IdpcServerError              # 500 Errors

    Error Parser

    The error parser consumes a HTTP API response and returns the correct error instance.

    import { errors } from "@ideal-postcodes/core-browser";
    const { parse, IdpcPostcodeNotFoundError } = errors;
    
    const invalidPostcodeUrl = "https://api.ideal-postcodes.co.uk/v1/postcodes/bad_postcode?api_key=iddqd"
    
    const response = await fetch(invalidPostcodeUrl);
    
    // Generate an error object if present, otherwise returns `undefined`
    const error = parse(response);
    
    // Handle the error
    if (error instanceof IdpcPostcodeNotFoundError) {...}

    Test

    npm test

    Licence

    MIT

    Install

    npm i @ideal-postcodes/core-interface

    DownloadsWeekly Downloads

    4,123

    Version

    2.0.3

    License

    MIT

    Unpacked Size

    129 kB

    Total Files

    60

    Last publish

    Collaborators

    • cablanchard
    • mfilip