Integrating Salesforce with Hashnode: A Step-by-Step Guide to Creating and Managing Blog Posts

Salesforce is a powerful platform that allows you to integrate with a wide range of external services. In this guide, I’ll walk you through how to integrate Salesforce with Hashnode, a popular blogging platform for developers, to create, manage, and track your blog posts—all from within Salesforce.

In this integration, I have built three key features

  1. Fetching all published blog posts from.

  2. Fetching a single blog post by its ID from hashnode.

  3. Publishing a new blog post on Hashnode from Salesforce.

Let’s explore how to set up this integration step by step.

Step 1: Storing API Credentials with Custom Settings

To ensure our integration is secure, we’ll store the Hashnode API credentials, such as the API Key, Endpoint, Host, and Publication ID, in Custom Settings within Salesforce. This method allows us to manage sensitive data without hardcoding it into our Apex classes, promoting better security and flexibility.

Begin by navigating to the Setup menu and selecting Custom Settings. Here, create a new custom setting, within this setting add the following fields:

  • APIKey for storing the Hashnode API Key.

  • Endpoint for the Hashnode GraphQL Endpoint.

  • Host: for storing the Host URL.

  • Publication: for your specific publication’s ID on Hashnode.

With these settings in place, we can easily retrieve the credentials dynamically in our Apex code.

Step 2: Creating the Blog Post Custom Object

Next, we need a way to store the blog post details in Salesforce. For this purpose, we will create a custom object called Blog. This object will hold crucial information such as the unique post ID, the title of the blog, and the URL of the published post.

The Blog object will include the following fields:

  • Id: A text field to store the unique ID of the blog post as returned by Hashnode.

  • Name: The standard field to capture the blog post's title.

  • URL: A URL field to store the link to the published blog post.

  • Brief: A text area field to capture a brief description of the blog.

  • View Count: A number field to store the number of views for the blog post.

  • Date Posted: A date field to store the date the blog post was published.

This structure will facilitate effective tracking and management of blog posts directly within Salesforce.

Fetching All Blog Posts

To fetch all your blog posts from Hashnode, we will create an Apex class that makes an API call to the Hashnode GraphQL endpoint. This class retrieves all publications associated with your account and stores them in the Blog object.

global class HashnodeFetchAllAPI {
// Define the GraphQL query for fecthing all post
// It accepts an input variable of type String and returns the post's ID, URL, title and other details
    private static final String QUERY = 
        'query Publication($host: String) {' +
                              '  publication(host: $host) {' +
                              '    posts(first: 100) {' +
                              '      edges {' +
                              '        node {' +
                              '          title' +
                              '          views' +
                              '          url' +
                              '          id' +
                              '          publishedAt' +
                                '        }' +
                              '      }' +
                              '      totalDocuments' +
                              '    }' +
                              '  }' +
                              '}';

    // Method to fetch all post on hashnode using the graphql query
        public static void  fetchPublication() {

        // Fetch the API, endpoint and host from custom settings
        String ENDPOINT = Hashnode_API_Setting__c.getInstance('Hashnode Endpoint').Value__c;
        String HOST = Hashnode_API_Setting__c.getInstance('Hashnode Host').Value__c;

        // Prepare the request body
        String requestBody = '{"query": "' + QUERY + '", "variables": {"host": "' + HOST + '"}}';

        // Create the HTTP request
        HttpRequest req = new HttpRequest();
        req.setEndpoint(ENDPOINT);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(requestBody);

        // Send the request
        Http http = new Http();
        HttpResponse res = http.send(req);

        // Handle the response
        if (res.getStatusCode() == 200) {
                // Deserialize the response into the PublicationResponse class
                PublicationResponse responseMap = (PublicationResponse) JSON.deserialize(res.getBody(),PublicationResponse.class);


               // Create a new List of Blogs to insert record in org                 
                List<Blog__c> lstBlog = new list<Blog__c>();
                  for (PublicationResponse.cls_edges edge : responseMap.data.publication.posts.edges) {
                PublicationResponse.cls_node node = edge.node;
                // Create a new Blog object to store the post ID, title, URL and other fields               

                Blog__c newBlog = new Blog__c(
                    Id__c=node.id,
                    Title__c=node.title,
                    URL__c=node.url,
                    View_Count__c=node.views,
                    Date_Posted__c=node.publishedAt
                );
                 lstBlog.add(newBlog);    
            }
            System.debug(responseMap);

            //Upsert the record based on post Id
            upsert lstBlog Id__c;
        } else {
            System.debug('Error: ' + res.getStatus());
            System.debug('Response Body: ' + res.getBody());
        }
    }

}

Fetching a Single Blog Post by ID

In addition to fetching all blog posts, you can also retrieve a single blog post using its ID. This can be useful when you want to view or update specific blog details.

global class HashnodeSingleFetch {

// Define the GraphQL mutation for fetching a post
// It accepts an input variable of type Id and returns the post's ID, URL, title and other details
    private static final String QUERY = 
    'query Post($id: ID!) { ' +
    '  post(id: $id) { ' +
    '    id ' +
    '    slug ' +
    '    publishedAt ' +
    '    url ' +
    '    title ' +
    '    views ' +
    '    brief ' +
    '  } ' +
    '}';

    // Method to fetch a post on hashnode using the graphql query based on Id
    public static void fetchPublication(String Ids){

                // Prepare the request body
                String requestBody = '{"query": "' + QUERY + '", "variables": {"id": "' + Ids + '"}}';

                // Fetch the endpoint from custom settings
                String ENDPOINT = Hashnode_API_Setting__c.getInstance('Hashnode Endpoint').Value__c;

                // Create the HTTP request
                HttpRequest req = new HttpRequest();
                req.setEndpoint(ENDPOINT);
                req.setMethod('POST');
                req.setHeader('Content-Type', 'application/json');
                req.setBody(requestBody);

                // Send the request
                Http http = new Http();
                HttpResponse res = http.send(req);


                if (res.getStatusCode() == 200) {
                // Deserialize the response into the SingleFetchResponse class
                SingleFetchResponse responseMap = (SingleFetchResponse) JSON.deserialize(res.getBody(),SingleFetchResponse.class);
                // Create a new Blog object  to store the post ID, title, and URL  and other fields              
                Blog__c fetchedDetail = new Blog__c(
                    Id__c=responseMap.data.post.id,
                    URL__c=responseMap.data.post.url,
                    Title__c=responseMap.data.post.title,
                    View_Count__c=responseMap.data.post.views,
                    Brief__c=responseMap.data.post.brief,
                    Date_Posted__c=responseMap.data.post.publishedAt
                );
                //Upsert the record based on post Id
                upsert  fetchedDetail Id__c;
        } else { 
            System.debug('Error: ' + res.getStatus());
            System.debug('Response Body: ' + res.getBody());
        }
    }
}

Publishing a New Blog Post

The highlight of this integration is the ability to publish a new blog post directly from Salesforce. You can use LWC to create a simple form with fields for the post title and content. On form submission, an Apex class will be invoked to publish the post on Hashnode via its API. After successfully publishing the post, the post ID and URL will be saved in the Blog object for future reference and management.

global class HashnodeMutationAPI {
    // Define the GraphQL mutation for creating a post
    // It accepts an input variable of type PublishPostInput and returns the post's ID, URL, and title 
        private static final String MUTATION = 
        'mutation PublishPost($input: PublishPostInput!) {' +
        '  publishPost(input: $input) {' +
        '    post {' +
        '      id' +
        '       url'+
        '      title' +
        '    }' +
        '  }' +
        '}';

    // Inner class to hold the input structure for creating a post (title and content)
    public class CreatePostInput {
        public String title;                // Title of the blog post
        public String contentMarkdown;        // Content of the blog post

        // Constructor to initialize the post title and content
        public CreatePostInput(String title, String contentMarkdown) {
            this.title = title;
            this.contentMarkdown = contentMarkdown;         
        }
    }

    // Method to create a post on Hashnode using the provided CreatePostInput
    public static String createPost(CreatePostInput input) {
        // Fetch the API endpoint, publicationId, and API key from custom settings
        String ENDPOINT = Hashnode_API_Setting__c.getInstance('Hashnode Endpoint').Value__c;
        String publicationId = Hashnode_API_Setting__c.getInstance('Hashnode PublicationId').Value__c;
        String APIKey = Hashnode_API_Setting__c.getInstance('Hashnode API Key').Value__c;

        // Prepare the request body by serializing the mutation and variables into a JSON object
        String requestBody = JSON.serialize(new Map<String, Object>{
            'query' => MUTATION,                                  // The GraphQL mutation to be executed
                'variables' => new Map<String, Object>{
                    'input' => new Map<String, Object>{
                        'publicationId' => publicationId,        // The publication ID where the post will be published
                            'title' => input.title,
                            'contentMarkdown' => input.contentMarkdown
                            }
                }
        });

        // Create the HTTP request
        HttpRequest req = new HttpRequest();
        req.setEndpoint(ENDPOINT);                            // The API endpoint fetched from the custom setting
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');    
        req.setHeader('Authorization', 'Bearer ' + APIKey); // Set the Authorization header with the Bearer token (API key)
        req.setBody(requestBody);                            // Set the serialized request body (GraphQL query and variables)

        try {
            // Send the HTTP request and receive the response
            Http http = new Http();
            HttpResponse res = http.send(req);

            // Handle the response
            if (res.getStatusCode() == 200) {
                // Deserialize the response into the MutationResponse class
                MutationResponse response = (MutationResponse) JSON.deserialize(res.getBody(),MutationResponse.class);
                // Create a new Blog record in Salesforce to store the post ID, title, and URL                
                Blog__c newBlog = new Blog__c(
                    Id__c=response.data.publishPost.post.id,
                    Title__c=response.data.publishPost.post.title,
                    URL__c=response.data.publishPost.post.url
                );

                insert newBlog;


                System.debug('Post created: ' + response);
                        return response.data.publishPost.post.url; 

            } else {
                System.debug('Error: ' + res.getStatus());
                System.debug('Response Body: ' + res.getBody());
            }
        } catch (Exception e) {
            System.debug('Exception occurred: ' + e.getMessage());
        }
        return null;

    }
}

Conclusion

By following these steps, you can integrate Salesforce with Hashnode, giving you the ability to manage your blog posts directly from within Salesforce. Whether it’s creating new posts, retrieving published posts, or keeping your records updated, this integration simplifies the process while providing a powerful way to track and manage your content.

Feel free to customize this integration further based on your specific needs. You can add more functionality, such as scheduling posts, fetching additional metadata, or automating tasks related to your blog content. For reference, you can visit the Hashnode API documentation to explore more features and capabilities.