From ff331935d2c853ea6373a5b1379ebc9a7953a4c4 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Wed, 5 Dec 2012 15:35:23 -0500 Subject: [PATCH] API Sample now supports minimal GET, POST, PUT, and DELETE actions. --- samples/apisample/README.txt | 28 +++ .../apisample/data/ArticlesControler.inc.php | 115 ++++++++++++ samples/apisample/data/articles.json | 11 ++ .../handlers/ArticleCollectionHandler.inc.php | 82 ++++++++- .../handlers/ArticleItemHandler.inc.php | 174 +++++++++++++++++- 5 files changed, 404 insertions(+), 6 deletions(-) create mode 100644 samples/apisample/README.txt create mode 100644 samples/apisample/data/ArticlesControler.inc.php create mode 100644 samples/apisample/data/articles.json diff --git a/samples/apisample/README.txt b/samples/apisample/README.txt new file mode 100644 index 0000000..0e5d6f4 --- /dev/null +++ b/samples/apisample/README.txt @@ -0,0 +1,28 @@ +The apisample directory contains a mini API project that demonstrates all of the +main features of Well RESTEd. + +/articles/ + Represents a list of articles. + + GET + Displays a list of articles + POST + Add a new article + PUT + Not allowed + DELETE + Not allowed + +/articles/{id} +/articles/{slug} + Represents one specific article identified by the numberic ID {id} or by the + alpha-numeric slug. + + GET + Displays one specific article + POST + Not allowed + PUT + Replace the article with the given contents + DELETE + Remove the article diff --git a/samples/apisample/data/ArticlesControler.inc.php b/samples/apisample/data/ArticlesControler.inc.php new file mode 100644 index 0000000..b4ce53e --- /dev/null +++ b/samples/apisample/data/ArticlesControler.inc.php @@ -0,0 +1,115 @@ +path = dirname(__FILE__) . '/articles.json'; + $this->load(); + } + + public function load() { + + if (file_exists($this->path)) { + $data = file_get_contents($this->path); + $this->data = json_decode($data, true); + } + + } + + public function save() { + + if (is_writable($this->path)) { + $data = json_encode($this->data); + return file_put_contents($this->path, $data); + } + + return false; + + } + + public function getArticleById($id) { + + foreach ($this->data as $article) { + if ($article['articleId'] == $id) { + return $article; + } + } + return false; + + } + + public function getArticleBySlug($slug) { + + foreach ($this->data as $article) { + if ($article['slug'] == $slug) { + return $article; + } + } + return false; + + } + + public function addArticle($newArticle) { + + $validatedArticle = array( + 'articleId' => $this->getNewId(), + 'slug' => $newArticle['slug'], + 'title' => $newArticle['title'], + 'excerpt' => $newArticle['excerpt'] + ); + + $this->data[] = $validatedArticle; + + return $validatedArticle; + + } + + public function updateArticle($newArticle) { + + foreach ($this->data as &$oldArticle) { + + if ($oldArticle['articleId'] == $newArticle['articleId']) { + $oldArticle['slug'] = $newArticle['slug']; + $oldArticle['title'] = $newArticle['title']; + $oldArticle['excerpt'] = $newArticle['excerpt']; + return $newArticle; + } + + } + + return false; + + } + + public function removeArticle($id) { + + foreach ($this->data as $index => $article) { + if ($article['articleId'] == $id) { + unset($this->data[$index]); + return true; + } + } + + return false; + + } + + + protected function getNewId() { + + $maxId = 0; + + foreach ($this->data as $article) { + $maxId = max($maxId, $article['articleId']); + } + + return $maxId + 1; + + } + +} + +?> \ No newline at end of file diff --git a/samples/apisample/data/articles.json b/samples/apisample/data/articles.json new file mode 100644 index 0000000..174289e --- /dev/null +++ b/samples/apisample/data/articles.json @@ -0,0 +1,11 @@ +[{ + "articleId": 1, + "slug": "good-movie", + "title": "Reports Of Movie Being Good Reach Area Man", + "excerpt": "Local resident Daniel Paxson has reportedly heard dozens of accounts from numerous friendly sources in the past two weeks confirming that the new James Bond film is pretty good. According to persons with knowledge of the situation, an unnamed friend of Paxson’s coworker Wendy Mathers watched the movie on opening weekend and found it to be “decent enough.”" +}, { + "articleId": 2, + "slug": "species-protection", + "title": "Endangered Wildlife To Be Given New Identities In Species Protection Program", + "excerpt": "In an effort to protect at-risk animals from those who might wish to do them harm, the U.S. Fish and Wildlife Service announced Friday it had launched a program that provides endangered species with new names and habitats to ensure their anonymity." +}] \ No newline at end of file diff --git a/samples/apisample/handlers/ArticleCollectionHandler.inc.php b/samples/apisample/handlers/ArticleCollectionHandler.inc.php index 385e4ec..74a29d0 100644 --- a/samples/apisample/handlers/ArticleCollectionHandler.inc.php +++ b/samples/apisample/handlers/ArticleCollectionHandler.inc.php @@ -3,14 +3,90 @@ namespace handlers; require_once(dirname(__FILE__) . '/../../../Handler.inc.php'); +require_once(dirname(__FILE__) . '/../data/ArticlesControler.inc.php'); class ArticleCollectionHandler extends \wellrested\Handler { protected function get() { - $this->response->statusCode = 200; - $this->response->setHeader('Content-type', 'text/plain'); - $this->response->body = 'A list of articles.'; + // Display the list of articles. + $articles = new \ArticlesControler(); + + if (isset($articles->data)) { + + $this->response->statusCode = 200; + $this->response->setHeader('Content-type', 'application/json'); + $this->response->body = json_encode($articles->data); + + } else { + + $this->response->statusCode = 500; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to read the articles.'; + + } + + } + + protected function post() { + + // Read the request body, and ensure it is in the proper format. + $article = json_decode($this->request->body, true); + + // Ensure the JSON is well-formed. + if (!$article) { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to parse JSON from request body.'; + return; + } + + // Ensure requied fields are present. + if (!isset($article['slug']) || $article['slug'] === '') { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Request body missing slug.'; + return; + } + + if (!isset($article['title'])) { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Request body missing title.'; + return; + } + + if (!isset($article['excerpt'])) { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Request body missing excerpt.'; + return; + } + + // Ensure slug is not a duplicate. + $articles = new \ArticlesControler(); + if ($articles->getArticleBySlug($article['slug']) !== false) { + $this->response->statusCode = 409; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to store article. Slug "' . $article['slug'] . '" is already in use.'; + return; + } + + // All looks good! Add this to the articles and save! + $article = $articles->addArticle($article); + + if ($articles->save() === false) { + $this->response->statusCode = 500; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to write to file. Make sure permissions are set properly.'; + return; + } + + // Ok! + $this->response->statusCode = 201; + $this->response->setHeader('Content-type', 'application/json'); + $this->response->body = json_encode($article); + return; } diff --git a/samples/apisample/handlers/ArticleItemHandler.inc.php b/samples/apisample/handlers/ArticleItemHandler.inc.php index 59b0d95..2675743 100644 --- a/samples/apisample/handlers/ArticleItemHandler.inc.php +++ b/samples/apisample/handlers/ArticleItemHandler.inc.php @@ -3,15 +3,183 @@ namespace handlers; require_once(dirname(__FILE__) . '/../../../Handler.inc.php'); +require_once(dirname(__FILE__) . '/../data/ArticlesControler.inc.php'); class ArticleItemHandler extends \wellrested\Handler { protected function get() { + // Read the list of articles. + $articles = new \ArticlesControler(); + + $article = false; + + // Locate the article by ID or slug + if (isset($articles->data)) { + + if (isset($this->args['id'])) { + $article = $articles->getArticleById($this->args['id']); + } elseif (isset($this->args['slug'])) { + $article = $articles->getArticleBySlug($this->args['slug']); + } + + } + + if ($article !== false) { + + $this->response->statusCode = 200; + $this->response->setHeader('Content-type', 'application/json'); + $this->response->body = json_encode($article); + + } else { + + $this->response->statusCode = 404; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to locate the article.'; + + } + + } + + protected function put() { + + // Read the request body, and ensure it is in the proper format. + $article = json_decode($this->request->body, true); + + // Ensure the JSON is well-formed. + if (!$article) { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to parse JSON from request body.'; + return; + } + + // Ensure required fields are present. + if (!isset($article['slug']) || $article['slug'] === '') { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Request body missing slug.'; + return; + } + + if (!isset($article['title'])) { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Request body missing title.'; + return; + } + + if (!isset($article['excerpt'])) { + $this->response->statusCode = 400; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Request body missing excerpt.'; + return; + } + + // Read the list of articles. + $articles = new \ArticlesControler(); + + $oldArticle = false; + + // Locate the article by ID or slug + if (isset($articles->data)) { + + if (isset($this->args['id'])) { + $oldArticle = $articles->getArticleById($this->args['id']); + } elseif (isset($this->args['slug'])) { + $oldArticle = $articles->getArticleBySlug($this->args['slug']); + } + + } + + // Fail if the article identified by the URI does not exist. + if ($oldArticle === false) { + + $this->response->statusCode = 404; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to locate the article.'; + return; + + } + + // If the user located the resource by ID and has passed a slug, + // make sure the new slug is not already in use. + if (isset($this->args['id'])) { + + $slugArticle = $articles->getArticleBySlug($article['slug']); + + if ($slugArticle && $slugArticle['articleId'] != $article['articleId']) { + $this->response->statusCode = 409; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to store article. Slug "' . $article['slug'] . '" is already in use.'; + return; + } + + } + + // Update the article. + + // First, ensure the articleId is set. + // It must match the existing article found earlier. + $article['articleId'] = $oldArticle['articleId']; + + // Keep the results from the update for the response. + $article = $articles->updateArticle($article); + + if ($articles->save() === false) { + $this->response->statusCode = 500; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to write to file. Make sure permissions are set properly.'; + return; + } + + // Ok! $this->response->statusCode = 200; - $this->response->setHeader('Content-type', 'text/plain'); - $this->response->body = 'One article'; - $this->response->body = print_r($this->args, true); + $this->response->setHeader('Content-type', 'application/json'); + $this->response->body = json_encode($article); + return; + + } + + protected function delete() { + + // Read the list of articles. + $articles = new \ArticlesControler(); + + $article = false; + + // Locate the article by ID or slug + if (isset($articles->data)) { + + if (isset($this->args['id'])) { + $article = $articles->getArticleById($this->args['id']); + } elseif (isset($this->args['slug'])) { + $article = $articles->getArticleBySlug($this->args['slug']); + } + + } + + // Ensure the article exists. + if ($article === false) { + $this->response->statusCode = 404; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to locate the article.'; + return; + } + + // Remove the article and save. + $articles->removeArticle($article['articleId']); + + if ($articles->save() === false) { + $this->response->statusCode = 500; + $this->response->setHeader('Content-type', 'text/plain'); + $this->response->body = 'Unable to write to file. Make sure permissions are set properly.'; + return; + } + + // Ok! + $this->response->statusCode = 200; + return; }