Skip to content

Ashwani Soni | Certified | Salesforce | Partner | Senior Team Lead | Consultant | Developer | Mobile | Integration | Contributor | SFSE

Metadata

Create or Update Custom Metadata Type via Apex code – Salesforce Summer 17

Posted on May 2, 2017May 2, 2017 by Ashwani

Salesforce Blog Template.png

Salesforce Summer 17 came with a most wanted feature for Custom Metadata Types which is managing it via Apex code. Now custom metadata records can be create and updated via Apex code which means no changes set or force.com migration tool is required from Summer 17.

There is a Namespace called Metadata introduced in Summer ’17 release to manage Custom Metadata.

Below is the sample code to create a Custom metadata type:-

First define a Metadata in org the same as previous releases. Here Response_Type__mdt is created.

Add new field Status_Code__c.

Here our purpose is to configure status codes by Custom Metadata proper message can be displayed.

New Metadata would look like as below:-

Screenshot 2017-04-28 23.00.03
Custom Metadata

Few things to consider:-

  • Custom Metadata create/update is asynchronous
  • It actually does a deployment in backend instead of DML
  • Doesn’t count against governor limit

Because the Custom Metadata update happens asynchronous it requires a way to get the status of deployment. So, it requires callback class. Lets define a callback class as:-

public class CustomMetadataCallback implements Metadata.DeployCallback {
    public void handleResult(Metadata.DeployResult result,
                             Metadata.DeployCallbackContext context) {
        if (result.status == Metadata.DeployStatus.Succeeded) {
            System.debug('success: '+ result);
        } else {
            // Deployment was not successful
            System.debug('fail: '+ result);
        }
    }
}

A callback class implement Metadata.DeployCallback interface.

Below is the way to create a custom Metadata:-

    // Set up custom metadata to be created in the subscriber org.
    Metadata.CustomMetadata customMetadata =  new Metadata.CustomMetadata();
    customMetadata.fullName = 'Response_Type.Not_Found_Code';
    customMetadata.label = 'Not_Found_Code';

    Metadata.CustomMetadataValue customField = new Metadata.CustomMetadataValue();
    customField.field = 'Status_Code__c';
    customField.value = '404';

    customMetadata.values.add(customField);

    Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
    mdContainer.addMetadata(customMetadata);

    // Setup deploy callback, MyDeployCallback implements
    // the Metadata.DeployCallback interface (code for
    // this class not shown in this example)
    CustomMetadataCallback callback = new CustomMetadataCallback();

    // Enqueue custom metadata deployment
    // jobId is the deployment ID
    Id jobId = Metadata.Operations.enqueueDeployment(mdContainer, callback);

By executing the above code we can create a Custom Metadata record in Response_Type__mdt custom Metadata.

All failures and success can be traced in callback class CustomMetadataCallback‘s method handleResult.

In addition deployment result can be checked in Setup -> Deploy | Deployment Status as shown below:

Screenshot 2017-04-29 13.26.09.png

This is how we an create Custom Metadata record. It has been the most demanded feature since Custom Metadata introduced. Hope that will help a lot in Custom Metadata based implementations.

Useful links:-

Salesforce Summer ’17 release notes

Metadata Namespace reference

Stackexchange question on Custom metadata creation

Advertisement
Posted in ApexTagged Custom Metadata, Deployment, Metadata, Salesforce, VisualforceLeave a comment

Force.com Tooling API : Create Apex class, Apex Trigger dynamically and update/delete Apex Trigger, Apex class using Tooling API with REST API

Posted on January 18, 2017April 6, 2017 by Ashwani
Salesforce Tooling API - Ashwani Soni

In summer ’13 salesforce introduced a new set of API to control organization object like Apex class, Apex Trigger, TraceFlag, Visualforce Pages and other components from outside the organization. Tooling API allows to access coverage for Apex class and Apex trigger. Managing custom objects and anonymous execution of code and access debug logs from organization. Tooling API provides bothREST and SOAP API interface to access its features. Tooling API provides set of objects accessible from RESP API and SOAP API. It is just like SOAP API and REST API with a difference of endpoint only and selected set of objects available through it.Below is given Apex code example to create, update and delete operation on apex class. Which will answer, How to use  Tooling API? How to create Apex Trigger/Apex Class using Tooling API and How to update these? and various other useful features.

Before working with Tooling API object first create some generic methods which will used throughout the class e.g creating a http request.

public with sharing class SalesforceTool
{
    final String endpoint = 'https://na1.salesforce.com/services/data/v28.0/tooling/sobjects';

    // SomeValues to be store
    public String oid ;
    public String cid ;
    public String apmid ;
    public String carid ;

    public SalesforceTool()
    {
    }

    // used receive response by sending a http request
    private String getResponse(HttpRequest req)
    {
        try
        {
            Http httpreq = new Http();
            HttpResponse res = httpreq.send(req);
            String reqresponse = res.getBody();
            return reqresponse;
        }
        catch (Exception e)
        {
          return 'Error:' +e.getMessage();
        }
    }

    // create a http request with required endpoint and request method
    private HttpRequest createHttpRequest(String endpoint, String method)
    {
        HttpRequest req = new
        HttpRequest();
        endpoint += '';
        req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
        req.setHeader('Content-Type', 'application/json');
        req.setEndpoint(endpoint);
        req.setMethod(method);
        return req;
    }
}
Here we created to methods to send request and receive response from Tooling API.
Endpoint url configuration of Tooling API is “http://domain/services/data/vXX.X/tooling/ where domain is a Salesforce instance or a custom domain and vXX.X is the API version number. For  example: http://na1.salesforce.com/services/data/v28.0/tooling/” as written in Salesforce Tooling API guide. In  endpoint “na1” is instance of salesforce which is dynamic so it should be take care that instance should match with organization instance. Organization instance can be get when authorization process is done, in which “session id”/”access token” received with Salesforce instance and time period.
In below example “UserInfo.getSessionId()” will be used to remove confusion and maintain code simplicity.

Create a new Apex Class:

public void createApexClass()
{
    // create a Http request with post method
    HttpRequest req = createHttpRequest(endpoint+'/ApexClass','POST');
    req.setBody( '{"Name":"NewApexClass1","Body":"public class NewApexClass1 {}"}');
    // send request and receive response
    String response = getResponse(req);
    // These two lines have no role in creating apex class. So they can be ignored for now.
    Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
    oid = (String)rmp.get('id');
}
New Class
Created Using Tooling API
In endpoint url “ApexClass” is added because we are working on ApexClass object to create a new class. By executing method a new Apex class named “NewApexClass1” will be created in organization and response will be like  {“id”:”01p900000039N0vAAE”,”success”:true,”errors”:[]} where in json id is “NewApexClass1” id so that we can perform other operation targeting this id.

Deleting an Apex Class:

// [Status=No Content, StatusCode=204]
public void deleteApexClass()
{
    HttpRequest req = createHttpRequest(endpoint+'/ApexClass/'+oid,'DELETE');
    String responseJson = getResponse(req); // Store the result to do something
}

To delete a apex class or some other component only DELETE request is need to do by passing component object’s id. If request is successful then Status code 204 will be received and Apex class will be deleted from organization.

Query Tooling Objects:

This will result a JSON of Apex class named “NewApexClass1” with id and name and some other details. There are two fields in JSON because query was about two fields only.

Response will be like:

{
    "size":1,"totalSize":1,"done":true,"records":[{
        "attributes":{
            "type":"ApexClass","url":"/services/data/v28.0/tooling/sobjects/ApexClass/01p900000039N0vAAE"
        }
        ,"Id":"01p900000039N0vAAE","Name":"NewApexClass1"
    }
    ],"queryLocator":null,"entityTypeName":"ApexClass"
}

Describing an individual Tooling object record:

public void accessApexClass()
{
    HttpRequest req = createHttpRequest(endpoint+'/sobjects/ApexClass/'+oid,'GET');
    getResponse(req));
}
This will result full metadata of Apex class in json format which id (oid) is passed with endpoint url.

Update a Apex class:

To update a apex class involves some more steps then steps we required above. Apex class can be update by  ApexClassMember Object and by same way ApexTrigger are updated by ApexTriggerMember and so on.

Steps to update are:

– First we need to create MetadataContainer object ex:

public void createMetadataContainer()
{
    HttpRequest req = createHttpRequest(endpoint+'/sobjects/MetadataContainer','POST');
    req.setBody('{"Name":"ApexContainer"}');
    String response = getResponse(req);
    Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
    String cid = (String)rmp.get('id'); // used to save containerId
}

Store the MetadaContainer id because it will be required in ApexClassMember which is used to hold ApexClassMember, ApexTriggerMember etc.

– After this we need to create ApexClassMember object if we want to update ApexClass. If we want to update Apex Trigger then we need to create ApexTriggerMember. Here is example to create Apex Class so ApexClassMember will be created by:

// mid: MetadaContainserId
// axid: apexclass Id
// classBody: Apex class body (updated)
public void createApexClassMember(String mid, String axid, String classBody)
{
    HttpRequest req = createHttpRequest(endpoint+'/sobjects/ApexClassMember','POST');
    req.setBody('{"MetadataContainerId" : "'+mid+'", "ContentEntityId" : "'+axid+'", "Body": "'+classbody+'"}');
    String response = getResponse(req);
    Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
    String apmid = (String)rmp.get('id'); // Store ApexClassMember Id
}

ApexClassMember require 3 parameters, MetadatacontainerId, ApexClass id (which is created previously) as ContentEntityId and full body of class as string which is updated. Sending request by above code will provide newly created ApexClassMember Id. This should be store in some variable as it will require in next step. Till now this class is not updated.

To update a class ContainerAsyncRequest object is used. It compile and deploy the code and provide status of code. Is code deployed or has some problem and what is the problem. ContainerAsyncRequest object can be created by:

public void createContainerAsyncRequest(String mid)
{
    HttpRequest req = createHttpRequest(endpoint+'/sobjects/containerAsyncRequest','POST');
    req.setBody('{"MetadataContainerId" : "'+mid+'", "isCheckOnly": "false"}');
    String response = getResponse(req);
    Map<String,Object> rmp = (Map<String,Object>)JSON.deserializeuntyped(response);
    carid = (String)rmp.get('id');
}

It return the id by this status of deployed code can be checked as:

public void getContainerAsyncRequestStatus()
{
    HttpRequest req = createHttpRequest(endpoint+'/sobjects/containerAsyncRequest/'+carid,'GET');
    String responseJson = getResponse(req));
}

In response to this it provide updated class detail including error. If class deployed successfully error message is null.

{
    "attributes":{
        "type":"ContainerAsyncRequest",
        "url":"/services/data/v28.0/tooling/sobjects/ContainerAsyncRequest/1dr90000000EKSBAA4"
    }
    ,"Id":"1dr90000000EKSBAA4","IsDeleted":false,
"CreatedDate":"2013-09-08T14:32:30.000+0000","CreatedById":"00590000001CfQjAAK",
"LastModifiedDate":"2013-09-08T14:32:30.000+0000","LastModifiedById":"00590000001CfQjAAK",
"SystemModstamp":"2013-09-08T14:32:30.000+0000","MetadataContainerId":"1dc9000000009tXAAQ",
"MetadataContainerMemberId":null,"ErrorMsg":null,
"CompilerErrors":null,"IsRunTests":false,
"State":"Queued","IsCheckOnly":false
}

Same way ApexTrigger can be created using ApexTriggerMember.

Execute Anonymous:

Executing the Apex code
anonymously will available from API version 29.0 or later in Tooling
API sp calling it will result a error “requested resource doesn’t
exist”.

These are the some basic implementation of
Tooling API. Which may help in how Tooling api is used to create
objects.

There are still many things to explore about
tooling api so this post is not completed. In next few days there will
be sure new updates about tooling api.

Posted in Integration, Tooling API, UncategorizedTagged Apex, Dynamic Apex, Force.com, Integration, Metadata, Rest API, Tooling API, TriggerLeave a comment

Social

  • View ashwaniarea’s profile on Facebook
  • View ashwanisoni_’s profile on Twitter
  • View ashwaniarea’s profile on Instagram
  • View ashwaniarea’s profile on LinkedIn
  • View codemafiaa’s profile on GitHub
  • View ashwanisoniatgoogle’s profile on Google+

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 129 other subscribers

Recent Posts:

Salesforce Community and Site.com URL redirect management: An Easy Way

Salesforce1 Lightning Components: Getting started with Salesforce1 lightning components

Salesforce1 : Share/Upload photo directly to Chatter from mobile camera using Salesforce1 App

Show Custom Visualforce page in Salesforce1. Setup publisher action to allow user to check-in using Salesforce1 app

Salesforce1 look and feel. Customise Visualforce Pages for Salesforce1

Flickr Photos

Winterfall is hereMy #mac Simply.. It looks #beautiful, #powerful. The best machine for a #Salesforce #Dev #MacBook #apple #linuxfan #hackerstayawayThe back stage silence! #Salesforce #meetup 2 minutes before #rock as #rockstar #lightning #naptime #fancrowd #goingtorockthis #staytunedformore #calmbeforethestormThe #macroworld #macro flower photography #beautiful #flower20150314_204739
More Photos

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 129 other subscribers
  • View ashwaniarea’s profile on Facebook
  • View ashwanisoni_’s profile on Twitter
  • View ashwaniarea’s profile on Instagram
  • View ashwaniarea’s profile on LinkedIn
Follow Ashwani Soni | Certified | Salesforce | Partner | Senior Team Lead | Consultant | Developer | Mobile | Integration | Contributor | SFSE on WordPress.com
Create a free website or blog at WordPress.com.
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy
  • Follow Following
    • Ashwani Soni | Certified | Salesforce | Partner | Senior Team Lead | Consultant | Developer | Mobile | Integration | Contributor | SFSE
    • Already have a WordPress.com account? Log in now.
    • Ashwani Soni | Certified | Salesforce | Partner | Senior Team Lead | Consultant | Developer | Mobile | Integration | Contributor | SFSE
    • Customize
    • Follow Following
    • Sign up
    • Log in
    • Report this content
    • View site in Reader
    • Manage subscriptions
    • Collapse this bar
 

Loading Comments...