This article will show you how to use the Octopart API using Python.
Octopart is a product of Nexar Cloud Platform. Nexar is a division of AltiumĀ®, and in Feb 2024 Renesas Electronics announced the acquisition of Altium.
Nexar has 8 products, one is Octopart and another is the API access to Octopart data which they call the Nexar API. For simplicity I will continue to refer to it as the Octopart API.
An important thing to understand about API's is that every one is custom.
While there are certain conventions, every API has been set up and configured differently depending on the implementation of the API owner.
The most common types of API are REST, SOAP, and GraphQL.
Octopart once used REST, but now uses GraphQL.
This makes it easy to request very specific data, like say the lifecycle status for a part. Sometimes this is very helpful. But...
A very important consideration with Octopart is the distinction between a query and matched parts. A single query may have X number of matched parts and may return Y number of data fields.
You pay for the number of matched parts in every query no matter how many data fields you return.
This tends to make it in your interest to request a large amount of data for each matched part and then parse out what you actually want from the returned JSON.
If you make a single query with a wildcard at the end that returns 100 part numbers, that is 100 matched parts even if you only requested lifecycle status for each one.
You can limit the number of matched parts returned, be sure you do!
The Octopart API is divided into two data sets which they call Scope, Design and Supply. You can access these depending on what you sign up and pay for.
Today we will focus on the Supply Scope.
You start here to sign up with Nexar for API access. Initially you have up to 100 matched parts in their Playground for free.
Once signed up there is a free tier that allows up to 1000 matched parts.
After signing up you will log into the Portal, you may need to be patient and reload the page a couple times especially if returning from the day before.
Once in the Portal you will create an app via the Create app button.
Then go your app, then to the Authorization tab, generate an Access Token, then paste your Access Token, Client ID, and Client Secret somewhere secure for use in a moment.
Here is code to place near the top of your script that will be used with the specific queries later.
You will need to manage your ID and Secret according to your best practice.
For simplicity you can simply replace the variables NEXAR_CLIENT_ID and NEXAR_CLIENT_SECRET with text you saved earlier.
This approach is fine for quick start, but remember to go back and use better secrets management later.
import httpx #pip install if necessary# Global session for API's
client = httpx.Client()
#Initialize GraphQL Query
clientId = NEXAR_CLIENT_ID
clientSecret = NEXAR_CLIENT_SECRET
NEXAR_URL = "https://api.nexar.com/graphql"
PROD_TOKEN_URL = "https://identity.nexar.com/connect/token"
def get_token(client_id, client_secret):
"""Return the Nexar token from the client_id and client_secret provided."""
if not client_id or not client_secret:
raise Exception("client_id and/or client_secret are empty")
if 'token' in st.session_state:
token = st.session_state['token']
else:
token = {}
try:
#token = requests.post(
token = client.post(
url=PROD_TOKEN_URL,
data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret
},
follow_redirects=False,
).json()
except Exception:
raise
st.session_state['token'] = token
return token
def decodeJWT(token):
return json.loads(
(base64.urlsafe_b64decode(token.split(".")[1] + "==")).decode("utf-8")
)
class NexarClient:
def __init__(self, id, secret) -> None:
self.id = id
self.secret = secret
self.s = httpx.Client()
self.s.keep_alive = False
self.token = st.session_state.get('token', get_token(id, secret))
#self.token = get_token(id, secret)
self.s.headers.update({"token": self.token.get('access_token')})
self.exp = decodeJWT(self.token.get('access_token')).get('exp')
def check_exp(self):
if (self.exp < time.time() + 300):
self.token = st.session_state.get('token', get_token(self.id, self.secret))
#self.token = get_token(self.id, self.secret)
self.s.headers.update({"token": self.token.get('access_token')})
self.exp = decodeJWT(self.token.get('access_token')).get('exp')
def get_query(self, query: str, variables: Dict) -> dict:
"""Return Nexar response for the query."""
try:
self.check_exp()
r = self.s.post(
NEXAR_URL,
json={"query": query, "variables": variables},
)
except Exception as e:
print(e)
raise Exception("Error while getting Nexar response")
response = r.json()
if ("errors" in response):
for error in response["errors"]: print(error["message"])
raise SystemExit
return response["data"]
nexar = NexarClient(clientId, clientSecret)
Whew. With this code in place you are ready to make a query. Here is a base template you can use.
def SearchMPN(que):
gqlQuery = '''
query SearchMPN ($que: String! {
supSearch(
q: $que
start: 0
limit: 1
){
results {
part {
mpn
genericMpn
akaMpns
manufacturer {name}
shortDescription
sellers (authorizedOnly: true) {
company {name}
offers {
packaging
factoryPackQuantity
multipackQuantity
inventoryLevel
moq
orderMultiple
prices {
quantity
price
}
clickUrl
}
}
}
}
}
}
'''
# Execute the query with the provided query variable
data = nexar.get_query(gqlQuery, {"que": que})
return data
This code creates a Python function named SearchMPN that requires a text input which will be a part number. You might use it something like this:
part = "AD7685ARM"
part_json_data = SearchMPN(part)
Now the variable part_json_data will contain all the requested fields in JSON format.
Let's breakdown the query itself.
Notice the lines start and limit.
Remember a query may want to return multiple matched parts. These lines tell the API to return matched parts beginning with the first one (0 is the first record number in Python) and to return only 1.
That is how you limit the number of matched parts returned.
The labels SearchMPN are not used by the API and can be whatever you want.
SupSearch is the important part. This is part of the GraphQL query language that was created by the designer of the API.
Meet your new best friend, the Interactive Schema.
It is too large and complex to display here, but the important thing is to start with the table on the left, these are Query Roots.
All queries must begin with one of these Query Roots.
If you look at the Schema you will see a root named supSuggest with a line to the fields available for return.
Notice the variables q, start, and limit, are not specified in the Schema for supSuggest.
The only way I could discover the variables was by trial and error in the Playground, which will autocomplete as you type. The same is true for the authorizedOnly: true filter after sellers.
In the Schema, follow the line to SupPartResultSet. You will never use this name. You may specify any of the fields in SupPartResultSet in your query.
Notice that each field might be a Int!, String!, or another result set. If it is another result set you must specify what you want from that result set, and this can continue many layers deep.
As in the example above, you will very frequently want to query supSuggest>results>parts. Hopefully by comparing the Schema to the code example above you will understand how to get to what you want.
Now that you have your JSON file you can use ChatGPT to guide you with how to parse and use the JSON.
Just provide ChatGPT a sample of the output so it understands the JSON structure, then describe what you want to accomplish.
Once you are able to return this data into your own applications you will have opened up a whole new world of component data connectivity, good luck!