We use cookies to improve your experience. No personal information is gathered and we don't serve ads. Cookies Policy.

ExpressionEngine Logo ExpressionEngine
Features Pricing Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University
Log In or Sign Up
Log In Sign Up
ExpressionEngine Logo
Features Pro new Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University Blog
  • Home
  • Add-Ons
default app icon

Fetchy

By Blair Liikala
Templating

Description

Fetch remote JSON and turn into template tags.

  • Code example
  • Debug and Data

See the YouTube walkthrough

Basic Usage

Here is an example using the Random Fox api. Take the JSON response below:

{
    "image": "https://randomfox.ca/images/110.jpg",
    "link": "https://randomfox.ca/?i=110"
}

EE Template:

{exp:fetchy:get url="https://randomfox.ca/floof/"}

    {data}
        <a href="{link}">
            <img src="{image}" alt="random fox" />
        </a>
    {/data}

{/exp:fetchy:get}

Output:

<a href="https://randomfox.ca/?i=110">
    <img src="https://randomfox.ca/images/110.jpg" alt="random fox" />
</a>

Full Example

{exp:fetchy:get
    url="https://hp-api.onrender.com/api/characters"
    cache="true" refresh="500"
    headers="x-custom: value, x-more: value"
    }

    {data limit="10"}
        <p>{name}, {house} <i>{wand}({wood}/{core}{/wand})</i></p>
    {/data}

    {if empty}
        <p>No Results.</p>
    {/if}

    {if error}
        <div class="error">
            <h3>Error Getting Feed for Harry Potter characters.</h3>
            <p>Message: {error_message}</p>
            <p>url: {url}</p>
            <p>Content Type:
                {response_headers}{content_type}{/response_headers}</p>
            <pre>{body}</pre>
        </div>
    {/if}

{/exp:fetchy:get}

Nested Parameters

Using the SpaceX API https://api.spacexdata.com/v5/launches

{exp:fetchy:get 
    url="https://api.spacexdata.com/v5/launches/latest"
}

    {data}
        <article>
            <p>{details}</p>
            <p>{links}<a href="{webcast}">Livestream Link</a>{/links}</p>
        </article>
    {/data}

{/exp:fetchy:get}

Indexed Arrays

Arrays that have no named key values can be accessed using the item tag. In other words, json arrays looking like this:

{
    "data": [
        "info1",
        "info2",
        "info3"
    ]
}

Will be internally converted so that the EE tags look like this:

{data}
    {item} <!-- info1... -->
{/data}

:get Tag

Parameters

Parameter Description Example Default
url Full path or relative path to a remote data source. Only the “GET” method is supported (at this time…) url=”https://example.com/data.json” (empty)
format JSON or XML parsing format="xml" json
cache To use a cached response if exists and not expired. Clear cache cache="clear" cache="true" false
refresh Time in seconds to cache for. refresh="300" 3600
headers Pass custom headers to the remote URL. Comma-seperated. Useful for bearer tokens. headers="Token: 1234, X-Stuff: things" (*empty)
debug Display the data explorer. Used when building the template tags or debugging. debug="true" false
prefix Append text before each tag name in order to make the tag unique and avoid conflicts elsewhere in the loop. prefix="fetchy_" (empty)
orderby Order by a parameter found in the first level of each item. random is also supported. orderby="name" none.
sort Reorder the first level of data as asc or desc sort="asc" The order the API returned the data.

*Note, the header Content-Type: application/json is applied by default, and Content-Type: application/xml if the format is xml.

Tags

These tags are available on every request:

{data} Loop

Parameter Description
{data}{/data} The loop that will contain the response data tags.
  • Note that count switch and total_results are available in the {data} loop and will have values for data in that loop.

Responses

Parameter Description
{ok} (boolean) Shortcut if the response was successful. Code 200-299 are true, 300-500 will return false. Internal errors of 0 will also return false.
{url} The url used to make the request.
{http_code} The numeric response code (shortcut to the header field value).
{http_code_phrase} A short phrase of the standard code.
{http_code_description} A longer description fo the standard code.
{response_headers}{/response_headers} Loop. The response headers from the CURL request. The list can be found here. Useful for debugging.
{response_body} Raw text of the response from the remote location. Useful for debugging.

Error Handling

Parameter Description
{error} (boolean) General error handler covering any errors from connections, decoding, and server response error codes.
{error_message} A human readable error message set by the add-on due to internal error, or when empty is true.
{internal_error} (boolean) Connection issue, url unreachable, and json/xml parsing error.
{empty} (boolean) No text in the response, or the parsed data is empty. Similar to the native no_results

About Script Blocking

Template with the Fetchy tags will not load until the remote API responds. PHP is synchronous. This means if the remote API takes 10 seconds to respond, then your users could see a white page for 10 seconds, plus your site’s normal rendering time. Therefore use this add-on with caution.

Caching is available to speed up loads. Caches are saved by the full URL, meaning these two paths would have different caches:

https://example.com/api.php
https://example.com/api.php?

Another way around this blocking process is to call the template over javascript.

For example: Visitor EE template -> js -> EE template with Fetchy -> php -> Remote API.

The Fetchy template could look like this to output JSON. It uses the free http_header add-on to set the correct header for returning JSON:

{exp:http_header content_type="application/json"}

{exp:fetchy:get url="xxxx"}
    {json}
{/exp:fetchy:get}

data Parsing Bug

If the response uses the word “data” then there is potential for a name bug/conflict in the EE parser. For example, this would create an error:

{data} <!-- Required -->
    {data} <!-- The API response -->
        {field}
    {/data}
{/data}

Therefore the plugin will change the second (returned) data to _data:

{data}
    {_data}
        {field}
    {/_data}
{/data}

The other solution is using the prefix parameter, however this would also modify all tags in the loop as well.

Error Handling and Debugging

There are multiple ways a request can fail, and Fetchy has tags to handle these. The quickest way to jump in is simply to use {error_messsage} to catch most issues with a general error message, along with {empty}. Here is an example:

{if error_message}
    <p>Something went wrong: {error_message}</p>
{if:elseif empty}
    <p>No Results</p>
{if:else}
    {data}...{/data}
{/if}

A better way is to be much more descriptive about the problem to your users just by using a few more tags. Errors can be put into two groups:

Setup errors such as connection, and content decoding. Fetchy error handling mostly focuses on setup errors to gracefully fail when connection to remote servers or parsing issues happen.

Remote server errors such as the content not being available, rate limiting, or permission issues. Errors coming from the remote service will be different for each service and depend on how their API was designed. For example, if a video was deleted, the service should respond with a 404 http status code, along with an error body explaining the error.

Each API is different in terms of how they setup their body data scheme. Each service will take some time to find the best way of handling errors. With Fetchy, good data scheme and error data schemes are just turned into tags, and the service’s error responses would be available in the {data} tag loop.

A reminder that {empty} looks at all the returned data. If the data return data includes parameters like { success: true, result: 0 } then empty will actually be false since there is data…its just telling you there no results returned.

Event {error_message} {internal_error} {empty} {ok} {http_code} {data}
Unreachable URL yes true false false 0 no
Parsing Error yes true false true/false x > 0 no
Non-200 response code yes false true/false false > 300 yes
Empty response body empty false true true/false > 0 empty
Sucessful Response empty false false true 200 yes

Error Block Example

<!-- Parsing errors, server response code errors, connection errors. -->
{if internal_error}
    <p>An error happened. {error_message}</p>

    Heres More Debug:
    <li>URL: {url}</li>
    <li>Code: {http_code}</li>
    <li>Body: {response_body}</li>
{/if}

<!-- Non-successful error codes. -->
{if !ok}
    <p>The remote server responded with an error.</p>
    {data}
        //...find the specific API error message.
    {/data}
{/if}

<!-- Response was successful -->
{if ok}

    <!-- No text returned, or empty array. -->
    {if empty}
        <p>No Results were returned</p>
    {/if}

    {data}
        //...successful response tags here.
    {/data}

{/if}

Error block with HTTP Codes

<!-- Connection Errors -->
{if status_code == '0'}
    <p>An error happened. {error_message}</p>
    <p>URL: {url}</p>
{/if}

{if status_code == '404'}
    <p>Not Found</p>
{/if}

{if status_code == '429'}
    <p>Too many requests, please wait and try again.</p>
{/if}

{if status_code == '200'}
    <!-- No text returned, or empty array. -->
    {if empty}
        <p>No Results were returned</p>
    {/if}

    {data}...{/data}
{/if}

:parse Tag (bonus)

Already have the JSON and just need to parse it? The Parse tag takes json in the body and converts to tags. The {data} block works exactly the same way as :get.

Example:

{exp:fetchy:parse}
    {json_input}
        // Your json as a string.
    {/json_input}

    {data}
        ...
    {/data}
{/exp:fetchy:parse}

JSON Issues

String numbers are converted into integers and need to be prefixed:

{
    "123": "data", // Numbers as string.
    123: "data", // what is converts to.
    "_123": "data" // Will render correctly.
}

Support

If you find a tag not rendering correctly, check these things first:

  • Are there parsing or other errors? Use the {error_message} tags.
  • Does it have the {data} loop?
  • Is the tag needing to be in a loop?
  • Does it need to be an {item}?
  • Check the debug info using debug="true" to see if there is data in the resposne body.

If those all check out, grab a copy of the JSON, strip any sensitive info, and send a support request along with the template tag you are trying out.

This add-on requires PHP 8.1 or higher.

Information
Version 1.2
Last Update 8 months ago
Compatibility EE 7, 6
License Commercial
Links
  • Support
ExpressionEngine Home Features Pro Contact Version Support
Learn Docs University Forums
Resources Support Add-Ons Partners Blog
Privacy Terms Trademark Use License

Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.