文档
Welcome! 安装(Installation) 示例列表(List of examples) 依赖注入与服务定位器(Dependency Injection/Service Location) MVC 架构(The MVC Architecture) 使用控制器(Using Controllers) 使用模型(Working with Models) 模型元数据(Models Meta-Data) 事务管理(Model Transactions) Phalcon 查询语言(Phalcon Query Language (PHQL)) 缓存对象关系映射(Caching in the ORM) 对象文档映射 ODM (Object-Document Mapper) 使用视图(Using Views) 视图助手(View Helpers) 资源文件管理(Assets Management) Volt 模版引擎(Volt: Template Engine) MVC 应用(MVC Applications) 路由(Routing) 调度控制器(Dispatching Controllers) 微应用(Micro Applications) 使用命名空间(Working with Namespaces) 事件管理器(Events Manager) 请求环境 (Request Environment) 返回响应(Returning Responses) Cookie 管理(Cookies Management) 生成 URL 和 路径(Generating URLs and Paths) 闪存消息(Flashing Messages) 使用 Session 存储数据(Storing data in Session) 过滤与清理(Filtering and Sanitizing) 上下文编码(Contextual Escaping) 验证(Validation) 表单(Forms) 读取配置(Reading Configurations) 分页(Pagination) 使用缓存提高性能(Improving Performance with Cache) 安全(Security) 加密/解密( Encryption/Decryption ) 访问控制列表 ACL(Access Control Lists ACL) 多语言支持(Multi-lingual Support) 通用类加载器 ( Universal Class Loader ) 日志记录(Logging) 注释解析器(Annotations Parser) 命令行应用(Command Line Applications) 队列(Queueing) 数据库抽象层(Database Abstraction Layer) 国际化(Internationalization) 数据库迁移(Database Migrations) 调试应用程序(Debugging Applications) Phalcon 开发工具(Phalcon Developer Tools) 提高性能:下一步该做什么?(Increasing Performance: What's next?) 单元测试(Unit testing) 授权(License)
教程

发布于 2015-08-21 15:11:48 | 543 次阅读 | 评论: 0 | 来源: 网络整理

教程 7:创建简单的 REST API(Tutorial 7: Creating a Simple REST API)

在这个教程中,我们会学习如何创建一个拥有 RESTful API 的应用程序,它将会使用如下的几个 HTTP 方法:

  • GET - 接受、查找数据
  • POST - 添加数据
  • PUT - 更新数据
  • DELETE - 删除数据

定义 API(Defining the API)

这个 API 包含如下方法(Methods)

Method URL Action
GET /api/robots Retrieves all robots
GET /api/robots/search/Astro Searches for robots with ‘Astro’ in their name
GET /api/robots/2 Retrieves robots based on primary key
POST /api/robots Adds a new robot
PUT /api/robots/2 Updates robots based on primary key
DELETE /api/robots/2 Deletes robots based on primary key

创建应用(Creating the Application)

As the application is so simple, we will not implement any full MVC environment to develop it. In this case, we will use a micro application to meet our goal.

The following file structure is more than enough:

my-rest-api/
    models/
        Robots.php
    index.php
    .htaccess

First, we need an .htaccess file that contains all the rules to rewrite the URIs to the index.php file, that is our application:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^((?s).*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

Then, in the index.php file we create the following:

<?php

use PhalconMvcMicro;

$app = new Micro();

// Define the routes here

$app->handle();

Now we will create the routes as we defined above:

<?php

use PhalconMvcMicro;

$app = new Micro();

// Retrieves all robots
$app->get('/api/robots', function () {

});

// Searches for robots with $name in their name
$app->get('/api/robots/search/{name}', function ($name) {

});

// Retrieves robots based on primary key
$app->get('/api/robots/{id:[0-9]+}', function ($id) {

});

// Adds a new robot
$app->post('/api/robots', function () {

});

// Updates robots based on primary key
$app->put('/api/robots/{id:[0-9]+}', function () {

});

// Deletes robots based on primary key
$app->delete('/api/robots/{id:[0-9]+}', function () {

});

$app->handle();

Each route is defined with a method with the same name as the HTTP method, as first parameter we pass a route pattern, followed by a handler. In this case, the handler is an anonymous function. The following route: ‘/api/robots/{id:[0-9]+}’, by example, explicitly sets that the “id” parameter must have a numeric format.

When a defined route matches the requested URI then the application executes the corresponding handler.

创建模型(Creating a Model)

Our API provides information about ‘robots’, these data are stored in a database. The following model allows us to access that table in an object-oriented way. We have implemented some business rules using built-in validators and simple validations. Doing this will give us the peace of mind that saved data meet the requirements of our application:

<?php

use PhalconMvcModel;
use PhalconMvcModelMessage;
use PhalconMvcModelValidatorUniqueness;
use PhalconMvcModelValidatorInclusionIn;

class Robots extends Model
{
    public function validation()
    {
        // Type must be: droid, mechanical or virtual
        $this->validate(
            new InclusionIn(
                array(
                    "field"  => "type",
                    "domain" => array(
                        "droid",
                        "mechanical",
                        "virtual"
                    )
                )
            )
        );

        // Robot name must be unique
        $this->validate(
            new Uniqueness(
                array(
                    "field"   => "name",
                    "message" => "The robot name must be unique"
                )
            )
        );

        // Year cannot be less than zero
        if ($this->year < 0) {
            $this->appendMessage(new Message("The year cannot be less than zero"));
        }

        // Check if any messages have been produced
        if ($this->validationHasFailed() == true) {
            return false;
        }
    }
}

Now, we must set up a connection to be used by this model and load it within our app:

<?php

use PhalconLoader;
use PhalconMvcMicro;
use PhalconDIFactoryDefault;
use PhalconDbAdapterPdoMysql as PdoMysql;

// Use Loader() to autoload our model
$loader = new Loader();

$loader->registerDirs(
    array(
        __DIR__ . '/models/'
    )
)->register();

$di = new FactoryDefault();

// Set up the database service
$di->set('db', function () {
    return new PdoMysql(
        array(
            "host"     => "localhost",
            "username" => "asimov",
            "password" => "zeroth",
            "dbname"   => "robotics"
        )
    );
});

// Create and bind the DI to the application
$app = new Micro($di);

检索数据(Retrieving Data)

The first “handler” that we will implement is which by method GET returns all available robots. Let’s use PHQL to perform this simple query returning the results as JSON:

<?php

// Retrieves all robots
$app->get('/api/robots', function () use ($app) {

    $phql = "SELECT * FROM Robots ORDER BY name";
    $robots = $app->modelsManager->executeQuery($phql);

    $data = array();
    foreach ($robots as $robot) {
        $data[] = array(
            'id'   => $robot->id,
            'name' => $robot->name
        );
    }

    echo json_encode($data);
});

PHQL, allow us to write queries using a high-level, object-oriented SQL dialect that internally translates to the right SQL statements depending on the database system we are using. The clause “use” in the anonymous function allows us to pass some variables from the global to local scope easily.

The searching by name handler would look like:

<?php

// Searches for robots with $name in their name
$app->get('/api/robots/search/{name}', function ($name) use ($app) {

    $phql = "SELECT * FROM Robots WHERE name LIKE :name: ORDER BY name";
    $robots = $app->modelsManager->executeQuery(
        $phql,
        array(
            'name' => '%' . $name . '%'
        )
    );

    $data = array();
    foreach ($robots as $robot) {
        $data[] = array(
            'id'   => $robot->id,
            'name' => $robot->name
        );
    }

    echo json_encode($data);
});

Searching by the field “id” it’s quite similar, in this case, we’re also notifying if the robot was found or not:

<?php

use PhalconHttpResponse;

// Retrieves robots based on primary key
$app->get('/api/robots/{id:[0-9]+}', function ($id) use ($app) {

    $phql = "SELECT * FROM Robots WHERE id = :id:";
    $robot = $app->modelsManager->executeQuery($phql, array(
        'id' => $id
    ))->getFirst();

    // Create a response
    $response = new Response();

    if ($robot == false) {
        $response->setJsonContent(
            array(
                'status' => 'NOT-FOUND'
            )
        );
    } else {
        $response->setJsonContent(
            array(
                'status' => 'FOUND',
                'data'   => array(
                    'id'   => $robot->id,
                    'name' => $robot->name
                )
            )
        );
    }

    return $response;
});

插入数据(Inserting Data)

Taking the data as a JSON string inserted in the body of the request, we also use PHQL for insertion:

<?php

use PhalconHttpResponse;

// Adds a new robot
$app->post('/api/robots', function () use ($app) {

    $robot = $app->request->getJsonRawBody();

    $phql = "INSERT INTO Robots (name, type, year) VALUES (:name:, :type:, :year:)";

    $status = $app->modelsManager->executeQuery($phql, array(
        'name' => $robot->name,
        'type' => $robot->type,
        'year' => $robot->year
    ));

    // Create a response
    $response = new Response();

    // Check if the insertion was successful
    if ($status->success() == true) {

        // Change the HTTP status
        $response->setStatusCode(201, "Created");

        $robot->id = $status->getModel()->id;

        $response->setJsonContent(
            array(
                'status' => 'OK',
                'data'   => $robot
            )
        );

    } else {

        // Change the HTTP status
        $response->setStatusCode(409, "Conflict");

        // Send errors to the client
        $errors = array();
        foreach ($status->getMessages() as $message) {
            $errors[] = $message->getMessage();
        }

        $response->setJsonContent(
            array(
                'status'   => 'ERROR',
                'messages' => $errors
            )
        );
    }

    return $response;
});

更新数据(Updating Data)

The data update is similar to insertion. The “id” passed as parameter indicates what robot must be updated:

<?php

use PhalconHttpResponse;

// Updates robots based on primary key
$app->put('/api/robots/{id:[0-9]+}', function ($id) use ($app) {

    $robot = $app->request->getJsonRawBody();

    $phql = "UPDATE Robots SET name = :name:, type = :type:, year = :year: WHERE id = :id:";
    $status = $app->modelsManager->executeQuery($phql, array(
        'id' => $id,
        'name' => $robot->name,
        'type' => $robot->type,
        'year' => $robot->year
    ));

    // Create a response
    $response = new Response();

    // Check if the insertion was successful
    if ($status->success() == true) {
        $response->setJsonContent(
            array(
                'status' => 'OK'
            )
        );
    } else {

        // Change the HTTP status
        $response->setStatusCode(409, "Conflict");

        $errors = array();
        foreach ($status->getMessages() as $message) {
            $errors[] = $message->getMessage();
        }

        $response->setJsonContent(
            array(
                'status'   => 'ERROR',
                'messages' => $errors
            )
        );
    }

    return $response;
});

删除数据(Deleting Data)

The data delete is similar to update. The “id” passed as parameter indicates what robot must be deleted:

<?php

use PhalconHttpResponse;

// Deletes robots based on primary key
$app->delete('/api/robots/{id:[0-9]+}', function ($id) use ($app) {

    $phql = "DELETE FROM Robots WHERE id = :id:";
    $status = $app->modelsManager->executeQuery($phql, array(
        'id' => $id
    ));

    // Create a response
    $response = new Response();

    if ($status->success() == true) {
        $response->setJsonContent(
            array(
                'status' => 'OK'
            )
        );
    } else {

        // Change the HTTP status
        $response->setStatusCode(409, "Conflict");

        $errors = array();
        foreach ($status->getMessages() as $message) {
            $errors[] = $message->getMessage();
        }

        $response->setJsonContent(
            array(
                'status'   => 'ERROR',
                'messages' => $errors
            )
        );
    }

    return $response;
});

测试应用(Testing our Application)

Using curl we’ll test every route in our application verifying its proper operation:

Obtain all the robots:

curl -i -X GET http://localhost/my-rest-api/api/robots

HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 07:05:13 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 117
Content-Type: text/html; charset=UTF-8

[{"id":"1","name":"Robotina"},{"id":"2","name":"Astro Boy"},{"id":"3","name":"Terminator"}]

Search a robot by its name:

curl -i -X GET http://localhost/my-rest-api/api/robots/search/Astro

HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 07:09:23 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 31
Content-Type: text/html; charset=UTF-8

[{"id":"2","name":"Astro Boy"}]

Obtain a robot by its id:

curl -i -X GET http://localhost/my-rest-api/api/robots/3

HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 07:12:18 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 56
Content-Type: text/html; charset=UTF-8

{"status":"FOUND","data":{"id":"3","name":"Terminator"}}

Insert a new robot:

curl -i -X POST -d '{"name":"C-3PO","type":"droid","year":1977}'
    http://localhost/my-rest-api/api/robots

HTTP/1.1 201 Created
Date: Tue, 21 Jul 2015 07:15:09 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 75
Content-Type: text/html; charset=UTF-8

{"status":"OK","data":{"name":"C-3PO","type":"droid","year":1977,"id":"4"}}

Try to insert a new robot with the name of an existing robot:

curl -i -X POST -d '{"name":"C-3PO","type":"droid","year":1977}'
    http://localhost/my-rest-api/api/robots

HTTP/1.1 409 Conflict
Date: Tue, 21 Jul 2015 07:18:28 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 63
Content-Type: text/html; charset=UTF-8

{"status":"ERROR","messages":["The robot name must be unique"]}

Or update a robot with an unknown type:

curl -i -X PUT -d '{"name":"ASIMO","type":"humanoid","year":2000}'
    http://localhost/my-rest-api/api/robots/4

HTTP/1.1 409 Conflict
Date: Tue, 21 Jul 2015 08:48:01 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 104
Content-Type: text/html; charset=UTF-8

{"status":"ERROR","messages":["Value of field 'type' must be part of
    list: droid, mechanical, virtual"]}

Finally, delete a robot:

curl -i -X DELETE http://localhost/my-rest-api/api/robots/4

HTTP/1.1 200 OK
Date: Tue, 21 Jul 2015 08:49:29 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 15
Content-Type: text/html; charset=UTF-8

{"status":"OK"}

结束语(Conclusion)

As we have seen, develop a RESTful API with Phalcon is easy. Later in the documentation we’ll explain in detail how to use micro applications and the PHQL language.

最新网友评论  共有(0)条评论 发布评论 返回顶部

Copyright © 2007-2017 PHPERZ.COM All Rights Reserved   冀ICP备14009818号  版权声明  广告服务