在Web开发,Api开发是一项非常重要的技术,这里就以Laravel项目实例来开发API 熟悉下API的具体的流程

介绍

关于API的开发 不得不提的就是可以利用Dingo来构建更加强大的API 这样我们可以更好的去实现API认证和请求

本文基于laravist的Api教程 作为笔记参考

安装

首先当然是去安装页面 根据提供的包进行下载 在laravel项目中就是require这个package

"dingo/api": "1.0.*@dev"

接着在laravel项目的configapp.php去添加服务

'providers' => [
    Dingo\Api\Provider\LaravelServiceProvider::class
]

再去生成相应的配置文件

$ php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"

如果需要实现jwt 同样的也是去安装页面 安装这个package

"require": {
    "tymon/jwt-auth": "0.5.*"
}

添加对应的服务:

'Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class'

当然也是需要去配置一下他的alias

'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class

生成配置文件

$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

生成一个key

$ php artisan jwt:generate

使用

1.这个时候我们是在开发的环境下 还需对Dingo进行相应的配置 在.env文件里

API_STANDARDS_TREE=vnd

添加前缀

API_PREFIX=api

填写版本 这个我们之前自己写测试的时候也是提供的v1以此来区别版本

API_VERSION=v1

开启Debug模式

API_DEBUG=true

一开始可以去实现一个jwtauth认证 在config/api.php里配置

'auth' => [
    'basic'=>function($app){
        return new  Dingo\Api\Auth\Provider\Basic($app['auth']);
    },
    'jwt'=>function($app){
        return new  Dingo\Api\Auth\Provider\JWT($app['Tymon\JWTAuth\JWTAuth']);
    }
],

这样我们即实现了在Dingojwt认证

2.既然是auth认证我们就需要先注册刚配置好的认证 即在Kernel文件里添加

'jwt.auth'=> \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
'jwt.refresh'=>\Tymon\JWTAuth\Middleware\RefreshToken::class,

3.添加api路由
laravel 5.2以后的版本我们可以直接放在routes/api.php

$api = app('Dingo\Api\Routing\Router');

为了区分开来 我们可以在app目录下新建Api目录然后在新建Controllers和在Https目录一样 在这里用来管理api的控制器

在这个目录下新建一个基本的控制器BaseController

<?php
namespace App\Api\Controllers;
use App\Http\Controllers\Controller;
use Dingo\Api\Routing\Helpers;
class BaseController extends Controller
{
    use Helpers;
}

所以这个时候我们再去创建对数据表的api时就可以继承这个表而使用Dingo ApiHelpers 比如在此目录下创建PostsController

这样我们就可以在routes里根据Dingo提供的方法去定义想要的api

$api = app('Dingo\Api\Routing\Router');

$api->version('v1', function ($api) {
    $api->group(['namespace' => 'App\Api\Controllers'], function ($api) {
        $api->get('lessons','PostsController@index');
        $api->get('lessons/{id}','PostsController@show');
    });
});

PostsControllerindex返回所有数据 那么再去访问http://localhost:8000/api/lessons
就可以看到所有的数据了

在这里路由的定义就是这样 这于我们之前自己写的路由方式还是不太一样的 因为这是Dingo为我们封装好的路由

当然和之前的一样 我们需要对数据字段进行映射 那么我们可以在Api目录下新建Transformer目录 然后在这个目录下新建PostTransformer

<?php
namespace App\Api\Transformer;
use App\Post;
use League\Fractal\TransformerAbstract;
class PostTransformer extends TransformerAbstract
{
    public function transform(Post $post)
    {
        return [
            'title' => $post['title'],
            'content' => $post['body'],
            'is_free' => (boolean)$ppost['free']
        ];
    }
}

在这里我们是可以使用Dingo APITransformerTransformerAbstract

这样写完我们就可以在控制器里去重新返回所有信息

 public function index()
{
    $lessons =  Post::all();

    return $this->collection($post,new PostTransformer());
}

这里的PostTransformerApp\Api\Transformer\PostTransformer

当然还有之前的show方法 因为他的返回状态信息之前都是自己写的 其实在Dingo里也有相应的方法

public function show($id)
{
    $lesson = Lesson::find($id);
    if(! $lesson){
        return $this->response->errorNotFound('Lesson not found');
    }
    return $this->item($lesson,new LessonTransformer());
}

结合Jwt的auth认证

App\Api\Controllers目录下新建AuthController并继承之前定义好的BaseController

jwt创建token的页面 我们就可以使用它的authenticate方法

public function authenticate(Request $request)
{
    // grab credentials from the request
    $credentials = $request->only('email','password');
    try {
        // attempt to verify the credentials and create a token for the user
        if (! $token = JWTAuth::attempt($credentials)) {
            return response()->json(['error' => 'invalid_credentials'], 401);
        }
    } catch (JWTException $e) {
        // something went wrong whilst attempting to encode the token
        return response()->json(['error' => 'could_not_create_token'], 500);
    }
    // all good so return the token
    return response()->json(compact('token'));
}

为了执行这个方法 可以去路由中定义

$api->version('v1', function ($api) {
    $api->group(['namespace' => 'App\Api\Controllers'], function ($api) {
        $api->post('user/login','AuthController@authenticate');
        $api->post('user/register','AuthController@register');
    });
});

这个时候再去查看一下我们的路由的话就会看到新定义的post路由

为了验证请求的结果 我们可以使用postman这个chrome工具 去请求http://localhost:8000/api/user/login

这个时候是会返回{"error":"invalid_credentials"}

为了能够正确通过我们可以在body部分给出用户邮箱和密码(用户可用thinker创建一个) 这个时候就会正确返回一个token

这个token就是用来保护有jwt认证下的信息 我们可以为Post的数据添加一个middleware

$api->group(['middleware'=>'jwt.auth'],function ($api){
    $api->get('posts',PostsController@index');
    $api->get('posts/{id}','PostsController@show');
});

所以这个时候如果我们没有之前authenticate返回的token的话 我们是无法访问api/postsapi/post/{id}

只有加上返回的token我们才能继续访问到之前的数据信息 如/api/posts?token=xxxxxx

既然只有登录的用户才能访问到这些资源 那么我们是不是也可以去拿到登录的用户

jwtAuthentication里就提供了getAuthenticatedUser这个方法 所以为了查看效果 可以去注册一条路由

$api->group(['middleware'=>'jwt.auth'],function ($api){
    $api->get('user/me','AuthController@getAuthenticatedUser');
});

接着在AuthController里去定义这个方法

public function getAuthenticatedUser()
{
    try {
        if (! $user = JWTAuth::parseToken()->authenticate()) {
            return response()->json(['user_not_found'], 404);
        }
    } catch (TokenExpiredException $e) {
        return response()->json(['token_expired'], $e->getStatusCode());
    } catch (TokenInvalidException $e) {
        return response()->json(['token_invalid'], $e->getStatusCode());
    } catch (JWTException $e) {
        return response()->json(['token_absent'], $e->getStatusCode());
    }
    // the token is valid and we have found the user via the sub claim
    return response()->json(compact('user'));
}

所以说这时候去访问http://localhost:8000/api/user/me?token=xxx就可以拿到当前登录的用户信息了

相关链接