Jump to content

AppApi Module: AppApiPage


Sebi
 Share

Recommended Posts

AppApiPage adds the /page endpoint to the AppApi routes definition. Makes it possible to query pages via the api. 
This module relies on the base module AppApi, which must be installed before AppApiPage can do its work.

Route Description
/api/page/ Calls the root page of the page-tree
/api/page/42 Will call the page with id=42
/api/page/my/test/page Calls your page with path my/test/page

After installing AppApi and AppApiPage, you simply have to add the following code at the top of your ProcessWire-template to provide your page with a custom JSON output:

<?php
// Check if AppApi is available:
if (wire('modules')->isInstalled('AppApi')) {
  $module = $this->wire('modules')->get('AppApi');
  // Check if page was called via AppApi
  if($module->isApiCall()){
    // Output id & name of current page
    $output = [
      'id' => wire('page')->id,
      'name' => wire('page')->name
    ];

    // sendResponse will automatically convert $output to a JSON-string:
    AppApi::sendResponse(200, $output);
  }
}

// Here continue with your HTML-output logic...
  • Like 6
  • Thanks 1
Link to comment
Share on other sites

@flydev ?? Yep, that's right. The module has basically the same code as the PageApiAccess class that I posted in the other thread. I added an improvement for handling the "lang"-GET-param, that enables you to switch to another language in a multilang environment. But everything else is the same code.

 

  • Thanks 2
Link to comment
Share on other sites

  • 8 months later...
On 3/7/2022 at 9:30 PM, Sebi said:

Yep, that's right. The module has basically the same code as the PageApiAccess class that I posted in the other thread. I added an improvement for handling the "lang"-GET-param, that enables you to switch to another language in a multilang environment. But everything else is the same code.

Hi @Sebi Would you please give some actual code examples? I've tried all sorts of variations and if I manage to get a response, it's always in the default lang (English), eg:

Spoiler
<script>
// Javscript in page template
  
      const testing = async (url) => {
          let connect = await fetch(url, {
              method: 'GET',
              credentials: 'same-origin',
              mode: 'same-origin',
              headers: {
                  'x-api-key': 'xxxxxxxxxxxxxxxxxxxxxxx',
              }
          })

          let result = await connect.json()
          return result
      }

// Testing AppApi only
      
// const url ="/api/v1/licki/test"        // works. Multilang not tested
// const url ="/api/v1/users/41"          // works. Multilang not tested
      
// Testing AppApiPage
      
// const url = "/api/page/1/?lang=german"  // returns default lang obj {id: 1, name: 'home', title: 'Home', path: '/'}.
                                           // title should be German 'Startseite' and path '/de/'
      
// const url = "/api/page/1/de"            // fails with {error: 'Method Page::localUrl does not exist or is not callable 
                                           // in this context', devmessage: {…}}
      
// const url = "/api/page/de/1"            // fails with {error: 'Method Page::localUrl does not exist or is not callable 
                                           // in this context', devmessage: {…}}
      
// const url = "/api/page/home/de"         // fails with {error: 'Method Page::localUrl does not exist or is not callable 
                                           // in this context', devmessage: {…}}
      
// const url = "/api/page/1/?lang=de"      // fails with {error: 'Method Page::localUrl does not exist or is not callable 
                                           // in this context', devmessage: {…}} 

     const url = "/api/page/1/?lang=german"
		testing(url).then((res) => {
        console.log(res)
        }
     )
</script>

 

Thanks for all the work you've done with AppApi and the add-on modules.

Hope you can help.

Cheers
psy

SOLVED (almost!)

In _init.php:

Spoiler

 

<?php

// Check if AppApi is available:
if (wire('modules')->isInstalled('AppApi')) {
    $module = $this->wire('modules')->get('AppApi');
    // Check if page was called via AppApi
    if($module->isApiCall()){
        $slug = $user->language->name !== 'default' ? '/' . $pages->get(1)->getLanguageValue($user->language, 'name') : '';
          $output = [
            'id' => $page->id,
            'name' => $page->name,
            'title' => $page->title,
            'slug' => \ltrim($slug, '/'),
            'path' => $slug . $page->path,
            'lang' => $user->language->name,
        ];
        // sendResponse will automatically convert $output to a JSON-string:
       AppApi::sendResponse(200, $output);
    }
}

 

In my page template javascript:

Spoiler
<script>
	const pathArray = window.location.pathname.split('/')
	console.log(pathArray)

    const url = `/api/page/1028/?lang=${pathArray[1]}`
    testing(url).then((res) => {
        console.log(res)
        }
     )
</script>

 

In my AppApi custom class to make it multi-language:

Spoiler
<?php
    public static function myFunction($data)
    {
        $pages = wire('pages');
        $input = wire('input');
        $sanitizer = wire('sanitizer');
        $languages = wire('languages');
        $modules = wire('modules');

        $data = AppApiHelper::checkAndSanitizeRequiredParameters($data, ['id|int']);

        if (!empty($input->get->lang)) {
            $slug = $sanitizer->pageName($input->get->lang);
            if ($modules->isInstalled('AppApiPage')) {
                $langName = AppApiPage::getLanguageCode($slug);
                if ($langName)  $languages->setLanguage($langName);
            }
        }
        $response = new \StdClass();
        $page = $pages->get($data->id);

        if (!$page->id || $page instanceof NullPage) {
            throw new \Exception('Not found', 404);
        }

        $response->id = $page->id;
        $response->name = $page->name;
        $response->title = $page->title;

        return $response;

    }

 

Everything seems to work fine EXCEPT when using AppApiPage on the home page. The response is still always in the default language.

 

Link to comment
Share on other sites

  • 2 years later...

Hey @Sebi, I had zero problems for several months, but today a client told me that a site, that was working perfectly, suddenly stopped working. I have a SvelteKit WebApp that uses PW as API with AppApi and all other routes are working fine (status code 200, correct json) except of those called via /api/page/... 

The (API) webserver gives a status code 500, although outputting correct json:

curl -v -H "Origin: https://domain.com" https://api.comain.com/api/page/touren
*   Trying XX.XX.XX.XX:443...
* Connected to api.domain.com (XX.XX.XX.XX) port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=api.domain.com
*  start date: Dec  9 14:27:01 2024 GMT
*  expire date: Mar  9 14:27:00 2025 GMT
*  subjectAltName: host "api.domain.com" matched cert's "api.domain.com"
*  issuer: C=US; O=Let's Encrypt; CN=R10
*  SSL certificate verify ok.
* using HTTP/2
* h2 [:method: GET]
* h2 [:scheme: https]
* h2 [:authority: api.domain.com]
* h2 [:path: /api/page/touren]
* h2 [user-agent: curl/8.1.2]
* h2 [accept: */*]
* h2 [origin: https://domain.com]
* Using Stream ID: 1 (easy handle 0x14c00c600)
> GET /api/page/touren HTTP/2
> Host: api.domain.com
> User-Agent: curl/8.1.2
> Accept: */*
> Origin: https://domain.com
>
< HTTP/2 500
< server: nginx
< date: Thu, 09 Jan 2025 23:51:40 GMT
< content-type: application/json
< expires: Thu, 19 Nov 1981 08:52:00 GMT
< cache-control: no-store, no-cache, must-revalidate
< pragma: no-cache
< x-powered-by: ProcessWire CMS
< access-control-allow-origin: https://domain.com
< access-control-allow-headers: Content-Type, AUTHORIZATION, X-API-KEY
< access-control-allow-credentials: true
< x-original-status: 200
< set-cookie: wires=krcrpn4pn6v9pc16mbqXXXXXX; path=/; secure; HttpOnly; SameSite=Lax
< x-frame-options: SAMEORIGIN
< x-xss-protection: 1; mode=block
<
{"last_modified":1729504403,"tours":[{...}]... (json is fine)

I tried a lot, but there is nothing in the logs indicating a solution. Maybe you have an explanation or can give me a hint?

This was working perfectly fine for more than a year and suddenly stopped working, although nothing (PHP version, PW version, code) changed in the last few months (at least nothing that I am aware of). 

Any help is appreciated.

Thanks,
Flo

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...