@t2ee系列文章(1) - 一个简单的todo list的api服务器(1)

原文地址: blog.t2ee.org/2017/08/04/…

第一句话

这是一个多系列多章节的教程计划. 每一个系列完成一个小目标, 每个小目标分为多个章节实现

这是本系列的第一篇本章, 我们将会使用@t2ee的库来编写一个restful服务器, 实现todo list的CRUD功能.

本系列文章所用到的代码均可在 github.com/t2ee/tutori… 获取

准备工作

这个小项目将会用到@t2eetypescript来开发. 我们先来安装一些依赖

npm i typescript reflect-metadata @t2ee/core @t2ee/sl4js @t2ee/validation @t2ee/vdaer koa@2

对于typescript稍有了解的同学会知道每一个ts项目需要一个tsconfig.json, 如果你不是太了解如何配置, 我们将为你准备一个.

{
    "compilerOptions": {
        "module": "commonjs",
        "outDir": "./dist",
        "target": "ES6",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "declaration": true,
        "sourceMap": true
    },
    "compileOnSave": false,
    "include": [
        "src/**/*.ts"
    ]
}

我们所有的代码将在 src 目录下.

目标

本章节我们将会实现两个api, GET /todoGET /todo/:id, 第一个返回所有todo items, 第二个按id返回.

第一个控制器

首先, 引入所有我们需要用到的依赖

import {
    GET,
    Path,
    Response,
    PathParam,
} from '@t2ee/vader';
import {
    Component,
} from '@t2ee/core';

我们来准备一些基于内存的数据(避免用到数据库)

let LIST = [{
    id: 0,
    name: 'a',
}, {
    id: 1,
    name: 'b',
}];

现在开始写路由啦.

@Path('/todo')
@Component
export default class Controller {
    @GET
    @Path('/')
    async getList(): Promise<Response> {
        const response = new Response();
        response.body = LIST;
       return response;
    }
}

@GET@Path 使用定义路由的装饰器
所有路由的方法最后都会返回一个Response实体
@PathParam是一个装饰器用来获取路径中的参数
@Component用来把当前class下面用到的装饰器注入到依赖管理中.

现在, 第一个api已经写好了, 让我们来测试一下吧. 但是我们只有一个控制器, 我们还需要准备一个index.ts来启动服务器.

一切就绪后, 在控制台键入 tsc -p tsconfig.json && node dist, 服务器就会被编译然后运行了.

你应该能看到类似如下的输出

这表示我们的路由注册成功, 可以被访问到了. 打开浏览器, 键入http://localhost:8080/todo就看到输出啦!

第二个路由

我们还有一条路由没有实现, GET /todo/:id

@GET
@Path('/:id')
async getItem(@PathParam('id') id) {
    id = parseInt(id);
    const item = LIST.find(todo => todo.id === id);
    if (item) {
        const response = new Response();
        response.body = item;
        return response;    
    }
}

在这个路由中, 我们使用到了@PathParam来绑定/:id中的参数. 这样我们就可以通过 http://localhost:8080/todo/1 这样来访问.

或者如果你想通过query到传递id的话, 可以像下面这样写.

@GET
@Path('/')
async getList(@QueryParam('id') id): Promise<Response> {
    if (id) {
        id = parseInt(id);
        const item = LIST.find(todo => todo.id === id);
        if (item) {
            const response = new Response();
            response.body = item;
            return response;    
        }
    } else {
        const response = new Response();
        response.body = LIST;
        return response;
    }
}

这样, 我们完成了两个简单的GET api, 接下来两个章节, 我们会实现POST, PUT, DELETE的接口, 然后我们会加上参数检查, 实现自定义错误处理.

所有文件

index.ts

import 'reflect-metadata';
import * as path from 'path';
import * as Koa from 'koa';
import {
    ConfigurationStore,
} from '@t2ee/core';
ConfigurationStore.loadFile(path.resolve(__dirname, '../logger'));
import {
    Router,
} from '@t2ee/vader';
import Controller from './controller';
const router = Router.newInstance();
router.use(Controller);
const app = new Koa();
app.use(router.routes());
app.listen(8080);

controller.ts

import {
    GET,
    Path,
    Response,
    PathParam,
} from '@t2ee/vader';
import {
    Component,
} from '@t2ee/core';
let LIST = [{
    id: 0,
    name: 'a',
}, {
    id: 1,
    name: 'b',
}];
@Path('/todo')
@Component
export default class Controller {
    @GET
    @Path('/')
    async getList(@QueryParam('id') id): Promise<Response> {
        if (id) {
            id = parseInt(id);
            const item = LIST.find(todo => todo.id === id);
            if (item) {
                const response = new Response();
                response.body = item;
                return response;    
            }
        } else {
            const response = new Response();
            response.body = LIST;
            return response;
        }
    }
    @GET
    @Path('/:id')
    async getItem(@PathParam('id') id) {
        id = parseInt(id);
        const item = LIST.find(todo => todo.id === id);
        if (item) {
            const response = new Response();
            response.body = item;
            return response;    
        }
    }
}
关注下面的标签,发现更多相似文章
评论
说说你的看法