Offer users either xml response or json based on URL


#1

So I am trying to work out the best way to allow users to request either xml, json, ymal response from the API. I understand that each needs to have a template view, which I have done (see below a file layout). But what I can not work out - and yes this could be because it is the first slim app I have made.

So a user will request data from http://api.site.com/me/{user}.xml
This would be simular to Twitter API https://api.twitter.com/1.1/statuses/user_timeline.json

Now I don’t know if this is a good idea, I just know that the more options I can return the results to the developer the more likely apps will be developed.

I will state though, don’t most poeple just use JSON?

My app folder layout

  • layouts
    • xml
      • books.xml
    • json
      • book.json
  • Views
    • media.php
    • profiles.php
  • index.php

#2

Usually when you’re offering output in XML/JSON format, it’s an API and so the information you want to send the user is structured.

If so, then rka-content-type-renderer may help you as it will render an array into either JSON, XML or HTML based on the Accept Header.

This is a simple Slim route that uses it:

$app->get("/users", function ($request, $response, $args) {

    $data = [
        'items' => [
            [
                'name' => 'Alex',
                'is_admin' => true,
            ],
            [
                'name' => 'Robin',
                'is_admin' => false,
            ],
        ],
    ];

    $renderer = new RKA\ContentTypeRenderer\Renderer();
    $response = $renderer->render($request, $response, $data);

    return $response;
});

To get XML output, the user simply requests XML via the HTTP Accept header:

$ curl -H "Accept: application/xml" http:/localhost:8888/users
<?xml version="1.0"?>
<root>
  <items>
    <name>Alex</name>
    <is_admin>1</is_admin>
  </items>
  <items>
    <name>Robin</name>
    <is_admin>0</is_admin>
  </items>
</root>

To get JSON:

$ curl -H "Accept: application/json" http:/localhost:8888/users
{
    "items": [
        {
            "name": "Alex",
            "is_admin": true
        },
        {
            "name": "Robin",
            "is_admin": false
        }
    ]
}

Now, if you wanted to allow uses to set the format via the URL rather than the Accept header, I would use a format query parameter, so that the URL looks like http:/localhost:8888/users?format=xml.

To do this, write some middleware:

// middleware that converts ?format=xxx to an Accept header
$app->add(function ($request, $response, $next) {
    $format = $request->getParam('format');
    if ($format) {
        $mapping = [
            'html' => 'text/html',
            'xml' => 'application/xml',
            'json' => 'application/json',
        ];
        if (isset($mapping[$format])) {
            $request = $request->withHeader('Accept', $mapping[$format]);
        }
    }
    return $next($request, $response, $next);
});

and now http:/localhost:8888/users?format=xml will render XML.


#3

Hi I got this error

Class ‘RKA\ContentTypeRenderer’ not found in home/DIRECTORY/public_html/index.php on line 29

is their a composer I need to add?


#4

YEP NOOB composer require akrabat/rka-content-type-renderer


#5

Thank @akrabat Just wondering is there away that is the format is not in the URL string that it returns an error "sorry your missing format in your request string?

this is what I added to the code to make an error accor, however I am sure there would have to be a better way?

$app->add(function ($request, $response, $next) {
    $format = $request->getParam('format');
    if ($format) {
        $mapping = [
            'html' => 'text/html',
            'xml' => 'application/xml',
            'json' => 'application/json',
        ];
        if (isset($mapping[$format])) {
            $request = $request->withHeader('Accept', $mapping[$format]);
        }
        else{
          print "error";
          die();
        }
    }
    return $next($request, $response, $next);
});

#6

If the format doesn’t exist, then return a $response from this middleware with the appropriate error in it. Of course, this is not necessary as you should be honouring the Accept header.


#9

Perhaps try composer dump-autoload ?


#11

sorry, i do not replicat on server the local installation of the package.
my stupid mistake


#12
Hi! 
I need to follow a payment process and I need to save XML file into a variable which need to be encrypted and send to the payment server together with other encrypted vars. My quests are:
1. to get the XML file into a variable for later encryption
2. to create a custom XML structure (withour <root> and similar). See bellow the XML structure I need to get:
    <?xml version="1.0" encoding="UTF-8"?>
    <order type="card" id="1" timestamp="201820182018201806062525161658583434">
        <signature>ABCD-ABCD-ABCD-ABCD-ABCD</signature>
        <invoice currency="RON" amount="11.99">
            <details>Plata cu card-ul prin mobilPay</details>
            <contact_info>
                <billing type="person">
                    <first_name>Andrei</first_name>
                    <last_name>Mirlo</last_name>
                    <email>email@yahoo.com</email>
                    <address></address>
                    <mobile_phone>07070707070</mobile_phone>
                </billing>
            </contact_info>
        </invoice>
        <params>
            <param>
                <name>param1Name</name>
                <value>param1Value</value>
            </param>
        </params>
        <url>
            <confirm>https://blabla.com/public/</confirm>
            <return>https://blabla.com/backpublic/</return>
        </url>
    </order>