How To Create a dev.to API Wrapper in PHP to Fetch your Latest Posts
Tags: tutorial, php, api, meta
Published: 2020-02-25 12:26:28

---
title: How To Create a dev.to API Wrapper in PHP to Fetch your Latest Posts
published: true
description: In this tutorial, you'll learn how to create an API wrapper in PHP to fetch your latest dev.to posts. 
tags: tutorial, PHP, apis, meta
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/sb0fw4oirat4fang50l6.jpg
---

The dev.to platform is becoming more and more popular among content producers, specially those focused on sharing dev-focused tutorials and articles. Meanwhile, the ongoing discussion about owning your content has a valid point, even though that creates new demands and questions around how to give it more visibility and reach a wider audience, something that a platform such as dev.to facilitates immensely. 

![We can have both!](https://media.giphy.com/media/3ohzdMDbNXvnWdeOZi/giphy.gif) 

Luckily for us, dev.to has a [public API](https://docs.dev.to/api/) that you can use to fetch all your posts, and [you are free to do as you wish](https://dev.to/page/faq) with your own content. 

In this tutorial, you'll learn how to create a wrapper around the dev.to API, using "vanilla" PHP (without userland dependencies). We'll build a class to fetch your latest dev.to posts using the [Curl PHP extension](https://www.php.net/manual/en/book.curl.php). 

### Prerequisites

You'll need PHP (`php-cli` is enough), and the `php-curl` extension installed on your local machine or remote development server. 

We'll run this script from the command line, but you can also run it from a browser if you prefer. In this case, you'll need to run the following command to use PHP's built-in web server to test the script:

```bash
php -S 0.0.0.0:8000
```

This will run a test server using the current directory as document root. You will be able to access it by pointing your browser to `localhost:8000`.

## 1. Dev.to API Overview 

The dev.to API has a few endpoints that require authorization via a personal api token, but you won't need that for fetching public posts from a user.

To fetch your posts, you'll connect to the `/articles` endpoint and provide a `username` parameter with your own dev.to user. 

You can try this query from your browser:

```
https://dev.to/api/articles?username=erikaheidi
```

In the next step, we'll use `curl` to query for this endpoint and manipulate the results in a PHP  script. 

## 2. Using Curl to Query the API

The `php-curl` extension allows us to make HTTP queries in PHP and is a popular choice for connecting and fetching data from APIs. 

The following code will use `curl` functions to connect to the dev.to API and pull the latest posts from the specified user:

```php
<?php

$user = "erikaheidi";
$endpoint = "https://dev.to/api/articles?username=" . $user;

$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_URL => $endpoint,
]);

$response = curl_exec($curl);
curl_close($curl);

$articles = json_decode($response, true);
print_r($response);
```

This code starts by defining the username whose posts we'll be fetching, and the endpoint to query for.

We then initialize a new Curl resource, and use the `curl_setopt_array` function to define the details of our query. The `CURLOPT_RETURNTRANSFER` guarantees that the output produced by the query will be fully returned in the results, and the `CURLOPT_URL` option defines the query endpoint.

The `curl_exec` function makes the query and return its results to a `$response` variable. We then close the Curl resource, and use `json_decode` to decode the returned json into an array that we can later loop through to exhibit the posts.

The `print_r` method is a debug method to show us detailed information about the `$articles` array.

When you run this code (either from your command line or from a browser), you should get output similar to this:

```
Array
(
    [0] => Array
        (
            [type_of] => article
            [id] => 261347
            [title] => Which Techie Are You?
            [description] => Our desks tell a lot about ourselves, don't they? What is your style? 
            [cover_image] => https://res.cloudinary.com/practicaldev/image/fetch/s--PkX-bPVo--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/76j8y68yfscszyf3ripv.png
            [readable_publish_date] => Feb 14
            [social_image] => https://res.cloudinary.com/practicaldev/image/fetch/s--m81Jlno9--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/76j8y68yfscszyf3ripv.png
            [slug] => which-techie-are-you-1251
            [path] => /erikaheidi/which-techie-are-you-1251
            [url] => https://dev.to/erikaheidi/which-techie-are-you-1251
            [canonical_url] => https://dev.to/erikaheidi/which-techie-are-you-1251
            [comments_count] => 109
            [positive_reactions_count] => 121
            [collection_id] => 
            [created_at] => 2020-02-14T07:18:34Z
            [edited_at] => 2020-02-21T16:01:57Z
            [crossposted_at] => 
            [published_at] => 2020-02-14T11:31:10Z
            [last_comment_at] => 2020-02-25T09:17:36Z
            [published_timestamp] => 2020-02-14T11:31:10Z
            [tag_list] => Array
                (
                    [0] => discuss
                    [1] => illustrations
                    [2] => comics
                    [3] => humour
                )

            [tags] => discuss, illustrations, comics, humour
            [user] => Array
                (
                    [name] => Erika Heidi
                    [username] => erikaheidi
                    [twitter_username] => erikaheidi
                    [github_username] => erikaheidi
                    [website_url] => http://heidislab.com
                    [profile_image] => https://res.cloudinary.com/practicaldev/image/fetch/s--ABUlwZrQ--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/162988/5faf315a-4b14-4103-8640-983dfe9d57c2.jpg
                    [profile_image_90] => https://res.cloudinary.com/practicaldev/image/fetch/s--V9Gwrj-u--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/162988/5faf315a-4b14-4103-8640-983dfe9d57c2.jpg
                )

            [flare_tag] => Array
                (
                    [name] => discuss
                    [bg_color_hex] => #000000
                    [text_color_hex] => #FFFFFF
                )

        )

    [1] => Array
        (
            [type_of] => article
            [id] => 252194
            [title] => A Git from the Future (Comic)
            [description] => When working with Git, we often clone existing projects, since this is part of a typical collaboration workflow. What if we want to bootstrap a whole new project of our own?
            [cover_image] => https://res.cloudinary.com/practicaldev/image/fetch/s--WsP0wEBA--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/pvb1vbr5k5tirzqxhlp2.jpg
            [readable_publish_date] => Jan 31
            [social_image] => https://res.cloudinary.com/practicaldev/image/fetch/s--2m-4zDiP--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/i/pvb1vbr5k5tirzqxhlp2.jpg
            [slug] => a-git-from-the-future-comic-p86
            [path] => /erikaheidi/a-git-from-the-future-comic-p86
            [url] => https://dev.to/erikaheidi/a-git-from-the-future-comic-p86
            [canonical_url] => https://dev.to/erikaheidi/a-git-from-the-future-comic-p86
            [comments_count] => 15
            [positive_reactions_count] => 147
            [collection_id] => 4483
            [created_at] => 2020-01-31T11:12:49Z
            [edited_at] => 2020-01-31T11:51:03Z
            [crossposted_at] => 
            [published_at] => 2020-01-31T11:48:56Z
            [last_comment_at] => 2020-02-10T04:59:03Z
            [published_timestamp] => 2020-01-31T11:48:56Z
            [tag_list] => Array
                (
                    [0] => git
                    [1] => beginners
                    [2] => comics
                    [3] => illustrated
                )

            [tags] => git, beginners, comics, illustrated
            [user] => Array
                (
                    [name] => Erika Heidi
                    [username] => erikaheidi
                    [twitter_username] => erikaheidi
                    [github_username] => erikaheidi
                    [website_url] => http://heidislab.com
                    [profile_image] => https://res.cloudinary.com/practicaldev/image/fetch/s--ABUlwZrQ--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/162988/5faf315a-4b14-4103-8640-983dfe9d57c2.jpg
                    [profile_image_90] => https://res.cloudinary.com/practicaldev/image/fetch/s--V9Gwrj-u--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/162988/5faf315a-4b14-4103-8640-983dfe9d57c2.jpg
                )

        )

...
)

```

You'll notice that the results contain only a summary of the articles information, and doesn't contain the body of the article itself. Depending on your use case, you might want to fetch the content of the article as well; this will require an additional query for each article in the list. 

In the next section, we'll refactor this code to turn it into a class, and then we'll include a new method to fetch individual articles too. 

## 3. Creating an API wrapper class

So far, we've seen how to make queries to the dev.to API using the Curl PHP extension to fetch a list containing your most recent posts. We'll now create a Wrapper class to facilitate handling these operations and reusing the code in multiple locations. 

Create a new folder in your directory of choice and a new file named `DevtoWrapper.php` inside of it.

The following code defines a new class named `DevtoWrapper` containing the code we've seen in the last section, now refactored into a class:

```php
<?php

class DevtoWrapper
{
    static $ARTICLES_ENDPOINT = 'https://dev.to/api/articles';

    public function fetchArticlesFromUser($username)
    {
        return $this->get(self::$ARTICLES_ENDPOINT . "?username=" . $username);
    }

    private function get($endpoint)
    {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_URL => $endpoint,
        ]);

        $response = curl_exec($curl);
        curl_close($curl);

        return json_decode($response, true);
    }
}
```

We've created a `get` method with the portion of the code that would get duplicated if we were to include new methods that query the API, as we're going to do next.

But first, let's replace the `test.php` code to include that class file, instantiate a new `DevtoWrapper` object and call the `fetchArticlesFromUser` method:

```php
<?php

require('DevtoWrapper.php');

$user = "erikaheidi";
$wrapper = new DevtoWrapper();

$articles = $wrapper->fetchArticlesFromUser($user);
print_r($articles);

```

Running the `test.php` script now will produce the same output as before.

Now you can include additional methods to the `DevtoWrapper` class. We'll include a method to call the `/articles/{article_id}` endpoint, which will fetch the full article information including the body of content in both markdown and html. 

This is how the updated `DevtoWrapper` class looks after including the `fetchArticle` method:


```php
<?php

class DevtoWrapper
{
    static $ARTICLES_ENDPOINT = 'https://dev.to/api/articles';

    public function fetchArticlesFromUser($username)
    {
        return $this->get(self::$ARTICLES_ENDPOINT . "?username=" . $username);
    }

    public function fetchArticle($article_id)
    {
        return $this->get(self::$ARTICLES_ENDPOINT . "/" . $article_id);
    }

    private function get($endpoint)
    {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_URL => $endpoint,
        ]);

        $response = curl_exec($curl);
        curl_close($curl);

        return json_decode($response, true);
    }
}
```

After updating your `DevtoWrapper` class, you can now obtain the full content of all your articles by looping through the list and calling the `fetchArticle` method for each article.

The following code will fetch your 30 most recent articles and save their full markdown body into local `.md` files inside a directory called `articles`. Make sure you create this directory before running the code:


```php
<?php

require('DevtoWrapper.php');

$user = "erikaheidi";
$articles_dir = "articles";

$wrapper = new DevtoWrapper();

$articles = $wrapper->fetchArticlesFromUser($user);

foreach ($articles as $article) {
    echo "Importing " . $article['title'] . "...\n";

    $filename = $article['slug'] . '.md';
    $full_article = $wrapper->fetchArticle($article['id']);

    try {
        $file = fopen($articles_dir . '/' . $filename, 'w+');
        fwrite($file, $full_article['body_markdown']);
        fclose($file);
    } catch (Exception $e) {
        echo "There was an error while trying to save the file.";
    }
}
```

When you run this code, it will output a message telling which article is being imported at each iteration of the `foreach` loop. When it is finished, check your `articles` folder - you should find your articles there, in individual `.md` files containing the full markdown body as published on your dev.to account.

```bash
ls articles
```

```
a-git-from-the-future-comic-p86.md
an-introduction-to-3d-printing-ln1.md
a-primer-on-basic-electronics-and-circuits-n3e.md
bootstrapping-a-cli-php-application-in-vanilla-php-4ee.md
building-minicli-autoloading-command-namespaces-3ljm.md
creativity-is-the-pipeline-2pm6.md
...
```

Importing your dev.to posts into markdown files can be very useful if you want to display the full content on your own blog or site, but you can also use the listing and link back to dev.to if you'd prefer to only exhibit a summary of your posts.


## Conclusion

In this tutorial, we've seen how to import your dev.to articles into local markdown files that you can then aggregate to an existing blog or website. 

As next steps, you could use a markdown parser such as [ParseDownExtra](https://github.com/erusev/parsedown-extra) to convert the markdown content into HTML, or use a database to persist your articles content along with all the metadata associated with them, making it easier for searching and listing these posts on your own blog or website.