How To Use The Octopart API
Everett Frank
?? CEO, Consultant, Advisor/ Electronics / AI Workflow Automation / AI Agents / Co-Founder at SnapChip / CEO DigiSource / ?? Upskilling Python, CoT, Salsa dancing.
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.
API Basics
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!
Getting Started
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.
Using the API with Python
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 just 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") ? ? ? ?
? ? 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
? ? ? ??
? return token
def decodeJWT(token): ?
? ? return {
? ? ? ? "exp": time.time() + 3600 ?# Token expires in 1 hour for demonstration
? ? }
class NexarClient:
token_flag = False
? ? def __init__(self, id, secret) -> None:
? ? ? ? self.id = id
? ? ? ? self.secret = secret
? ? ? ? self.s = httpx.Client()
? ? ? self.s.keep_alive = False ? ? ?
? ? ? ? # Perform token initialization only once
? ? ? ? if not NexarClient.token_flag:
? ? ? ? ? ? self.token = self.retrieve_or_generate_token()
? ? ? ? ? ? # Update headers with the current token
? ? ? ? ? ? self.s.headers.update({"Authorization": f"Bearer {self.token.get('access_token')}"})
? ? ? ? ? ? self.exp = decodeJWT(self.token.get('access_token')).get('exp')
? ? ? ? ? ? NexarClient.token_flag = True ?# Set flag to True after initialization
? ? ? ? else:
? ? ? ? ? ? print("Token already initialized.")
def retrieve_or_generate_token(self):
? ? ? """Retrieve token or generate a new one if necessary."""
? ? ? try: ? ? ? ? ?
? ? ? ? ? ? if token_data:
? ? ? ? ? ? ? ? # Check expiration
? ? ? ? ? ? ? ? exp = decodeJWT(token_data['access_token']).get('exp')
? ? ? ? ? ? ? ? if exp < time.time() + 300:
? ? ? ? ? ? ? ? ? ? print("Token expired or about to expire. Generating a new one.")
? ? ? ? ? ? ? ? ? token_data = get_token(self.id, self.secret) ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? #print("Token not expired.")
? ? ? ? ? ? ? ? ? ? pass
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? #print("No token found. Generating a new one.")
? ? ? ? ? ? ? token_data = get_token(self.id, self.secret) ? ? ? ? ? ? ?
? ? ? ? ? return token_data
def get_query(self, query: str, variables: Dict) -> dict:
"""Return Nexar response for the query."""
? ? ? ? ?if NexarClient.token_flag:
try:
r = self.s.post(
NEXAR_URL,
json={"query": query, "variables": variables},
)
response = r.json()
# Handle unauthorized error indicating token issues
? ? ? ? ? ? if r.status_code == 401 or "errors" in response:
? ? ? ? ? ? #print("Token validation failed. Please provide a valid access token.") ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? # Regenerate a new token
? ? ? ? ? ? ? ? ? #print("Regenerating a new token...")
? ? ? ? ? ? ? ? ? self.token = self.retrieve_or_generate_token()
? ? ? ? ? ? ? ? ? self.s.headers.update({"Authorization": f"Bearer {self.token.get('access_token')}"})
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? # Retry the query with the new token
? ? ? ? ? ? ? ? ? r = self.s.post(
? ? ? ? ? ? ? ? ? ? ? NEXAR_URL,
? ? ? ? ? ? ? ? ? ? ? json={"query": query, "variables": variables},
? ? ? ? ? ? ? ? ? )
? ? ? ? ? ? ? ? ? response = r.json() ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ??
? ? ? ? ? except Exception as e:
? ? ? ? ? ? ? #print(e)
? ? ? ? ? ? ? raise Exception("Exception error while getting Nexar response")
? ? ? ? ? if "errors" in response:
? ? ? ? ? ? for error in response["errors"]:
? ? ? ? ? ? ? ? ? #print(error["message"])
? ? ? ? ? ? ? ? ? raise Exception("Errors in response while getting Nexar response")
? ? ? ? ? ? ? ??
? ? ? ? ? return response["data"]
# Reusing a single NexarClient instance
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.
Introducing the Schema
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!