Go SDK - Developer

Obtain the SDK The Go SDK is currently in a pre-release, experimental state. While in this state, we reserve the right to make any changes to it (including breaking changes) without worrying about backwards compatibility, semantic versioning, and so on. If you are eager to experiment with it, it is available on GitHub . You can use Go dependencies to install it directly from there. We welcome your feedback during the pre-release, but cannot commit to any specific revisions or timelines at this point in time. Configure the SDK There are two ways to configure the SDK: Using environment variables ATLAN_API_KEY should be given your Atlan API token , for authentication ( don't forget to assign one or more personas to the API token to give access to existing assets! ) ATLAN_BASE_URL should be given your Atlan URL (for example, https://tenant.atlan.com ) Here's an example of setting those environment variables: On client creation If you prefer to not use environment variables, you can do the following: Careful not to expose your API token! We generally discourage including your API token directly in your code, in case you accidentally commit it into a (public) version control system. But it's your choice exactly how you manage the API token and including it for use within the client. That's it — once these are set you can start using your SDK to make live calls against your Atlan instance! 🎉 Delve into more detailed examples: Common tasks Common operations on assets, that are available across all assets. Discover actions Common operations on assets, that are available across all assets. Asset-specific Operations that are specific to certain assets. Focus on a specific kind of asset Operations that are specific to certain assets. Focus on a specific kind of asset Governance structures Operations dealing with governance structures, rather than assets. Manage governance structures Operations dealing with governance structures, rather than assets. Manage governance structures Samples Real code samples our customers use to solve particular use cases. Review live samples Real code samples our customers use to solve particular use cases. Review live samples Events Delve deep into the details of the events Atlan triggers. Learn more about events Delve deep into the details of the events Atlan triggers. Learn more about events The SDK defines exceptions for the following categories of error: A given API call could fail due to all of the errors above. So these all extend a generic AtlanError exception, and all API operations can potentially raise AtlanError . For example, when creating a connection there is an asynchronous process that grants permissions to the admins of that connection. So there can be a slight delay between creating the connection and being permitted to do any operations with the connection. During that delay, any attempt to interact with the connection will result in a PermissionError , even if your API token was used to create connection in the first place. Another example you may occasionally hit is some network issue that causes your connection to Atlan to be interrupted. In these cases, an ApiConnectionError will be raised. Atlan is a distributed, cloud-native application, where network problems can arise. The SDK therefore automatically attempts to handle ephemeral problems. The SDK uses the slog library internally to provide a flexible framework for emitting log messages. You can enable logging for your SDK script by adding the following lines above your snippets: You can enable logging by using .SetLogger() on the context object with various logging levels: "debug" : used to give detailed information, typically of interest only when diagnosing problems (mostly used level in SDK). "info" : used to confirm that things are working as expected. "warn" : used as an indication that something unexpected happened, or as a warning of some problem in the near future. "error" : indicates that due to a more serious problem, the SDK has not been able to perform some operation. You can enable logging by using .SetLogger() on the context object with various logging levels: "debug" : used to give detailed information, typically of interest only when diagnosing problems (mostly used level in SDK). "info" : used to confirm that things are working as expected. "warn" : used as an indication that something unexpected happened, or as a warning of some problem in the near future. "error" : indicates that due to a more serious problem, the SDK has not been able to perform some operation.


Introductory walkthrough - Developer

An introductory walkthrough You might also like our Atlan Platform Essentials certification . Not sure where to start? Allow us to introduce Atlan development through example. 1 We strongly recommend using one of our SDKs to simplify the development process. As a first step, set one up: The SDK is available on Maven Central , ready to be included in your project: Include the latest version of the Java SDK in your project as a dependency. You can also give a specific version instead of the + , if you'd like. The Java SDK uses slf4j for logging purposes. You can include logback as a simple binding mechanism to send any logging information out to your console (standard out). Provide two values to create an Atlan client: Provide your Atlan tenant URL as the first parameter. You can also read the value from an environment variable, if you leave out both parameters. Provide your API token as the second parameter. You can also read the value from another environment variable, by leaving out this parameter. You can then start writing some actual code to run within a static main method. (We'll show some examples of this further below.) Once the block is complete, any resources held by the client (i.e. for caching) will be automatically released. Set up logging for SDK You can also checkout to the advanced configuration section of the SDK to learn about how to set up logging. The SDK is available on PyPI . You can use pip to install it as follows: Provide two values to create an Atlan client: Provide your Atlan tenant URL to the base_url parameter. (You can also do this through environment variables .) Provide your API token to the api_key parameter. (You can also do this through environment variables .) Set up logging for SDK You can also checkout to the advanced configuration section of the SDK to learn about how to set up logging. The SDK is available on Maven Central , ready to be included in your project: Include the latest version of the Java SDK in your project as a dependency. You can also give a specific version instead of the + , if you'd like. The Java SDK uses slf4j for logging purposes. You can include slf4j-simple as a simple binding mechanism to send any logging information out to your console (standard out), along with the kotlin-logging-jvm microutil. Provide two values to create an Atlan client: Provide your Atlan tenant URL as the first parameter. You can also read the value from an environment variable, if you leave out both parameters. Provide your API token as the second parameter. You can also read the value from another environment variable, by leaving out this parameter. You can then start writing some actual code to run within a static main method. (We'll show some examples of this further below.) Once the block is complete, any resources held by the client (i.e. for caching) will be automatically released. Set up logging for SDK You can also checkout to the advanced configuration section of the SDK to learn about how to set up logging. The SDK is available on GitHub , ready to be included in your project: Provide two values to set up connectivity to Atlan: Provide your Atlan tenant URL to the assets.Context() method. If you prefer using the value from an environment variable, you can use assets.NewContext() without any parameters. Provide your API token as the second parameter to the assets.Context() method. (Or again, have it picked up automatically by the assets.NewContext() method.) Set up logging for SDK You can also checkout to the advanced configuration section of the SDK to learn about how to set up logging. Don't forget to give permissions If you want to be able to access existing metadata with an API token, don't forget that you need to assign one or more personas to the API token that grant it access to metadata. Now that you have an SDK installed and configured, you are ready to code! Before we jump straight to code, though, let's first introduce some key concepts in Atlan: What is an asset? In Atlan, we refer to all objects that provide context to your data as assets . Each type of asset in Atlan has a set of: Properties , such as: Certificates Announcements Properties , such as: Relationships to other assets, such as: Schema child tables Table parent schema Table child columns Column parent table Relationships to other assets, such as: Schema child tables Table parent schema Table child columns Column parent table In an object-oriented programming sense, think of an asset as an instance of a class. The structure of an asset (the class itself, in this analogy) is defined by something called a type definition , but that's for another day. So as you can see: There are many different kinds of assets: tables, columns, schemas, databases, business intelligence dashboards, reports, and so on. Assets inter-relate with each other: a table has a parent schema and child columns, a schema has a parent database and child tables, and so on. Different kinds of assets have some common properties (like certificates) and other properties that are unique to that kind of asset (like a columnCount that only exists on tables, not on schemas or databases). When you know the asset When you already know which asset you want to retrieve, you can read it from Atlan using one of its identifiers . We'll discuss these in more detail as part of updates, but for now you can think of them as: is a primary key for an asset: completely unique, but meaningless by itself is a business key for an asset: unique for a given kind of asset, and interpretable You can retrieve an asset using the static get() method on any asset type, providing the client and either the asset's GUID or qualifiedName . (Each asset type is its own unique class in the SDK.) You can retrieve an asset using the asset.get_by_guid() method on the Atlan client, providing both the type of asset you expect to retrieve and its GUID. (Each asset type is its own unique class in the SDK.) You can also retrieve an asset using the asset.get_by_qualified_name() method on the Atlan client, providing the type of asset you expect to retrieve and its qualified_name . (Each asset type is its own unique class in the SDK.) You can retrieve an asset using the static get() method on any asset type, providing the client and either the asset's GUID or qualifiedName . (Each asset type is its own unique class in the SDK.) You can retrieve an asset using the assets.GetByGuid() method on the Atlan client, providing both the type of asset you expect to retrieve and its GUID. (Each asset type is its own unique class in the SDK.) You can also retrieve an asset using the assets.GetByQualifiedName() method on the Atlan client, providing the type of asset you expect to retrieve and its qualifiedName . (Each asset type is its own unique class in the SDK.) Note that the response is strongly typed: If you are retrieving a table, you will get a table back (as long as it exists). You do not need to figure out what properties or relationships exist on a table - the Table class defines them for for you already. In any modern IDE, this means you have type-ahead support for retrieving the properties and relationships from the table variable. You can also refer to the types reference in this portal for full details of every kind of asset. Retrieval by identifier can be more costly than you might expect Even though you are retrieving an asset by an identifier, this can be more costly than you might expect. Retrieving an asset in this way will: Retrieve all its properties and their values Retrieve all its relationships Imagine the asset you are retrieving has 100's or 1000's of these. If you only care about its certificate and any owners, you will be retrieving far more information than you need. When you need to find it first For example, imagine you want to find all tables named MY_TABLE : You can then run the request using Execute() . For example, if you want to know the certificate of the asset you only need to tack that onto the query: Only this line differs from the original query. You can chain as many includeOnResults calls as you want to specify the properties and relationships you want to retrieve for matching assets. Only this line differs from the original query. You can chain as many include_on_results calls as you want to specify the properties and relationships you want to retrieve for matching assets. Only this line differs from the original query. You can chain as many includeOnResults calls as you want to specify the properties and relationships you want to retrieve for matching assets. Only this line differs from the original query. You can include as many attributes in IncludeOnResults as you want to specify the properties and relationships you want to retrieve for matching assets. Also gives the best performance If all you want to do is check or report on metadata, you should have a starting point from the information above. Or, now that you've found an asset of interest, maybe you want to update the asset with additional metadata ? Once again, before we jump to code, let's first understand some key concepts about how Atlan handles updates: Importance of identifiers Most operations on assets are upserts , that is, they could either create (insert) or update a given asset. How do you know which is going to happen? To answer this question, you need to understand how Atlan uniquely identifies each asset. Recall earlier we discussed asset's different identifiers in Atlan . Every asset in Atlan has at least the following two unique identifiers. These are both mandatory for every asset, so no asset can exist without these: Atlan uses globally-unique identifiers (GUIDs) to uniquely identify each asset, globally . They look something like this: As the name implies, GUIDs are: Globally unique (across all systems). Generated in a way that makes it nearly impossible for anything else to ever generate that same ID. 2 Note that this means the GUID itself is not : Meaningful or capable of being interpreted in any way Atlan uses qualifiedName s to uniquely identify assets based on their characteristics. They look something like this: Qualified names are not : Globally unique (across all systems). Instead, they are: Consistently constructed in a meaningful way, making it possible for them to be reconstructed. Note that this means the qualifiedName is: Meaningful and capable of being interpreted How these impact updates Since they are truly unique, operations that include a GUID will only update an asset, not create one. Conversely, operations that take a qualifiedName can: Create an asset, if no exactly-matching qualifiedName is found in Atlan. Update an asset, if an exact-match for the qualifiedName is found in Atlan. These operations also require a typeName , so that if creation does occur the correct type of asset is created. Unintended consequences of this behavior Be careful when using operations with only the qualifiedName . You may end up creating assets when you were only expecting them to be updated or to fail if they did not already exist. This is particularly true when you do not give the exact, case-sensitive qualifiedName of an asset. a/b/c/d is not the same as a/B/c/d when it comes to qualifiedName s. Perhaps this leaves you wondering: why have a qualifiedName at all? The qualifiedName 's purpose is to identify what is a unique asset. Many different tools might all have information about that asset. Having a common "identity" means that many different systems can each independently construct its identifier the same way. If a crawler gets table details from Snowflake it can upsert based on those identity characteristics in Atlan. The crawler will not create duplicate tables every time it runs. This gives idempotency. Looker knows the same identity characteristics for the Snowflake tables and columns. So if you get details from Looker about the tables it uses for reporting, you can link them together in lineage. (Looker can construct the same identifier for the table as Snowflake itself.) These characteristics are not possible using GUIDs alone. Limit to changes only Now that you understand the nuances of identifiers, let's look at how you can update metadata in Atlan. In general, you only need to send changes to Atlan. You do not need to send an entire asset each time you want to make changes to it. For example, imagine you want to mark a table as certified but do not want to change anything else (its name, description, owner details, and so on): You can update an asset without first looking the asset up, if you know (can construct) its identifying qualifiedName . Using the updater() static method on any asset type, you pass in (typically) the qualifiedName and name of the asset. This returns a builder onto which you can then chain any updates. You can then chain onto the returned builder as many updates as you want. In this example, we change the certificate status to VERIFIED . At the end of your chain of updates, you need to build the builder (into an object, in-memory). And then, finally, you need to .save() that object to persist those changes in Atlan (passing the client for the tenant you want to save it in). The response will contain details of the change: whether the asset was created, updated, or nothing happened because the asset already had those changes. You can update an asset without first looking the asset up, if you know (can construct) its identifying qualified_name . Using the updater() class method on any asset type, you pass in (typically) the qualified_name and name of the asset. You can then add onto the returned object as many updates as you want. In this example, we change the certificate status to VERIFIED . And then, finally, you need to client.asset.save() that object to persist those changes in Atlan. The response will contain details of the change: whether the asset was created, updated, or nothing happened because the asset already had those changes. You can update an asset without first looking the asset up, if you know (can construct) its identifying qualifiedName . Using the updater() static method on any asset type, you pass in (typically) the qualifiedName and name of the asset. This returns a builder onto which you can then chain any updates. You can then chain onto the returned builder as many updates as you want. In this example, we change the certificate status to VERIFIED . At the end of your chain of updates, you need to build the builder (into an object, in-memory). And then, finally, you need to .save() that object to persist those changes in Atlan (passing the client for the tenant you want to save it in). The response will contain details of the change: whether the asset was created, updated, or nothing happened because the asset already had those changes. You can update an asset without first looking the asset up, if you know (can construct) its identifying qualifiedName . Using the Updater() method on any asset type, you pass in (typically) the qualifiedName and name of the asset. This returns an object into which you can then place any updates. You can place into the returned object as many updates as you want. In this example, we change the certificate status to VERIFIED . And then, finally, you need to .Save() that object to persist those changes in Atlan. The response will contain details of the change: whether the asset was created, updated, or nothing happened because the asset already had those changes. Atlan will handle idempotency By sending only the changes you want to apply, Atlan can make idempotent updates. Atlan will only attempt to update the asset with the changes you send. Atlan leaves any existing metadata on the asset as-is. If the asset already has the metadata values you are sending, Atlan does nothing. It will not even update audit details like the last update timestamp, and is thus idempotent. What if you want to make changes to many assets, as efficiently as possible? Start by initializing a batch. Through this batch, we can automatically queue up and bulk-upsert assets — in this example, 20 at a time. Be sure to include any details you might need to make a decision about whether to update the asset or not (and what to update it with). You must flush() the batch outside of any loop where you've added assets into it. This ensures any final remaining elements in the batch are still sent to Atlan, even if the batch is not "full". Finally, from the batch you can retrieve the minimal details about any assets it created or updated. Start by initializing a batch. Through this batch, we can automatically queue up and bulk-upsert assets — in this example, 20 at a time. Be sure to include any details you might need to make a decision about whether to update the asset or not (and what to update it with). You can then add() any updated objects directly into the batch you created earlier. The batch itself will handle saving these to Atlan when a sufficient number have been queued up (20, in this example). You must flush() the batch outside of any loop where you've added assets into it. This ensures any final remaining elements in the batch are still sent to Atlan, even if the batch is not "full". Finally, from the batch you can retrieve the minimal details about any assets it created or updated. Start by initializing a batch. Through this batch, we can automatically queue up and bulk-upsert assets — in this example, 20 at a time. Be sure to include any details you might need to make a decision about whether to update the asset or not (and what to update it with). You must flush() the batch outside of any loop where you've added assets into it. This ensures any final remaining elements in the batch are still sent to Atlan, even if the batch is not "full". Finally, from the batch you can retrieve the minimal details about any assets it created or updated. Start by initializing a batch. Through this batch, we can automatically queue up and bulk-upsert assets — in this example, 20 at a time. Be sure to include any details you might need to make a decision about whether to update the asset or not (and what to update it with). You can then add() any updated objects directly into the batch you created earlier. The batch itself will handle saving these to Atlan when a sufficient number have been queued up (20, in this example). You must flush() the batch outside of any loop where you've added assets into it. This ensures any final remaining elements in the batch are still sent to Atlan, even if the batch is not "full". Finally, from the batch you can retrieve the minimal details about any assets it created or updated. Where to go from here Common tasks Common operations on assets, that are available across all assets. Discover actions Common operations on assets, that are available across all assets. Asset-specific Operations that are specific to certain assets. Focus on a specific kind of asset Operations that are specific to certain assets. Focus on a specific kind of asset Governance structures Operations dealing with governance structures, rather than assets. Manage governance structures Operations dealing with governance structures, rather than assets. Manage governance structures Samples Real code samples our customers use to solve particular use cases. Review live samples Real code samples our customers use to solve particular use cases. Review live samples Events Delve deep into the details of the events Atlan triggers. Learn more about events Delve deep into the details of the events Atlan triggers. Learn more about events Note that this is intentionally kept as simple as possible. The walkthrough is not intended to be exhaustive. Where possible, we have cross-referenced other detailed examples elsewhere in the site. ↩ Note that this is intentionally kept as simple as possible. The walkthrough is not intended to be exhaustive. Where possible, we have cross-referenced other detailed examples elsewhere in the site. ↩ There are orders of magnitude lower chances of GUIDs conflicting with each other than there are grains of sand on the planet. (And generating them does not rely on a central ID-assigning registry.) ↩ There are orders of magnitude lower chances of GUIDs conflicting with each other than there are grains of sand on the planet. (And generating them does not rely on a central ID-assigning registry.) ↩


Introductory walkthrough - Developer


Retrieving assets - Developer

Strictly speaking, no, you do not. And in fact if you ultimately intend to update an asset you should trim it down to only what you intend to change and not send a complete asset. See Updating an asset for more details. Retrieving an asset uses a slightly different pattern from the other operations. For this you can use static methods provided by the Asset class: To retrieve an asset by its GUID: If no exception is thrown, the returned object will be non-null and of the type requested. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Compile-time type checking This operation will type-check the asset you are retrieving is of the type requested. If it is not, you will receive a NotFoundException , even if the GUID represents some other asset. client.asset.get_by_guid() method takes following parameters: guid : specify the (GUID) of the asset to retrieve. asset_type ( optional ): specify the type of asset to retrieve. Defaults to Asset . If no exception is thrown, the returned object will be non-null and of the type requested. min_ext_info ( optional ): minimizes additional information when set to True . Defaults to False ignore_relationships ( optional ): specify whether to include relationships ( False ) or exclude them ( True ). Defaults to True attributes ( optional ): defines the list of attributes to retrieve for the asset. Accepts either a list of strings or a list of AtlanField . related_attributes ( optional ): defines the list of relationship attributes to retrieve for the asset. Accepts either a list of strings or a list of AtlanField . Attributes and Related attributes Run-time type checking This operation will type-check the asset you are retrieving is of the type requested. If it is not, you will receive a NotFoundException , even if the GUID represents some other asset. If no exception is thrown, the returned object will be non-null and of the type requested. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Compile-time type checking This operation will type-check the asset you are retrieving is of the type requested. If it is not, you will receive a NotFoundException , even if the GUID represents some other asset. In the case of retrieving an asset, all necessary information is included in the URL of the request. There is no payload for the body of the request. By GUID (runtime typing) To retrieve an asset by GUID, but only resolve the type at runtime: Retrieve the asset by its GUID. Since GUIDs are globally unique, you do not need to specify a type. (And this is why the operation returns a generic Asset , since the SDK can only determine the type at runtime, once it has a response back from Atlan.) Since the operation returns a generic Asset , you need to check and cast it to a more specific type if you want to access the more specific attributes of that type. client.asset.get_by_guid() method takes following parameters: guid : specify the (GUID) of the asset to retrieve. asset_type ( optional ): specify the type of asset to retrieve. Defaults to Asset . If no exception is thrown, the returned object will be non-null and of the type requested. min_ext_info ( optional ): minimizes additional information when set to True . Defaults to False ignore_relationships ( optional ): specify whether to include relationships ( False ) or exclude them ( True ). Defaults to True attributes ( optional ): defines the list of attributes to retrieve for the asset. Accepts either a list of strings or a list of AtlanField . related_attributes ( optional ): defines the list of relationship attributes to retrieve for the asset. Accepts either a list of strings or a list of AtlanField . Attributes and Related attributes Since the operation returns a generic Asset , you need to use isinstance() to cast it to a more specific type in the block if you want an IDE to provide more specific type hints. Since the operation returns a generic Asset , you need to use isinstance() to cast it to a more specific type in the block if you want an IDE to provide more specific type hints. Retrieve the asset by its GUID. Since GUIDs are globally unique, you do not need to specify a type. (And this is why the operation returns a generic Asset , since the SDK can only determine the type at runtime, once it has a response back from Atlan.) Since the operation returns a generic Asset , you need to check and cast it to a more specific type if you want to access the more specific attributes of that type. Does not apply to a raw API request There is no concept of typing in a raw API request — all responses to the raw API will simply be JSON objects. To retrieve an asset by its qualifiedName : If no exception is thrown, the returned object will be non-null and of the type requested. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Qualified name, not name For most objects, you can probably build-up the qualifiedName in your code directly. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Finding the connection portion The one exception is likely to be the connection portion of the name ( default/snowflake/1657037873 in this example). To find this portion, see Find connections . For most objects, you can probably build-up the qualifiedName in your code directly. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Finding the connection portion The one exception is likely to be the connection portion of the name ( default/snowflake/1657037873 in this example). To find this portion, see Find connections . client.asset.get_by_qualified_name() method takes following parameters: qualified_name : specify the qualified name of the asset to retrieve. asset_type : specify the type of asset to retrieve. If no exception is thrown, the returned object will be non-null and of the type requested. min_ext_info ( optional ): minimizes additional information when set to True . Defaults to False ignore_relationships ( optional ): specify whether to include relationships ( False ) or exclude them ( True ). Defaults to True attributes ( optional ): defines the list of attributes to retrieve for the asset. Accepts either a list of strings or a list of AtlanField . related_attributes ( optional ): defines the list of relationship attributes to retrieve for the asset. Accepts either a list of strings or a list of AtlanField . Attributes and Related attributes For most objects, you can probably build-up the qualified_name in your code directly. Finding the connection portion The one exception is likely to be the connection portion of the name ( default/snowflake/1657037873 in this example). To find this portion, see Find connections . For most objects, you can probably build-up the qualified_name in your code directly. Finding the connection portion The one exception is likely to be the connection portion of the name ( default/snowflake/1657037873 in this example). To find this portion, see Find connections . If no exception is thrown, the returned object will be non-null and of the type requested. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Qualified name, not name For most objects, you can probably build-up the qualifiedName in your code directly. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Finding the connection portion The one exception is likely to be the connection portion of the name ( default/snowflake/1657037873 in this example). To find this portion, see Find connections . For most objects, you can probably build-up the qualifiedName in your code directly. Because this operation will read the asset from Atlan, you must provide it an AtlanClient through which to connect to the tenant. Finding the connection portion The one exception is likely to be the connection portion of the name ( default/snowflake/1657037873 in this example). To find this portion, see Find connections . In the case of retrieving an asset, all necessary information is included in the URL of the request. There is no payload for the body of the request. URL encoding may be needed Note that depending on the qualifiedName, you may need to URL-encode its value before sending. This is to replace any parts of the name that could be misinterpreted as actual URL components (like / or spaces). In the case of retrieving an asset, all necessary information is included in the URL of the request. There is no payload for the body of the request. URL encoding may be needed Note that depending on the qualifiedName, you may need to URL-encode its value before sending. This is to replace any parts of the name that could be misinterpreted as actual URL components (like / or spaces). Full vs minimal assets The examples above illustrate how to retrieve: an asset with all of its relationships (a complete asset). an asset without any of its relationships (a minimal asset). You can also retrieve the opposite by explicitly requesting it: Retrieve the full asset, with all of its relationships, by its GUID. The last (optional) parameter being true indicates you want to retrieve the asset with all its relationships (a "full" asset). Similar variations exist on every asset as well as on the dynamically-typed Asset static methods. Optionally, you can provide the asset type: If no exception is thrown, the returned object will be non-null and of the type requested. If no exception is thrown, the returned object will be non-null and of the type requested. Retrieve the full asset, with all of its relationships, by its GUID. The last (optional) parameter being true indicates you want to retrieve the asset with all its relationships (a "full" asset). Similar variations exist on every asset as well as on the dynamically-typed Asset static methods. In the case of retrieving an asset, all necessary information is included in the URL of the request. Retrieving a minimal asset is a matter of setting the query parameters ignoreRelationships and minExtInfo to true . Retrieve minimal assets where possible You should retrieve minimal assets for better performance in cases where you do not need all of the relationships of the asset. Keep in mind that although the relationships will not be visible in the object after retrieving a minimal asset, this does not mean that there are no relationships on that asset (in Atlan).


Full model reference - Developer

Full model reference Our SDKs are strongly-typed to represent every type 's attributes and relationships directly. This reduces the burden on you to understand how these are named, capitalized, spelled, or even the type of data they possess — since all of those details are encoded directly into the models the SDKs use. Here you will find a complete reference of all of these attributes and relationships. In certain rare cases, our strongly-typed model might not (yet) include a property you need to access. In these cases, you can always directly access the raw properties returned in every API response. For example, when retrieving workflow credentials the response object does not include extra details that are connector-specific. However, you can still access these extra properties: Use the getRawJsonObject() accessor to access the entire (raw) response object from the API. For this credential example getRawJsonObject() looks like: { "id" : "e3d74922-e2e8-4dbe-a7ed-3937e5153a51" , "version" : "super-king-1886" , "isActive" : true , "createdAt" : 1719240600149 , "updatedAt" : 1719240600149 , "createdBy" : "service-account-apikey-5aca94d3-f0a3-4af5-b074-567e209c1b75" , "tenantId" : "default" , "name" : "default-snowflake-1719240599-0" , "description" : null , "connectorConfigName" : "atlan-connectors-snowflake" , "connector" : "snowflake" , "connectorType" : "jdbc" , "authType" : "basic" , "host" : "abc123.snowflakecomputing.com" , "port" : 443 , "metadata" : null , "level" : null , "connection" : null , "username" : "atlan-user" , "extra" : { "role" : "ADMIN" , "warehouse" : "DEV" } } Use the getRawJsonObject() accessor to access the entire (raw) response object from the API. For this credential example getRawJsonObject() looks like: Use __atlan_extra__ dict field for any response model to access extra API response properties. For this credential example __atlan_extra__ looks like: { "username" : "atlan-user" , "extra" : { "role" : "ADMIN" , "warehouse" : "DEV" } } Use __atlan_extra__ dict field for any response model to access extra API response properties. For this credential example __atlan_extra__ looks like: Use the rawJsonObject field to access the entire (raw) response object from the API. For this credential example rawJsonObject looks like: { "id" : "e3d74922-e2e8-4dbe-a7ed-3937e5153a51" , "version" : "super-king-1886" , "isActive" : true , "createdAt" : 1719240600149 , "updatedAt" : 1719240600149 , "createdBy" : "service-account-apikey-5aca94d3-f0a3-4af5-b074-567e209c1b75" , "tenantId" : "default" , "name" : "default-snowflake-1719240599-0" , "description" : null , "connectorConfigName" : "atlan-connectors-snowflake" , "connector" : "snowflake" , "connectorType" : "jdbc" , "authType" : "basic" , "host" : "abc123.snowflakecomputing.com" , "port" : 443 , "metadata" : null , "level" : null , "connection" : null , "username" : "atlan-user" , "extra" : { "role" : "ADMIN" , "warehouse" : "DEV" } } Use the rawJsonObject field to access the entire (raw) response object from the API. For this credential example rawJsonObject looks like: These are all the metadata assets currently available through Atlan's SDKs:


Searching for assets - Developer

Build the query 0.1.0 1.0.0 2.0.0 You can start building a query across all assets using the select() method on the assets member of any client. You can chain as many conditions as you want: where() is mandatory inclusion whereNot() is mandatory exclusion whereSome() for conditions where some of them must match You can start building a query across all assets using the select() method on the assets member of any client. You can chain as many conditions as you want: where() is mandatory inclusion whereNot() is mandatory exclusion whereSome() for conditions where some of them must match This helper provides a query that ensures results are active (not archived) assets. Equivalent Elastic query Query beActive = TermQuery . of ( m -> m . field ( "__state" ) . value ( AtlanStatus . ACTIVE . getValue ())) . _toQuery (); This helper provides a query that ensures results are active (not archived) assets. This helper provides a query that ensures results are active (not archived) assets. You can start building a query across all assets using the select() method on the assets member of any client. You can chain as many mandatory ( where() ) conditions, mandatory exclusion ( whereNot() ) conditions, and set of conditions some of which must match ( whereSome() ) as you want. This helper provides a query that ensures results are active (not archived) assets. Equivalent Elastic query val beActive = TermQuery . of ( m -> m . field ( "__state" ) . value ( AtlanStatus . ACTIVE . getValue ())) . _toQuery () This helper provides a query that ensures results are active (not archived) assets. This helper provides a query that ensures results are active (not archived) assets. A bool query combines together multiple conditions. A filter clause exactly matches all of the conditions, without scoring (so can be slightly faster than other scoring-based combination mechanisms). Term queries are generally used to exactly match values. The __state field will match the status of an asset in Atlan. So in this example you will only match assets that are currently ACTIVE (not archived or soft-deleted). You will also only match assets that are of a specific type, since __typeName.keyword will match the type of asset. Note these names do not exactly match attribute names Build the request 0.0.17 1.0.0 1.1.0 The number of results to include (per page). You can chain as many attributes to include on each related asset to each result. Since we are returning anchor relationships, this will ensure that the certificateStatus of those related glossaries is also included in each result. The number of results to include (per page). You can chain as many attributes to include on each related asset to each result. Since we are returning anchor relationships, this will ensure that the certificate_status of those related glossaries is also included in each result. The number of results to include (per page). You can chain as many attributes to include on each related asset to each result. Since we are returning anchor relationships, this will ensure that the certificateStatus of those related glossaries is also included in each result. The number of results to include (per page). You can chain as many attributes to include on each related asset to each result. Since we are returning anchor relationships, this will ensure that the certificateStatus of those related glossaries is also included in each result. A query should always be defined within the dsl portion of the request. In addition to the query, you can specify from and size parameters for pagination. The query itself should be provided within the query portion of the dsl . Here you would use the query body provided in the earlier step. You must set track_total_hits to true if you want an exact count of the number of results (in particular for pagination). The list of attributes to include on each relationship that is included in each result. Since we are returning anchor relationships, this will ensure that the certificateStatus of those related glossaries is also included in each result. (Optional) Build request directly from JSON A query should always be defined within the dsl portion of the request. In addition to the query, you can specify from and size parameters for pagination. The query itself should be provided within the query portion of the dsl . Here you would use the query body provided in the earlier step. You must set track_total_hits to true if you want an exact count of the number of results (in particular for pagination). The list of attributes to include on each relationship that is included in each result. Since we are returning anchor relationships, this will ensure that the certificateStatus of those related glossaries is also included in each result. 0.1.0 1.4.0 4.0.0 The getApproximateCount() method gives the total number of results overall (not restricted by page). The count property gives the total number of results overall (not restricted by page). The .approximateCount member gives the total number of results overall (not restricted by page). The ApproximateCount property gives the total number of results overall (not restricted by page). If an error occurs during iteration (e.g: a failed API request), it is sent to the errIter channel. The iteration stops, and you can handle the error accordingly. Implicit in the previous step Iterate through results One page of results 0.1.0 1.0.0 1.1.0 To iterate through one page of results, loop through the list of assets: The page of results itself can be accessed through the getAssets() method on the response. You can then iterate through these results from a single page. You can iterate through the results from a single page. The page of results itself can be accessed through the .assets member on the response. You can then iterate through these results from a single page. You can iterate through the results from a single page. You can filter the asset based on the typename and perform operations on the asset. Each object in entities is a matching asset Each item in the entities array of the response will give details about a matching asset. Multiple pages of results 0.0.17 1.0.0 1.1.0 To iterate through multiple pages of results: You can simply iterate over the reponse itself. This will lazily load and loop through each page of results until the loop finishes or you break out of it. (You could also use response.forEach() , which uses the same iteratable-based implementation behind-the-scenes.) Alternatively, you can also stream the results direct from the response. This will also lazily load and loop through each page of results. Can be chained without creating a request in-between You can actually chain the stream() method directly onto the end of your query and request construction, without creating a request or response object in-between. Alternatively, you can also stream the results direct from the response. This will also lazily load and loop through each page of results. Can be chained without creating a request in-between You can actually chain the stream() method directly onto the end of your query and request construction, without creating a request or response object in-between. With streaming, you can apply your own limits to the maximum number of results you want to process. Independent of page size Note that this is independent of page size. You could page through results 50 at a time, but only process a maximum of 100 total results this way. Since the results are lazily-loaded when streaming, only the first two pages of results would be retrieved in such a scenario. With streaming, you can apply your own limits to the maximum number of results you want to process. Independent of page size Note that this is independent of page size. You could page through results 50 at a time, but only process a maximum of 100 total results this way. Since the results are lazily-loaded when streaming, only the first two pages of results would be retrieved in such a scenario. You can also apply your own logical filters to the results. Push-down as much as you can to the query You should of course push-down as many of the filters as you can to the query itself, but if you have a particular complex check to apply that cannot be encoded in the query this can be a useful secondary filter over the results. You can also apply your own logical filters to the results. Push-down as much as you can to the query You should of course push-down as many of the filters as you can to the query itself, but if you have a particular complex check to apply that cannot be encoded in the query this can be a useful secondary filter over the results. The forEach() on the resulting stream will then apply whatever actions you want with the results that come through. The forEach() on the resulting stream will then apply whatever actions you want with the results that come through. The current_page() method returns a list of the assets for the current page. If there are none then an empty list will be returned. Iterate through the assets in the current page. The next_pages() method retrieves the next page of results and return True if more assets are available and False if they are not. Break out of the While loop if no more assets are available. This will iterate through all the results without the need to be concerned with pages. Iterating over results produces a Generator This means that results are retrieved from the backend a page at time. This also means that you can only iterate over the results once. This will iterate through all the results without the need to be concerned with pages. Iterating over results produces a Generator This means that results are retrieved from the backend a page at time. This also means that you can only iterate over the results once. You can simply iterate over the reponse itself. This will lazily load and loop through each page of results until the loop finishes or you break out of it. (You could also use response.forEach{ } , which uses the same iteratable-based implementation behind-the-scenes.) Alternatively, you can also stream the results direct from the response. This will also lazily load and loop through each page of results. Can be chained without creating a request in-between You can actually chain the stream() method directly onto the end of your query and request construction, without creating a request or response object in-between. Alternatively, you can also stream the results direct from the response. This will also lazily load and loop through each page of results. Can be chained without creating a request in-between You can actually chain the stream() method directly onto the end of your query and request construction, without creating a request or response object in-between. With streaming, you can apply your own limits to the maximum number of results you want to process. Independent of page size Note that this is independent of page size. You could page through results 50 at a time, but only process a maximum of 100 total results this way. Since the results are lazily-loaded when streaming, only the first two pages of results would be retrieved in such a scenario. With streaming, you can apply your own limits to the maximum number of results you want to process. Independent of page size Note that this is independent of page size. You could page through results 50 at a time, but only process a maximum of 100 total results this way. Since the results are lazily-loaded when streaming, only the first two pages of results would be retrieved in such a scenario. You can also apply your own logical filters to the results. Push-down as much as you can to the query You should of course push-down as many of the filters as you can to the query itself, but if you have a particular complex check to apply that cannot be encoded in the query this can be a useful secondary filter over the results. You can also apply your own logical filters to the results. Push-down as much as you can to the query You should of course push-down as many of the filters as you can to the query itself, but if you have a particular complex check to apply that cannot be encoded in the query this can be a useful secondary filter over the results. The forEach{ } on the resulting stream will then apply whatever actions you want with the results that come through. The forEach{ } on the resulting stream will then apply whatever actions you want with the results that come through. If an error occurs during iteration (e.g: a failed API request), it is sent to the errIter channel. The iteration stops, and you can handle the error accordingly. Use this query string from the response to start building a new query using the same logic. Add the page size to the from parameter embedded in that query string, to give the starting point for the next page of results. Re-include any attributes or relationAttributes from the query string into the new query. Send this new query to retrieve the next page of results.


Updating an asset - Developer

Updating an asset All objects in the SDK that you can update within Atlan implement the builder pattern. This allows you to progressively build-up the object you want to update. In addition, each object provides a method that takes the minimal set of required fields to update that asset , when it already exists in Atlan. Include only your intended changes, nothing more When enriching an asset in Atlan, you only need to specify the information you want to change. Any information you do not include in your update will be left untouched on the asset in Atlan. This way you do not need to: try to reproduce the complete asset in your request to do targeted updates to specific attributes worry about other changes that may be made to the asset in parallel to the changes you will be making to the asset Build minimal object needed For example, to update a glossary term we need to provide the qualifiedName and name of the term, and the GUID of the glossary in which it exists: The name of the existing term. This must match exactly (case-sensitive). The GUID of the glossary in which the term exists. The name of the existing term. This must match exactly (case-sensitive). The GUID of the glossary in which the term exists. The name of the existing term. This must match exactly (case-sensitive). The GUID of the glossary in which the term exists. Implicit in the API calls below There is nothing specific to do for this step when using the raw APIs — constructing the object is simply what you place in the payload of the API calls in the steps below. Since you should only include your intended changes, and nothing more, the SDKs provide a convenience method to reduce an asset down to its minimal properties. You should use this method to trim an object in your code down to a starting point for the changes you want to make to that asset: Assuming you have an existing asset in a variable called existing , you can call trimToRequired() to reduce it to a builder with the minimal properties needed to update that asset. Assuming you have an existing asset in a variable called existing , you can call trim_to_required() to reduce it to an object with the minimal properties needed to update that asset. Enrich before updating The term object now has the minimal required information for Atlan to update it. Without any additional enrichment, though, there isn't really anything to update. So first you should enrich the object: We'll create an object we can take actions on from this updater. In this example, we're adding a certificate to the object. Note that you can chain any number of enrichments together. Here we are also adding an announcement to the asset. To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) In this example, we're adding a certificate to the object. In this example, we're adding an announcement to the object. We'll create an object we can take actions on from this updater. In this example, we're adding a certificate to the object. Note that you can chain any number of enrichments together. Here we are also adding an announcement to the asset. To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) Implicit in the API calls below There is nothing specific to do for this step when using the raw APIs — constructing the object is simply what you place in the payload of the API calls in the steps below. Update the asset from the object You can then actually update the object in Atlan 1 : The save() method will either update an existing asset (if Atlan already has a term with the same name and qualifiedName in the same glossary) or create a new asset (if Atlan does not have a term with the same name in the same glossary). Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. You can distinguish what was created or updated: getCreatedAssets() lists assets that were created getUpdatedAssets() lists assets that were updated Note that the save() method always returns objects of type Asset , though. You can distinguish what was created or updated: getCreatedAssets() lists assets that were created getUpdatedAssets() lists assets that were updated Note that the save() method always returns objects of type Asset , though. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The updateMergingCM() method will only update an existing asset (if Atlan already has an asset of the same type with the same name qualifiedName ). Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. Depending on the update behavior you want, you could also use: updateMergingCM(false) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouched updateMergingCM(true) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing asset updateReplacingCM(false) to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouched updateReplacingCM(true) to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset The updateMergingCM() method will only update an existing asset (if Atlan already has an asset of the same type with the same name qualifiedName ). Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. Depending on the update behavior you want, you could also use: updateMergingCM(false) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouched updateMergingCM(true) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing asset updateReplacingCM(false) to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouched updateReplacingCM(true) to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset You can distinguish what was created or updated: getUpdatedAssets() lists assets that were updated Note that the update. () methods always returns objects of type Asset , though. You can distinguish what was created or updated: getUpdatedAssets() lists assets that were updated Note that the update. () methods always returns objects of type Asset , though. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. Since the update. () methods strictly update (and never create) an asset, if the asset you are trying to update does not exist the operation will throw a NotFoundException . Since the update. () methods strictly update (and never create) an asset, if the asset you are trying to update does not exist the operation will throw a NotFoundException . The save(term) method will either update an existing asset (if Atlan already has a term with the same name and qualifiedName in the same glossary) or (create a new asset, if Atlan does not have a term with the same name in the same glossary). You can distinguish what was created or updated: assets_created(asset_type = AtlasGlossaryType) returns a list assets of the specified type that were created. assets_updated(asset_type = AtlasGlossaryType) returns a list assets of the specified type that were updated. You can distinguish what was created or updated: assets_created(asset_type = AtlasGlossaryType) returns a list assets of the specified type that were created. assets_updated(asset_type = AtlasGlossaryType) returns a list assets of the specified type that were updated. If the returned list is not empty, get the term that was updated. If the returned list is not empty, get the term that was updated. The update_merging_cm() method will only update an existing asset (if Atlan already has an asset of the same type with the same name qualified_name ). Depending on the update behavior you want, you could also use: update_merging_cm(replace_atlan_tags=False) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouched update_merging_cm(replace_atlan_tags=True) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing asset update_replacing_cm(replace_atlan_tags=False) to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouched update_replacing_cm(replace_atlan_tags=True) to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset The update_merging_cm() method will only update an existing asset (if Atlan already has an asset of the same type with the same name qualified_name ). Depending on the update behavior you want, you could also use: update_merging_cm(replace_atlan_tags=False) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouched update_merging_cm(replace_atlan_tags=True) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing asset update_replacing_cm(replace_atlan_tags=False) to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouched update_replacing_cm(replace_atlan_tags=True) to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset You can distinguish what was created or updated: assets_updated(asset_type = AtlasGlossaryType) returns a list assets of the specified type that were updated. You can distinguish what was created or updated: assets_updated(asset_type = AtlasGlossaryType) returns a list assets of the specified type that were updated. Since the update. () methods strictly update (and never create) an asset, if the asset you are trying to update does not exist the operation will throw a NotFoundError . Since the update. () methods strictly update (and never create) an asset, if the asset you are trying to update does not exist the operation will throw a NotFoundError . The save() method will either update an existing asset (if Atlan already has a term with the same name and qualifiedName in the same glossary) or create a new asset (if Atlan does not have a term with the same name in the same glossary). Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. You can distinguish what was created or updated: createdAssets lists assets that were created updatedAssets lists assets that were updated Note that the save() method always returns objects of type Asset , though. You can distinguish what was created or updated: createdAssets lists assets that were created updatedAssets lists assets that were updated Note that the save() method always returns objects of type Asset , though. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The updateMergingCM() method will only update an existing asset (if Atlan already has an asset of the same type with the same name qualifiedName ). Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. Depending on the update behavior you want, you could also use: updateMergingCM(false) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouched updateMergingCM(true) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing asset updateReplacingCM(false) to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouched updateReplacingCM(true) to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset The updateMergingCM() method will only update an existing asset (if Atlan already has an asset of the same type with the same name qualifiedName ). Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. Depending on the update behavior you want, you could also use: updateMergingCM(false) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouched updateMergingCM(true) to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing asset updateReplacingCM(false) to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouched updateReplacingCM(true) to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset You can distinguish what was created or updated: getUpdatedAssets() lists assets that were updated Note that the update. () methods always returns objects of type Asset , though. You can distinguish what was created or updated: getUpdatedAssets() lists assets that were updated Note that the update. () methods always returns objects of type Asset , though. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. Since the update. () methods strictly update (and never create) an asset, if the asset you are trying to update does not exist the operation will throw a NotFoundException . Since the update. () methods strictly update (and never create) an asset, if the asset you are trying to update does not exist the operation will throw a NotFoundException . All assets must be wrapped in an entities array. You must provide the exact type name for the asset (case-sensitive). For a term, this is AtlasGlossaryTerm . You must provide the exact name of the existing asset (case-sensitive). (Unless you want to change its name, in which case you can provide the new name instead.) You must provide the exact qualifiedName of the existing asset (case-sensitive). Must exactly match the qualifiedName of an existing asset If this does not exactly match the qualifiedName of an existing asset, the API call will instead create a new asset rather than updating an existing one. You must provide the exact qualifiedName of the existing asset (case-sensitive). Must exactly match the qualifiedName of an existing asset If this does not exactly match the qualifiedName of an existing asset, the API call will instead create a new asset rather than updating an existing one. In this example, we're adding a certificate to the object. Note that you can include any number of enrichments together. Here we are also adding an announcement to the asset. Case-sensitive, exact match If you use a different capitalization or spelling for the qualifiedName , you may accidentally create a new asset rather than updating the existing one. 2 Remove information from an asset As mentioned in Enrich before updating section, only the information in your request will be updated on the object. But what if you want to remove some information that already exists on the asset in Atlan? We'll create an object we can take actions on from this updater. In this example, we'll remove any existing certificate from the object in Atlan. Note that you can chain any number of enrichments together. Here we are also removing any announcement from the asset. To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) The save() method will either: Update an existing asset, if Atlan already has a term with the same name and qualifiedName in the same glossary. Create a new asset, if Atlan does not have a term with the same name in the same glossary. Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. The save() method will either: Update an existing asset, if Atlan already has a term with the same name and qualifiedName in the same glossary. Create a new asset, if Atlan does not have a term with the same name in the same glossary. Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. You can distinguish what was created or updated: getCreatedAssets() lists assets that were created getUpdatedAssets() lists assets that were updated Note that the save() method always returns objects of type Asset , though. You can distinguish what was created or updated: getCreatedAssets() lists assets that were created getUpdatedAssets() lists assets that were updated Note that the save() method always returns objects of type Asset , though. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. In this example we will remove an existing certificate from any existing certificate from the object. In this example we will remove any existing announcement from the object. We'll create an object we can take actions on from this updater. In this example, we'll remove any existing certificate from the object in Atlan. Note that you can chain any number of enrichments together. Here we are also removing any announcement from the asset. To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) To persist the enrichment back to the object, we must build() the builder. Assign the result back Remember to assign the result of the build() operation back to your original object. Otherwise the result is not persisted back into any variable! (In this case we're assigning to the term variable back on line 5.) The save() method will either: Update an existing asset, if Atlan already has a term with the same name and qualifiedName in the same glossary. Create a new asset, if Atlan does not have a term with the same name in the same glossary. Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. The save() method will either: Update an existing asset, if Atlan already has a term with the same name and qualifiedName in the same glossary. Create a new asset, if Atlan does not have a term with the same name in the same glossary. Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant. You can distinguish what was created or updated: createdAssets lists assets that were created updatedAssets lists assets that were updated Note that the save() method always returns objects of type Asset , though. You can distinguish what was created or updated: createdAssets lists assets that were created updatedAssets lists assets that were updated Note that the save() method always returns objects of type Asset , though. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. The Asset class is a superclass of all assets. So we need to cast to more specific types (like GlossaryTerm ) after verifying the object that was actually returned. All assets must be wrapped in an entities array. You must provide the exact type name for the asset (case-sensitive). For a term, this is AtlasGlossaryTerm . You must provide the exact name of the existing asset (case-sensitive). (Unless you want to change its name, in which case you can provide the new name instead.) You must provide the exact qualifiedName of the existing asset (case-sensitive). Must exactly match the qualifiedName of an existing asset If this does not exactly match the qualifiedName of an existing asset, the API call will instead create a new asset rather than updating an existing one. You must provide the exact qualifiedName of the existing asset (case-sensitive). Must exactly match the qualifiedName of an existing asset If this does not exactly match the qualifiedName of an existing asset, the API call will instead create a new asset rather than updating an existing one. In this example, we're removing any existing certificate information from the object in Atlan (by sending null ). Note that you can include any number of enrichments together. Here we are also removing any announcement from the asset. Atlan automatically detects changes to determine whether to create or update an asset — see the Importance of identifiers for a more detailed explanation. To strictly update (and avoid creating) an asset, you must first look for the existing asset and only if found proceed with your update. When the SDKs provide such strict update functionality, this is what they are doing behind-the-scenes. Be aware that this will impact performance, so you should only do this where strictly necessary for your logic. ↩ Atlan automatically detects changes to determine whether to create or update an asset — see the Importance of identifiers for a more detailed explanation. To strictly update (and avoid creating) an asset, you must first look for the existing asset and only if found proceed with your update. When the SDKs provide such strict update functionality, this is what they are doing behind-the-scenes. Be aware that this will impact performance, so you should only do this where strictly necessary for your logic. ↩ This is because Atlan uses the exact qualifiedName to determine whether it should do an update. For a more detailed explanation, see the Importance of identifiers . ↩ This is because Atlan uses the exact qualifiedName to determine whether it should do an update. For a more detailed explanation, see the Importance of identifiers . ↩