API Builder (widgets)

Modified on Wed, 1 Apr at 5:50 AM

APIBuilder Documentation 

Overview 

The APIBuilder provides a fluent interface for making authenticated API calls to MAGICapp's API. It's automatically available through the magicapp-connect component and includes predefined methods for common endpoints plus a flexible builder pattern for custom API calls.

Installation 

The APIBuilder will lazy load via the magicapp-connect component.

<script type="module">
  import 'https://app.magicapp.org/widget/connectServiceComponent.js';
</script>

Basic Usage 

Access the APIBuilder through a connected magicapp-connect component:

const connector = document.querySelector('magicapp-connect');

// Wait for connection
connector.addEventListener('connected', async () => {
  // Now you can use the API
  const guidelines = await connector.api.guidelines.getAll();
  console.log(guidelines);
});

Predefined APIs 

The APIBuilder includes predefined methods for common MAGICapp endpoints.

Guidelines API 

Access guideline data through convenient methods:

const connector = document.querySelector('magicapp-connect');

// Get all guidelines
const guidelines = await connector.api.guidelines.getAll(queryParams);

// Get guideline by ID
const guideline = await connector.api.guidelines.getById(id);

// Get current published guideline by short code
const current = await connector.api.guidelines.getCurrentPublishedGuideline(shortCode);

// Get latest guideline IDs
const ids = await connector.api.guidelines.getLatestGuidelineIds(shortCode);

// Get recommendation metadata for a guideline
const meta = await connector.api.guidelines.getMetaByGuideline(guidelineId);

Guidelines API Methods 

MethodParametersReturnsDescription
getAll(queryParams?)queryParams (object, optional)Promise<Array>Get all guidelines with optional query filters
getById(id)id (long)Promise<Object>Get specific guideline by ID
getCurrentPublishedGuideline(shortCode)shortCode (string)Promise<Object>Get the current published version by short code
getLatestGuidelineIds(shortCode)shortCode (string)Promise<Object>Get the latest guideline version IDs
getMetaByGuideline(guidelineId)guidelineId (long)Promise<Array>Get recommendation metadata for a guideline
getGuidelineToc(guidelineId)guidelineId (long)Promise<Array>Get Table of Contents
getSection(guidelineId, sectionId)guidelineId (long), sectonId (long)Promise<Array>Get a single Section
getSections(guidelineId)guidelineId (long)Promise<Array>Get all sections for a Guideline
getSectionText(guidelineId)guidelineId (long), sectonId (long)Promise<Array>Get just the text for a single Section


Guidelines API Examples 

// Get all guidelines
const allGuidelines = await connector.api.guidelines.getAll();

// Get guidelines with query parameters
const filteredGuidelines = await connector.api.guidelines.getAll({
  status: 'published',
  limit: 10
});

// Get specific guideline
const guideline = await connector.api.guidelines.getById('123456');

// Get current published version
const current = await connector.api.guidelines.getCurrentPublishedGuideline('x1j32ks'); // shortcode

// Get latest IDs for a guideline
const ids = await connector.api.guidelines.getLatestGuidelineIds('x1j32ks');   // shortcode
console.log(ids);
// {
//   currentPublished: { guidelineId: '12345', version: '2.1' },
//   latest: { guidelineId: '12346', version: '2.2' }
// }

// Get all recommendations for a guideline
const recommendations = await connector.api.guidelines.getMetaByGuideline('12345');
recommendations.forEach(rec => {
  console.log(rec.recommendationId, rec.title);
});

Fluent Builder Pattern 

For custom API endpoints not covered by predefined methods, use the fluent builder:

Basic Builder Usage 

const connector = document.querySelector('magicapp-connect');

// GET request
const data = await connector.api
  .get()
  .endpoint('/api/v1/resource')
  .execute();

// POST request
const created = await connector.api
  .post()
  .endpoint('/api/v1/resource')
  .body({ name: 'Example', value: 42 })
  .execute();

// PUT request
const updated = await connector.api
  .put()
  .endpoint('/api/v1/resource/{id}')
  .pathParams({ id: 123 })
  .body({ name: 'Updated' })
  .execute();

Builder Methods 

HTTP Methods 

Set the HTTP method for your request:

// GET request
connector.api.get()

// POST request
connector.api.post()

// PUT request
connector.api.put()

Set the API endpoint path. Supports path parameter placeholders using {param} syntax:

// Simple endpoint
.endpoint('/api/v1/guidelines')

// Endpoint with path parameters
.endpoint('/api/v1/guidelines/{id}')
.endpoint('/api/v1/users/{userId}/posts/{postId}')

Parameters:

  • path (string): API endpoint path with optional {param} placeholders

Returns: Builder instance (chainable)

path Params(params) 

Replace path parameter placeholders with actual values:

.endpoint('/api/v1/users/{userId}/posts/{postId}')
.pathParams({ userId: 123, postId: 456 })
// Results in: /api/v1/users/123/posts/456

Parameters:

  • params (object): Key-value pairs where keys match placeholder names

Returns: Builder instance (chainable)

Note: Values are automatically URL-encoded.

query(params) 

Add query string parameters:

.endpoint('/api/v1/guidelines')
.query({ page: 1, size: 20, sort: 'name' })
// Results in: /api/v1/guidelines?page=1&size=20&sort=name

Parameters:

  • params (object): Key-value pairs for query parameters

Returns: Builder instance (chainable)

Note: Multiple calls to query() will merge parameters.

body(data) 

Set the request body (for POST, PUT, PATCH requests):

.post()
.endpoint('/api/v1/resource')
.body({ name: 'Example', value: 42 })

Parameters:

  • data (object): Data to send (will be JSON.stringify'd automatically)

Returns: Builder instance (chainable)

Note: Body is automatically ignored for GET and DELETE requests.

headers(headers) 

Add custom headers to the request:

.endpoint('/api/v1/resource')
.headers({ 
  'X-Custom-Header': 'value',
  'X-Request-ID': '12345'
})

Parameters:

  • headers (object): Key-value pairs for custom headers

Returns: Builder instance (chainable)

Note: The Authorization and Content-Type headers are set automatically.

execute()send() 

Execute the built request:

const result = await connector.api
  .get()
  .endpoint('/api/v1/resource')
  .execute();

// Or use send() - it's an alias
const result = await connector.api
  .get()
  .endpoint('/api/v1/resource')
  .send();

Returns: Promise<any> - Parsed JSON response

Throws: Error if the request fails or the token is invalid


Complete Examples 

Example 1: Get Guidelines with Filtering 

const connector = document.querySelector('magicapp-connect');

connector.addEventListener('connected', async () => {
  try {
    // Using predefined method
    const guidelines = await connector.api.guidelines.getAll({
      name: 'cardiology',
      limit: 10
    });
    
    displayGuidelines(guidelines);
  } catch (error) {
    console.error('Failed to load guidelines:', error);
  }
});

Example 2: Complex Workflow 

const connector = document.querySelector('magicapp-connect');

connector.addEventListener('connected', async () => {
  try {
    // Step 1: Get all guidelines
    const guidelines = await connector.api.guidelines.getAll();
    console.log('Found', guidelines.length, 'guidelines');
    
    // Step 2: Get latest IDs for first guideline
    const ids = await connector.api.guidelines.getLatestGuidelineIds(
      guidelines[0].shortCode
    );
    console.log('Latest guideline ID:', ids.currentPublished.guidelineId);
    
    // Step 3: Get recommendations for this guideline
    const recommendations = await connector.api.guidelines.getMetaByGuideline(
      ids.currentPublished.guidelineId
    );
    console.log('Found', recommendations.length, 'recommendations');
    
    // Step 4: Display first 5 recommendations
    recommendations.slice(0, 5).forEach(rec => {
      console.log(`- ${rec.title} (ID: ${rec.recommendationId})`);
    });
    
  } catch (error) {
    console.error('Workflow failed:', error);
  }
});

Example 3: Custom Endpoint with Builder 

const connector = document.querySelector('magicapp-connect');

connector.addEventListener('connected', async () => {
  try {
    // Custom GET with path params and query
    const user = await connector.api
      .get()
      .endpoint('/api/v1/users/{userId}')
      .pathParams({ userId: 123 })
      .query({ include: 'profile,permissions' })
      .execute();
    
    console.log('User:', user);
    
    // Custom POST
    const newResource = await connector.api
      .post()
      .endpoint('/api/v1/resources')
      .body({
        title: 'New Resource',
        content: 'Resource content here',
        tags: ['tag1', 'tag2']
      })
      .execute();
    
    console.log('Created:', newResource);
    
    // Custom PUT with headers
    const updated = await connector.api
      .put()
      .endpoint('/api/v1/resources/{id}')
      .pathParams({ id: newResource.id })
      .headers({ 'X-Update-Reason': 'User requested change' })
      .body({ title: 'Updated Title' })
      .execute();
    
    console.log('Updated:', updated);
    
  } catch (error) {
    console.error('API call failed:', error);
  }
});

Example 4: Pagination 

async function loadAllGuidelines() {
  const connector = document.querySelector('magicapp-connect');
  let allGuidelines = [];
  let page = 1;
  const pageSize = 20;
  
  while (true) {
    const result = await connector.api
      .get()
      .endpoint('/api/v1/guidelines')
      .query({ offset: page, limit: pageSize })
      .execute();
    
    allGuidelines = allGuidelines.concat(result.items);
    
    if (result.items.length < pageSize) {
      break; // Last page
    }
    
    page++;
  }
  
  return allGuidelines;
}

Example 5: Error Handling 

const connector = document.querySelector('magicapp-connect');

connector.addEventListener('connected', async () => {
  try {
    const data = await connector.api.guidelines.getAll();
    displayData(data);
    
  } catch (error) {
    // Handle different error types
    if (error.message.includes('Not connected')) {
      alert('Please connect to MAGICapp first');
      
    } else if (error.message.includes('reconnect')) {
      alert('Your session expired. Please reconnect.');
      connector.disconnect();
      
    } else if (error.message.includes('401')) {
      alert('Authentication failed. Please reconnect.');
      connector.disconnect();
      
    } else if (error.message.includes('403')) {
      alert('You do not have permission to access this resource');
      
    } else if (error.message.includes('404')) {
      alert('Resource not found');
      
    } else {
      console.error('API Error:', error);
      alert('An error occurred. Please try again.');
    }
  }
});

API Endpoints Reference 

Base URLs 

The base URL is automatically selected based on your environment.

Common Endpoints 

EndpointMethodDescription
/api/v1/guidelinesGETGet all guidelines
/api/v1/guidelines/{id}GETGet a guideline by ID
/api/v1/guidelines/{shortCode}/currentGETGet the current published guideline
/api/v2/guidelines/{shortCode}/latestGETGet latest guideline IDs
/api/v2/guidelines/{gId}/recommendation/metaGETGet recommendation metadata

Note: The predefined guidelines API methods handle these endpoints for you.


Authentication 

All API requests made through the APIBuilder are automatically authenticated:

  1. Access Token: Automatically included Authorization: Bearer {token} in the header
  2. Auto-Refresh: If a token is expired or expiring soon (< 60s), it's automatically refreshed
  3. Public Fallback: If no token is available, the request is made as a public user (no auth header)

You don't need to manually manage authentication—the magicapp-connect component handles it.


Error Handling 

Common Error Scenarios 

try {
  const data = await connector.api.guidelines.getAll();
} catch (error) {
  // Error types you might encounter:
  
  // 1. Not connected
  if (error.message.includes('Not connected')) {
    // User needs to connect first
  }
  
  // 2. Token expired
  if (error.message.includes('reconnect')) {
    // Session expired, prompt reconnection
  }
  
  // 3. Network error
  if (error.message.includes('Failed to fetch')) {
    // Network issue or API is down
  }
  
  // 4. HTTP errors
  if (error.message.includes('401')) {
    // Unauthorized - auth failed
  }
  if (error.message.includes('403')) {
    // Forbidden - no permission
  }
  if (error.message.includes('404')) {
    // Not found
  }
  if (error.message.includes('500')) {
    // Server error
  }
}

Best Practices 

  1. Always use try-catch when making API calls
  2. Listen for error events on the connector
  3. Check connection status before making calls
  4. Provide user feedback for all error scenarios
  5. Log errors for debugging (but not tokens!)


Rate Limits 

MAGICapp API enforces rate limits:

  • API endpoints: 1000 requests per hour per user
  • Token endpoint: 10 requests per minute per client

Exceeding limits returns 429 Too Many Requests with a Retry-After header.


Handling Rate Limits 

try {
  const data = await connector.api.guidelines.getAll();
} catch (error) {
  if (error.message.includes('429')) {
    alert('Rate limit exceeded. Please wait and try again.');
    // Optionally parse Retry-After header
  }
}

Testing 

Test Environment 

Use the test environment for development:

<!-- Your app at app-test.magicapp.org automatically uses test environment -->
<magicapp-connect client-id="your-client-id" env="test"></magicapp-connect>

Test environment automatically provides:


Local Development 

For local development:

<!-- Your app at localhost automatically uses local environment -->
<magicapp-connect client-id="your-client-id" env="local"></magicapp-connect>

Requires running local services:


TypeScript Support 

While the component is written in vanilla JavaScript, you can add type definitions for better IDE support:

interface Guideline {
  id: string;
  name: string;
  shortCode: string;
  version: string;
  status: string;
}

interface GuidelineIds {
  currentPublished: {
    guidelineId: string;
    version: string;
  };
  latest: {
    guidelineId: string;
    version: string;
  };
}

interface RecommendationMeta {
  recommendationId: string;
  title: string;
  text: string;
  strength: string;
}

// Use with API calls
const guidelines: Guideline[] = await connector.api.guidelines.getAll();
const ids: GuidelineIds = await connector.api.guidelines.getLatestGuidelineIds(shortCode);
const meta: RecommendationMeta[] = await connector.api.guidelines.getMetaByGuideline(guidelineId);

Browser Compatibility 

The APIBuilder works in all modern browsers that support:

  • ES6 Modules
  • Promises/async-await
  • Fetch API
  • URLSearchParams

Supported browsers:

  • Chrome/Edge 80+
  • Firefox 75+
  • Safari 13.1+
  • Opera 67+


Support 

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article