Skip to main content

Adding Likes to Your Social Graph

Likes are a fundamental engagement mechanism in social applications. The Tapestry Likes API allows users to express appreciation for content and interact with posts. You can use either the socialfi package (recommended for simpler integration) or call the API directly.

We recommend using the socialfi package as it provides a cleaner, more maintainable approach:

npm install socialfi
import { SocialFi } from 'socialfi';

const API_URL = 'https://api.usetapestry.dev/v1/'; // tapestry prod URL
// const API_URL = 'https://api.dev.usetapestry.dev/v1/'; // tapestry dev URL

const API_KEY = process.env.TAPESTRY_API_KEY; // Get your API key from https://app.usetapestry.dev/

const client = new SocialFi({
baseURL: API_URL,
apiKey: API_KEY,
});

Creating a Like

To allow users to like a post or content, use the like creation endpoint:

Using the Socialfi Package

try {
const newLike = await client.likes.createLike(
{
apiKey: API_KEY,
},
{
profileId: 'user123', // The ID of the profile creating the like
contentId: 'post456', // The ID of the content being liked
blockchain: 'SOLANA',
execution: 'FAST_UNCONFIRMED'
}
);
console.log('Like created:', newLike);
} catch (error) {
console.error('Error creating like:', error);
}

Using the API Directly

try {
const response = await fetch('https://api.usetapestry.dev/v1/likes?apiKey=YOUR_API_KEY', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
profileId: 'user123',
contentId: 'post456',
blockchain: 'SOLANA',
execution: 'FAST_UNCONFIRMED'
}),
});

const newLike = await response.json();
console.log('Like created:', newLike);
} catch (error) {
console.error('Error creating like:', error);
}

Request Parameters

FieldTypeDescription
profileIdstringThe ID of the profile creating the like.
contentIdstringThe ID of the content being liked.
blockchainstringThe blockchain to use (default: SOLANA)
executionstringExecution method (default: FAST_UNCONFIRMED)

Response Example

{
"like": {
"id": "like-1234567890",
"profileId": "user123",
"contentId": "post456",
"blockchain": "SOLANA",
"createdAt": "2024-01-15T10:30:00Z"
},
"user": {
"id": "user123",
"username": "johndoe",
"profileImage": "https://example.com/avatar.jpg"
}
}

Removing a Like (Unlike)

To allow users to unlike content they previously liked:

Using the Socialfi Package

try {
const result = await client.likes.deleteLike(
{
apiKey: API_KEY,
},
{
profileId: 'user123',
contentId: 'post456',
blockchain: 'SOLANA',
execution: 'FAST_UNCONFIRMED'
}
);
console.log('Like removed:', result);
} catch (error) {
console.error('Error removing like:', error);
}

Using the API Directly

try {
const response = await fetch('https://api.usetapestry.dev/v1/likes?apiKey=YOUR_API_KEY', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
profileId: 'user123',
contentId: 'post456',
blockchain: 'SOLANA',
execution: 'FAST_UNCONFIRMED'
}),
});

const result = await response.json();
console.log('Like removed:', result);
} catch (error) {
console.error('Error removing like:', error);
}

Response Example

{
"success": true,
"message": "Like removed successfully"
}

Getting Likes for Content

To retrieve all likes for a specific piece of content:

Using the Socialfi Package

try {
const likes = await client.likes.getLikesByContent(
{
apiKey: API_KEY,
contentId: 'post456',
limit: 20,
offset: 0
}
);
console.log('Likes for content:', likes);
} catch (error) {
console.error('Error fetching likes:', error);
}

Using the API Directly

try {
const response = await fetch(
'https://api.usetapestry.dev/v1/likes/content/post456?apiKey=YOUR_API_KEY&limit=20&offset=0'
);
const likes = await response.json();
console.log('Likes for content:', likes);
} catch (error) {
console.error('Error fetching likes:', error);
}

Query Parameters

ParameterTypeDescription
contentIdstringThe ID of the content to get likes for.
limitnumberMaximum number of likes to return.
offsetnumberNumber of likes to skip.

Response Example

{
"likes": [
{
"like": {
"id": "like-1234567890",
"createdAt": "2024-01-15T10:30:00Z"
},
"user": {
"id": "user123",
"username": "johndoe",
"profileImage": "https://example.com/avatar1.jpg"
}
},
{
"like": {
"id": "like-0987654321",
"createdAt": "2024-01-15T11:00:00Z"
},
"user": {
"id": "user789",
"username": "janedoe",
"profileImage": "https://example.com/avatar2.jpg"
}
}
],
"pagination": {
"total": 45,
"limit": 20,
"offset": 0,
"hasMore": true
},
"likeCount": 45
}

Getting Likes by User

To retrieve all content that a specific user has liked:

Using the Socialfi Package

try {
const userLikes = await client.likes.getLikesByProfile(
{
apiKey: API_KEY,
profileId: 'user123',
limit: 10,
offset: 0
}
);
console.log('Content liked by user:', userLikes);
} catch (error) {
console.error('Error fetching user likes:', error);
}

Using the API Directly

try {
const response = await fetch(
'https://api.usetapestry.dev/v1/likes/profile/user123?apiKey=YOUR_API_KEY&limit=10&offset=0'
);
const userLikes = await response.json();
console.log('Content liked by user:', userLikes);
} catch (error) {
console.error('Error fetching user likes:', error);
}

Response Example

{
"likes": [
{
"like": {
"id": "like-1234567890",
"createdAt": "2024-01-15T10:30:00Z"
},
"content": {
"id": "post456",
"content": "Amazing post about blockchain technology!",
"author": {
"id": "user789",
"username": "contentcreator"
}
}
}
],
"pagination": {
"total": 25,
"limit": 10,
"offset": 0,
"hasMore": true
}
}

Checking if User Liked Content

To check if a specific user has liked a specific piece of content:

Using the Socialfi Package

try {
const hasLiked = await client.likes.checkUserLikedContent(
{
apiKey: API_KEY,
profileId: 'user123',
contentId: 'post456'
}
);
console.log('User has liked this content:', hasLiked.hasLiked);
} catch (error) {
console.error('Error checking like status:', error);
}

Using the API Directly

try {
const response = await fetch(
'https://api.usetapestry.dev/v1/likes/check?apiKey=YOUR_API_KEY&profileId=user123&contentId=post456'
);
const hasLiked = await response.json();
console.log('User has liked this content:', hasLiked.hasLiked);
} catch (error) {
console.error('Error checking like status:', error);
}

Response Example

{
"hasLiked": true,
"likeId": "like-1234567890",
"likedAt": "2024-01-15T10:30:00Z"
}

Like Counts

To get just the like count for content without fetching all individual likes:

Using the Socialfi Package

try {
const likeCount = await client.likes.getLikeCount(
{
apiKey: API_KEY,
contentId: 'post456'
}
);
console.log('Like count:', likeCount.count);
} catch (error) {
console.error('Error fetching like count:', error);
}

Using the API Directly

try {
const response = await fetch(
'https://api.usetapestry.dev/v1/likes/count/post456?apiKey=YOUR_API_KEY'
);
const likeCount = await response.json();
console.log('Like count:', likeCount.count);
} catch (error) {
console.error('Error fetching like count:', error);
}

Response Example

{
"contentId": "post456",
"count": 45,
"lastUpdated": "2024-01-15T11:30:00Z"
}

Building Like Functionality

Here's a complete example of how to implement like/unlike functionality in your app using the socialfi package:

interface LikeButtonProps {
contentId: string;
currentUserId: string;
}

class LikeButton {
private contentId: string;
private currentUserId: string;
private isLiked: boolean = false;
private likeCount: number = 0;

constructor(props: LikeButtonProps) {
this.contentId = props.contentId;
this.currentUserId = props.currentUserId;
this.initializeLikeStatus();
}

async initializeLikeStatus() {
try {
// Check if user has liked this content
const likeStatus = await client.likes.checkUserLikedContent({
apiKey: API_KEY,
profileId: this.currentUserId,
contentId: this.contentId
});

// Get current like count
const likeCountData = await client.likes.getLikeCount({
apiKey: API_KEY,
contentId: this.contentId
});

this.isLiked = likeStatus.hasLiked;
this.likeCount = likeCountData.count;

this.updateUI();
} catch (error) {
console.error('Error initializing like status:', error);
}
}

async toggleLike() {
try {
if (this.isLiked) {
// Unlike the content
await client.likes.deleteLike(
{
apiKey: API_KEY,
},
{
profileId: this.currentUserId,
contentId: this.contentId,
blockchain: 'SOLANA'
}
);
this.isLiked = false;
this.likeCount--;
} else {
// Like the content
await client.likes.createLike(
{
apiKey: API_KEY,
},
{
profileId: this.currentUserId,
contentId: this.contentId,
blockchain: 'SOLANA'
}
);
this.isLiked = true;
this.likeCount++;
}

this.updateUI();
} catch (error) {
console.error('Error toggling like:', error);
// Revert optimistic update on error
this.initializeLikeStatus();
}
}

private updateUI() {
// Update your UI elements here
console.log(`Like button - Liked: ${this.isLiked}, Count: ${this.likeCount}`);
}
}

Real-time Like Updates

For real-time like updates, you can implement polling or use WebSocket connections:

// Polling example
async function pollLikeUpdates(contentId: string, intervalMs: number = 5000) {
setInterval(async () => {
try {
const likeCount = await client.likes.getLikeCount({
apiKey: API_KEY,
contentId: contentId
});

// Update your UI with the new count
updateLikeCountInUI(contentId, likeCount.count);
} catch (error) {
console.error('Error polling like updates:', error);
}
}, intervalMs);
}

Best Practices

When implementing likes functionality:

  • Optimistic Updates: Update the UI immediately when a user clicks like/unlike, then sync with the server
  • Debouncing: Implement debouncing to prevent rapid like/unlike actions that could spam the API
  • Error Handling: Always handle API errors gracefully and revert optimistic updates when necessary
  • Rate Limiting: Respect API rate limits to prevent service disruption
  • Authentication: Ensure users are authenticated before allowing like actions
  • Validation: Validate that content exists before allowing likes
  • Privacy: Respect user privacy settings regarding like visibility
  • Performance: Use pagination for like lists and implement lazy loading for better performance
  • Accessibility: Ensure like buttons are accessible with proper ARIA labels and keyboard navigation