Getting Started

Introduction

If you are interested in our most up to date API check out the full Nexar API here

The latest version of the Nexar Legacy API (formerly Octopart APIv4) is organized around GraphQL, with a newly added REST interface. While you can use the REST wrapper on Nexar Legacy API, we only recommend it as a temporary solution as you transition from Legacy APIv3 to Nexar Legacy API and get set up with our GraphQL interface. We will not continue enhancing and updating APIv3. If you need guidance on transitioning from APIv3 to the Nexar Legacy API REST wrapper, you can find documentation here. If you are ready to move to GraphQL, please continue reading this Getting Started guide.

As of March 31, 2022 we will be discontinuing support for APIv3. As of June 30, 2022 we will be disabling APIv3 altogether. The Getting started guide and reference pages that follow are for the latest release, the Nexar Legacy API.

Please don't hesitate to contact support@nexar.com with any questions.

As of late 2020 PartKeepr is compatible with Nexar Legacy API. We recommend signing up for a Pro tier token to get the most out of the Nexar Legacy API. You can sign up for your Nexar Legacy API token here.

How Limits Work

Monthly limits are based on returned part objects. This differs slightly from v3 behavior, which was based on number of http requests.

By default, searches return 10 parts per request, so this means that each request will increment your monthly API usage by up to 10 parts. multi_match requests return 3 parts per query by default, so if you batch request 3 MPN searches using multi_match, by default this will return up to 9 parts.

Making your first request

  1. Visit API Dashboard to get a token.
  2. Click the Open Playground button.
  3. In the left-hand panel, enter a simple query & press play:
query MyFirstQuery {
  categories {
    name
  }
}

Requesting additional fields

In GraphQL each field must be explicitly requested to be returned. There are three ways to explore the available fields:

  • View Category schema in these docs.
  • In playground, open the Schema tab on right hand side contains the definition for Category. The Docs tab also presents the root queries and their return types in an explorable hierarchy.
  • In playground, place cursor is in the query editor and press ctrl space to see typeahead suggestions available in the current context.

Inspecting the Category schema we see:

type Category {
  id: ID!
  parent_id: ID!
  name: String!
  ancestors: [Category!]!
  children: [Category!]!
  path: String!
  relevant_attributes: [Attribute!]!
}

Let's update our first query to pull back some additional fields:

query MyFirstQuery {
  categories {
    path
    name
    ancestors {
      path
      name
    }
    children {
      path
      name
    }
    relevant_attributes {
      shortname
      name
    }
  }
}

One of the features of graphql is the ability to retrieve properties from related objects. Here we can see that ancestors and children are lists of categories, and we can query all the Category fields on these related objects. The same is true of relevant_attributes which is a list of Attribute.

As explained in the GraphQL spec the fields in the result will match the ordering of fields requested, and only the requested fields will be returned. This can help make learning and exploring the API easy and fun!

Getting parts by ID

Let's get some parts by ID. The ID can be found at the end of a part URL. So for the page /msp430f5310iptr-texas+instruments-19495124 the ID is: 19495124.

To enable smooth transition, API v3 UIDs are also support, so for /api/v3/parts/7ad5b3df5fb7a512, you can use the ID 7ad5b3df5fb7a512

query SomeParts {
  parts(ids: ["1", "2", "asdf", "3", "7ad5b3df5fb7a512"]) {
    id
    v3uid
    manufacturer {
      name
    }
    mpn
  }
}

Some interesting things to point out here:

  • The manufacturer field is actually a linked company record with it's own set of requested fields. You must specify the desired fields on the related object, and failing to do so will produce an error: Field "manufacturer" of type "Company!" must have a selection of subfields. Did you mean "manufacturer { ... }"?. The ability to retrieve fields from related objects is why the term Graph appears in GraphQL. Try using the schema tab to explore the Company object and add a field to the manufacturer field set.
  • For ID 1, the returned ID is actually 46668526. When duplicate parts are merged, the redirect is followed and the new correct part is returned in place of the merged part.
  • For ID asdf a null is returned in the 3rd position. When requesting parts by ID the results will match the order requested, and any misses will be null.
  • ID 7ad5b3df5fb7a512 is requested using a UID from Octopart's APIv3. In the response we can see both the id (4) and the v3uid (7ad5b3df5fb7a512). The parts endpoint allows both numerical part IDs and v3uid values.

Searching for Parts

The search query is designed to power our search page: It accepts a query (q) and supports doing aggregations, filtering and sorting results, pagination, etc. Let's look at an example:

query MyPartSearch {
  search(q: "msp430") {
    total

    manufacturer_agg {
      company {
        id
        name
      }
      count
    }

    results {
      part {
        id
        manufacturer {
          name
        }
        mpn
      }
    }
  }
}

From this query we get 3789 hits and the manufacturer_agg provides aggregations or facets on the result set.

Based on the manufacturer_agg let's add a filter to only show parts manufactured by Olimex. Update the search args to read:

search(q: "msp430", filters: {manufacturer_id: "3330"})

After executing we should see a new total of 30 hits, which matches the aggregation. Let's add Texas Instruments back in:

search(q: "msp430", filters: {manufacturer_id: ["3330", "370"]})

We now see 3690 hits which is the sum of the two buckets in the aggregation.

Detour: using variables in GraphQL

So far we have been hard coding arguments like ids and q. But in a real application you will want to parameterize these arguments. Let's look at an example of doing this:

query MyPartSearch($q: String!, $filters: Map) {
  search(q: $q, filters: $filters) {
    total
  }
}

Here we define our custom query MyPartSearch with two variable arguments: $q and $filters. The ! at the end of String! marks that variable as required.

If we execute now, we'll get an error:

{
  "error": {
    "errors": [
      {
        "message": "must be defined",
        "path": ["variable", "q"]
      }
    ],
    "data": null
  }
}

In the playground open up the Query Variables tab in lower left hand corner and populate these:

{
  "q": "msp430"
}

We'll now see our 3789 hits.

To recreate last example:

{
  "q": "msp430",
  "filters": {
    "manufacturer_id": ["370", "3330"]
  }
}

We'll now see the 3690 we saw earlier.

Multi Match

Search is designed to operate on a single query string and support complex operations like aggregation, sorting, filtering and pagination. Often, though, there is a list of Manufacturer + MPNs and a desire to match many line items at a time. This is common in the BOM use case, and for this we use the multi_match query.

{
  multi_match(
    queries: [
      { manufacturer: "Texas Instruments", mpn: "LM317T" },
      { mpn: "SN74S74N", reference: "test", limit: 5 }
    ]
  ) {
    hits
    reference
    parts {
      id
      slug
      mpn
      manufacturer {
        name
      }
    }
    error
  }
}

Example Clients

Python Client

This is a copy-pastable Python 2.7+ example client. As you can see it is just a starting point. You are encouraged to customize the query in get_parts and write new functions to match the operations you need for your application. If you prefer you could define a MyOctopartClient class to hold the client instance for you, add metrics, error handling, etc.

from six.moves import urllib
import json
import os

# copy pasted from: https://github.com/prisma-labs/python-graphql-client/blob/master/graphqlclient/client.py
class GraphQLClient:
    def __init__(self, endpoint):
        self.endpoint = endpoint
        self.token = None
        self.headername = None

    def execute(self, query, variables=None):
        return self._send(query, variables)

    def inject_token(self, token, headername='token'):
        self.token = token
        self.headername = headername

    def _send(self, query, variables):
        data = {'query': query,
                'variables': variables}
        headers = {'Accept': 'application/json',
                   'Content-Type': 'application/json'}

        if self.token is not None:
            headers[self.headername] = '{}'.format(self.token)

        req = urllib.request.Request(self.endpoint, json.dumps(data).encode('utf-8'), headers)

        try:
            response = urllib.request.urlopen(req)
            return response.read().decode('utf-8')
        except urllib.error.HTTPError as e:
            print((e.read()))
            print('')
            raise e

def get_parts(client, ids):
    query = '''
    query get_parts($ids: [String!]!) {
        parts(ids: $ids) {
            id
            manufacturer {
                name
            }
            mpn
            category {
                name
            }
        }
    }
    '''

    ids = [str(id) for id in ids]
    resp = client.execute(query, {'ids': ids})
    return json.loads(resp)['data']['parts']

def match_mpns(client, mpns):
    dsl = '''
    query match_mpns($queries: [PartMatchQuery!]!) {
        multi_match(queries: $queries) {
            hits
            reference
            parts {
                manufacturer {
                    name
                }
                mpn
            }
        }
    }
    '''

    queries = []
    for mpn in mpns:
        queries.append({
            'mpn_or_sku': mpn,
            'start': 0,
            'limit': 5,
            'reference': mpn,
        })
    resp = client.execute(dsl, {'queries': queries})
    return json.loads(resp)['data']['multi_match']

def demo_part_get(client):
    print('\n---------------- demo_part_get')
    ids = ["1", "2", "asdf", "4"]
    parts = get_parts(client, ids)

    for id, part in zip(ids, parts):
        print(id, '\t', part)

def demo_match_mpns(client):
    print('\n---------------- demo_match_mpns')
    mpns = [
        'CC4V-T1A 32.768KHZ +-20PPM 9PF',
        'LMC6482IMX/NOPB',
        'PCF8583T/F5,112',
        'FH12-5S-1SH(55)',
    ]
    matches = match_mpns(client, mpns)

    for match in matches:
        for part in match['parts']:
            print(match['reference'], '\t', part['manufacturer']['name'], '\t', part['mpn'])

if __name__ == '__main__':
    client = GraphQLClient('https://octopart.com/api/v4/endpoint')
    client.inject_token(os.getenv('OCTOPART_TOKEN'))
    demo_part_get(client)
    demo_match_mpns(client)

CURL example

curl -H "Content-Type: application/json" -X POST \
  -d '{"operationName":null,"variables":{},"query":"{ categories { name }}"}' \
  https://octopart.com/api/v4/endpoint?token=MY_TOKEN

Known Issues

At the moment, the GraphQL Playground is not working on Internet Explorer browsers. We're working to get this resource up and running for all browsers. In the meantime, we recommend using an alternate browser of your choice while using the GraphQL Playground.