Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed modules/bc_api_docs/assets/dist/.DS_Store
Binary file not shown.
Binary file removed modules/bc_api_docs/assets/dist/js/.DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions modules/bc_api_example/bc_api_example.info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ core_version_requirement: ^10 || ^11
package: Bluecadet

dependencies:
- drupal:taxonomy
- bc_api_base:bc_api_base

configure: null
Expand Down
23 changes: 23 additions & 0 deletions modules/bc_api_example/bc_api_example.routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,26 @@ bc_api_example.pirates_detail:
parameters:
nid:
type: entity:node

bc_api_example.cacheable.pirates:
path: '/api/cacheable/pirates'
methods: [GET, HEAD]
defaults:
_controller: '\Drupal\bc_api_example\Controller\ApiControllerCacheableResponsePirateExample:getResourceList'
requirements:
_permission: 'use api'
options:
_auth: [ 'key_auth' ]

bc_api_example.cacheable.pirates_detail:
path: '/api/cacheable/pirates/{nid}'
methods: [GET, HEAD]
defaults:
_controller: '\Drupal\bc_api_example\Controller\ApiControllerCacheableResponsePirateExample:getResource'
requirements:
_permission: 'use api'
options:
_auth: [ 'key_auth' ]
parameters:
nid:
type: entity:node
Binary file removed modules/bc_api_example/config/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<?php

namespace Drupal\bc_api_example\Controller;

use Drupal\bc_api_base\Controller\ApiControllerBase;
use Drupal\bc_api_base\CacheableJsonResponseTrait;

/**
* Example API Controller Class.
*
* @ApiDoc(
* params = {
* @ApiParam(
* name = "status",
* type = "bool",
* description = "Filter on node status.",
* default = "TRUE",
* ),
* @ApiParam(
* name = "nat",
* type = "int",
* description = "Filter on nationality. This should use the taxonomy id of the nationality.",
* ),
* }
* )
*/
class ApiControllerCacheableResponsePirateExample extends ApiControllerBase {

use CacheableJsonResponseTrait;

/**
* {@inheritdoc}
*/
public function getApiCacheTime($id = NULL) {
// Parent method looks at settings form and takes into account list or
// detail.
return 0;
}

/**
* {@inheritdoc}
*/
public function getCacheId() {
// This should be a unique string, characters only.
$cid = "yo-ho-ho";

if (!empty($this->params)) {
$cid .= ":" . implode(":", $this->params);
}

$cid .= ":page-" . $this->page;
$cid .= ":limit-" . $this->limit;

return $cid;
}

/**
* {@inheritdoc}
*/
public function initCacheTags() {
$this->cacheTags = [
'myAwesomeCoolCacheTag',
];
}

/**
* {@inheritdoc}
*/
public function setParams() {
// It would be good to always run this.
parent::setParams();

$this->privateParams['status'] = 1;

// Here we also want to handle any bad param errors...
}

/**
* {@inheritdoc}
*/
public function getDefaultPlatform() {
return "cinder";
}

/**
* {@inheritdoc}
*/
public function getResourceQueryResult() {
// Just having this here as an example.
// Most times no need to override this method.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by this comment, because lines 92-94 show a clear reason for overriding the method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm... ok the non-cacheable one makes sense. But this one doesn't. Esp. since I'm using a trait and not extending the class. 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... that "example" should be added to the trait. then the comment will be valid then.

parent::getResourceQueryResult();
}

/**
* {@inheritdoc}
*/
public function getResourceListQueryResult() {
// This method should be overridden for any endpoint.
$query = $this->entityTypeManager->getStorage('node')->getQuery();
$query->accessCheck(TRUE);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know this is just an example, but should we recommend that accessCheck() be FALSE? otherwise, the results could vary based on which user triggers the API call, right?

$query->condition('status', $this->privateParams['status']);
$query->condition('type', 'pirate');

$count_query = clone $query;

$query->range(($this->page * $this->limit), $this->limit);
$entity_ids = $query->execute();

// Must set total result count so we can properly page.
$this->resultTotal = (int) $count_query->count()->execute();

// Process Items.
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($entity_ids);

$this->rawData = $nodes;
}

/**
* {@inheritdoc}
*/
public function buildAllResourceData() {
$data = [];

foreach ($this->rawData as $node) {
$this->cacheTags = array_merge($this->cacheTags, $node->getCacheTags());
$this->addCacheableDependency($node);
$created_changed = $this->transformer->createdChangedFieldVals($node);

$item = [
'nid' => (int) $node->id(),
'cms_title' => $node->label(),
'created' => $created_changed[0],
'updated' => $created_changed[1],
];
$data[] = $item;
}

$this->data = $data;
}

/**
* {@inheritdoc}
*/
public function buildLinks() {
// This method should be overridden for any endpoint.
$base_url = $this->request->getSchemeAndHttpHost() . $this->request->getPathInfo();
$tmp_query_params = $this->params;
$tmp_query_params['platform'] = $this->platform;
$tmp_query_params['limit'] = $this->limit;

if ($this->page == 0) {
$this->prev = "";
}
else {
$tmp_query_params['page'] = $this->page - 1;
$this->prev = $base_url . "?" . http_build_query($tmp_query_params);
}

if ($this->resultTotal > (($this->page + 1) * $this->limit)) {
$tmp_query_params['page'] = $this->page + 1;
$this->next = $base_url . "?" . http_build_query($tmp_query_params);
}
else {

$this->next = "";
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public function getApiCacheTime($id = NULL) {
* {@inheritdoc}
*/
public function getCacheId() {
$cid = "SOMETHING_UNIQUE";
// This should be a unique string, characters only.
$cid = "pirates";

if (!empty($this->params)) {
$cid .= ":" . implode(":", $this->params);
Expand Down Expand Up @@ -93,6 +94,7 @@ public function getResourceQueryResult() {
public function getResourceListQueryResult() {
// This method should be overridden for any endpoint.
$query = $this->entityTypeManager->getStorage('node')->getQuery();
$query->accessCheck(TRUE);
$query->condition('status', $this->privateParams['status']);
$query->condition('type', 'pirate');

Expand Down
Binary file removed modules/bc_api_logger/config/.DS_Store
Binary file not shown.
92 changes: 92 additions & 0 deletions src/CacheableJsonResponseTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace Drupal\bc_api_base;

use Drupal\Core\Cache\CacheableJsonResponse;
use Drupal\Core\Cache\CacheableMetadata;
use Symfony\Component\HttpFoundation\Response;

/**
* Trait CacheableJsonResponseTrait.
*
* This trait provides a way to create cacheable JSON responses. It allows for
* the addition of cacheable metadata and dependencies to the response, ensuring
* that the response can be cached appropriately.
*/
trait CacheableJsonResponseTrait {

/**
* Cacheable metadata for the response.
*
* @var \Drupal\Core\Cache\CacheableMetadata
*/
protected $cacheMetadata = NULL;

/**
* Returns the cacheable metadata for the response.
*
* When building any data, cacheable metadata should be set from there. And it
* will be applied when the request is altered.
*
* @return \Drupal\Core\Cache\CacheableMetadata
*/
protected function getCacheableMetadata(): CacheableMetadata {
if (!isset($this->cacheMetadata)) {
$this->cacheMetadata = new CacheableMetadata();
}
return $this->cacheMetadata;
}

/**
* Adds a dependency on an object: merges its cacheability metadata.
*
* For instance, when a response depends on some configuration, an entity, or
* an access result, we must make sure their cacheability metadata is present
* on the response. This method makes doing that simple.
*
* @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $dependency
* The dependency. If the object implements CacheableDependencyInterface,
* then its cacheability metadata will be used. Otherwise, the passed in
* object must be assumed to be uncacheable, so max-age 0 is set.
*
* @return $this
*/
public function addCacheableDependency($dependency) {

$this->cacheMetadata = $this->getCacheableMetadata()->merge(CacheableMetadata::createFromObject($dependency));

return $this;
}

/**
* {@inheritdoc}
*/
public function getResourceQueryResult() {
parent::getResourceQueryResult();

// If the resource is set, add it as a cacheable dependency.
if (isset($this->resource) && !empty($this->resource)) {
$this->addCacheableDependency($this->resource);
}
}

/**
* {@inheritdoc}
*
* Override the base classes response, to create a cacheable response.
*/
public function createResponse(): Response {
$response = new CacheableJsonResponse($this->return_data);

// Attach cache metadata if available.
if ($cache_metadata = $this->getCacheableMetadata()) {
$response->addCacheableDependency($cache_metadata);
}

// Alter it.
$this->responseAlter($response);

return $response;
}

}
22 changes: 16 additions & 6 deletions src/Controller/ApiControllerBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@
}

$this->platform = $platform;
$this->transformer->setPlatform($platform);

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.6)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.5)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.4)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.6)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.7)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.7)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.6)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.6)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.4)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.

Check failure on line 314 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.5)

Method Drupal\bc_api_base\Controller\ApiControllerBase::setPlatform() should return string but return statement is missing.
}

/**
Expand Down Expand Up @@ -341,9 +341,9 @@
public function autoParams() {

// @TODO: Why aren't these autoloaded???
new ApiDoc([]);

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.5)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.4)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.7)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.7)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.6)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.4)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 344 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.5)

Class Drupal\bc_api_base\Annotation\ApiDoc does not have a constructor and must be instantiated without any parameters.
new ApiBaseDoc([]);

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.5)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.4)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.7)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.7)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.6)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.4)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.

Check failure on line 345 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.5)

Class Drupal\bc_api_base\Annotation\ApiBaseDoc does not have a constructor and must be instantiated without any parameters.
new ApiParam([]);

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.5)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.3, 10.4)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.7)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.1.x, 8.3, 10.7)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (11.0.x, 8.3, 10.6)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.6)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.4)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

Check failure on line 346 in src/Controller/ApiControllerBase.php

View workflow job for this annotation

GitHub Actions / test (10.4.x, 8.2, 10.5)

Class Drupal\bc_api_base\Annotation\ApiParam does not have a constructor and must be instantiated without any parameters.

$reader = new SimpleAnnotationReader();
$reader->addNamespace('Drupal\bc_api_base\Annotation');
Expand Down Expand Up @@ -464,9 +464,8 @@
return [];
}

$response = new JsonResponse($this->return_data);
// Alter it.
$this->responseAlter($response);
// $response = new JsonResponse($this->return_data);
$response = $this->createResponse();

return $response;
}
Expand Down Expand Up @@ -533,9 +532,7 @@
return [];
}

$response = new JsonResponse($this->return_data);
// Alter it.
$this->responseAlter($response);
$response = $this->createResponse();

return $response;
}
Expand Down Expand Up @@ -589,6 +586,19 @@
$this->next = "";
}

/**
* {@inheritdoc}
*/
public function createResponse(): Response {
$response = new JsonResponse($this->return_data);
$response->setStatusCode($this->return_data['status']);

// Allow subclasses to alter it.
$this->responseAlter($response);

return $response;
}

/**
* {@inheritdoc}
*/
Expand Down
15 changes: 15 additions & 0 deletions src/Controller/ApiControllerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,23 @@ public function getResource(Request $request);
*/
public function getResourceList(Request $request);

/**
* Create the response object.
*
* We allow subclasses to override this method if they need to create
* different types of responses, however, they can also alter the response
* later, if they only need minor changes.
*
* @return Symfony\Component\HttpFoundation\Response
* The response object.
*/
public function createResponse(): Response;

/**
* Alter the response object before executing.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* The response object to alter.
*/
public function responseAlter(Response $response);

Expand Down
Loading
Loading