RESTã®é·æãšçæã«ã€ããŠã¯ãããªãã®æ°ã®èšäºããã§ã«æžãããŠããŸãïŒããã«ãããããžã®ã³ã¡ã³ãã§ïŒã ãŸãããã®ã¢ãŒããã¯ãã£ãé©çšãããµãŒãã¹ãéçºããå¿
èŠãçããå Žåãããã¥ã¡ã³ãã«ééããªãåºäŒãã§ãããã å®éãåã¡ãœãããäœæãããšããä»ã®ããã°ã©ããŒããããã®ã¡ãœãããåç
§ããããšã確ãã«ç解ããŠããŸãã ãããã£ãŠãããã¥ã¡ã³ãã¯å
æ¬çã§ãããæãéèŠãªã®ã¯é¢é£æ§ãããå¿
èŠããããŸãã
ç«ãžãããããããã§ç§ãã¡ã®ããŒã ã§ãã®åé¡ã解決ããæ¹æ³ã説æããŸãã
å°ãã®ã³ã³ããã¹ãã
ç§ãã¡ã®ããŒã ã¯ãçæé
ã§äžçšåºŠã®è€éãã®
Node.jsã§ããã¯ãšã³ã補åãçºè¡ããããšãä»»ãããŸããã ããã³ããšã³ãã®ããã°ã©ããŒãšã¢ãã©ã€ã¶ãŒã¯ããã®è£œåãšå¯Ÿè©±ããããšã«ãªã£ãŠããŸãã
å°ãèããŠã
TypeScriptã
YaPãšããŠäœ¿çšããããšã«ã
ãŸãã ã ãã調æŽããã
TSLintãš
Prettierã¯ãã³ãŒãã£ã³ã°/ã¢ã»ã³ããªæ®µéïŒããã³ã³ããã段éã§ã
ãã¹ã㌠ïŒã§åãã³ãŒãã¹ã¿ã€ã«ãšå³å¯ãªãã§ãã¯ãå®çŸããã®ã«åœ¹ç«ã¡ãŸããã 匷åãªã¿ã€ãã³ã°ã«ããããã¹ãŠã®ãªããžã§ã¯ãã®ã€ã³ã¿ãŒãã§ã€ã¹ãšã¿ã€ããæ確ã«èšè¿°ããããšãã§ããŸããã ãã®é¢æ°ãå
¥åãã©ã¡ãŒã¿ãŒãšããŠæ£ç¢ºã«äœããšãã®ããæçµçã«äœãè¿ãã®ãããªããžã§ã¯ãã®ã©ã®ããããã£ãå¿
é ã§ãããã©ã®ããããã£ãå¿
é ã§ã¯ãªãã®ããèªã¿ãããç解ã§ããããã«ãªããŸããã ã³ãŒãã¯Javaã«ããªã䌌ãŠããŸããïŒã ãããŠãã¡ããã
TypeDocã¯ãã¹ãŠã®æ©èœã«èªã¿ããããè¿œå ããŸããã
ããã¯ã³ãŒããã©ã®ããã«èŠããããã«ãªã£ããã§ãïŒ
export interface IResponseData<T> { nonce: number; code: number; message?: string; data?: T; } export class TransferObjectUtils { public static createResponseObject<T = object>(responseCode: number, message: string, data: T): IResponseData<T> { const result: IResponseData<T> = { code: responseCode || 200, nonce: Date.now() }; if (message) { result.message = message; } if (data) { result.data = data; } return result; } }
åå«ã«ã€ããŠèããŸãããã³ãŒããç¶æããããšã¯é£ãããããŸãããRESTãµãŒããŒã®ãŠãŒã¶ãŒã«ã€ããŠèããæã§ãã
ãã¹ãŠãéåžžã«è¿
éã«è¡ããããããã³ãŒããšããã¥ã¡ã³ããå¥ã
ã«èšè¿°ããã®ã¯éåžžã«é£ããããšãç解ããŸããã ç¹ã«ãããã³ããšã³ããŸãã¯mobilchikiã®èŠä»¶ã«åŸã£ãŠåçãŸãã¯èŠæ±ã«è¿œå ã®ãã©ã¡ãŒã¿ãŒãè¿œå ããä»ã®ãŠãŒã¶ãŒã«ããã«ã€ããŠèŠåããããšãå¿ããªãã§ãã ããã ããã¯ãæ確ãªèŠä»¶ãçŸããå Žæã§ãã
ããã¥ã¡ã³ãã®
ã³ãŒãã¯åžžã«åæããå¿
èŠããããŸã ã ã€ãŸãããã¥ãŒãã³ãã¡ã¯ã¿ãŒãé€å€ããããã¥ã¡ã³ããã³ãŒãã«åœ±é¿ãäžããã³ãŒããããã¥ã¡ã³ãã«åœ±é¿ãäžããå¿
èŠããããŸãã
ããã§ãããã«é©ããããŒã«ãæ¢ããŸããã 幞ããªããšã«ãNPMãªããžããªã¯ãããããçš®é¡ã®ã¢ã€ãã¢ãšãœãªã¥ãŒã·ã§ã³ã®åãªãå庫ã§ãã
ããŒã«ã®èŠä»¶ã¯æ¬¡ã®ãšããã§ãã
- ã³ãŒããšããã¥ã¡ã³ãã®åæã
- TypeScriptãµããŒãã
- çä¿¡/çºä¿¡ãã±ããã®æ€èšŒã
- ã©ã€ãããã³ãµããŒããããŠããããã±ãŒãžã
å€ãã®ç°ãªãããã±ãŒãžã䜿çšããŠRESTãµãŒãã¹ã§èšè¿°ããªããã°ãªããŸããã§ãããæã人æ°ã®ããããã±ãŒãžã¯ãtsoaãswagger-node-expressãexpress-openapiãswagger-codegenã§ãã
ãã ããTypeScriptããµããŒãããŠããªããã®ããã±ããæ€èšŒã䜿çšããŠãããã®ãããã¥ã¡ã³ãã«åºã¥ããŠã³ãŒããçæã§ãããã®ããããŸããããã以äžã®åæã¯æäŸãããŠããŸããã
ããã§ç§ã¯ãžã§ã€ãšã¹ã¯ãŒã¬ãŒã«åºäŒããŸããã èšè¿°ãããJoiã¹ããŒã ãSwaggerããã¥ã¡ã³ãã«å€æããããã«TypeScriptããµããŒãã§ããåªããããã±ãŒãžã åæãé€ããã¹ãŠã®ã¢ã€ãã ãå®è¡ãããŸãã ãã°ããæ¥ãã§ãKoaãã¬ãŒã ã¯ãŒã¯ãšäžç·ã«
joi-to-swaggerã䜿çšããŠããäžåœäººã®æŸæ£ããããªããžããªãèŠã€ããŸããã ç§ãã¡ã®ããŒã ã«ã¯Koaã«å¯ŸããåèŠã¯ãªããExpressãã¬ã³ãã«ç²ç®çã«è¿œåŸããçç±ããªãã£ãããããã®ã¹ã¿ãã¯ã§é¢éžããããšã決å®ããŸããã
ç§ã¯ãã®ãªããžããªããã©ãŒã¯ãããã°ãä¿®æ£ããããã€ãã®ããšãå®äºããŸããããããŠä»ãOpenSource Koa-Joi-Swagger-TSãžã®ç§ã®æåã®è²¢ç®ããªãªãŒã¹ãããŸããã ç§ãã¡ã¯ãã®ãããžã§ã¯ãã«åæ Œãããã®åŸããã§ã«ããã€ãã®ãããžã§ã¯ãããããŸããã RESTãµãŒãã¹ã®èšè¿°ãšä¿å®ãéåžžã«äŸ¿å©ã«ãªãããããã®ãµãŒãã¹ã®ãŠãŒã¶ãŒã¯Swaggerãªã³ã©ã€ã³ããã¥ã¡ã³ããžã®ãªã³ã¯ã®ã¿ãå¿
èŠãšããŸãã ãã®åŸããã®ããã±ãŒãžãéçºã§ããå Žæãæããã«ãªããããã«ããã€ãã®æ¹åãè¡ãããŸããã
Koa-Joi-Swagger-TSã䜿çšããŠãèªå·±ææžåRESTãµãŒããŒãäœæããæ¹æ³ãèŠãŠã¿ãŸãããã
å®æããã³ãŒããããã«æçš¿ããŸãã ã
ãã®ãããžã§ã¯ãã¯ãã¢ãªã®ã§ãããã€ãã®ãã¡ã€ã«ãåçŽåããŠ1ã€ã«ããŒãžããŸããã äžè¬ã«ãã€ã³ããã¯ã¹ãã¢ããªã±ãŒã·ã§ã³ãåæåããapp.tsãã¡ã€ã«ãåŒã³åºããšããªãœãŒã¹ãèªã¿åãããããŒã¿ããŒã¹ã«æ¥ç¶ããããã®åŒã³åºããªã©ãè¡ãããŸãã ãµãŒããŒã¯æåŸã®ã³ãã³ãã§éå§ããå¿
èŠããããŸãïŒä»¥äžã§èª¬æããå
容ã®ã¿ïŒã
ãããã£ãŠã
ãŸãæåã« ããã®ã³ã³ãã³ãã§
index.tsãäœæããŸãã
index.ts import * as Koa from "koa"; import { BaseContext } from "koa"; import * as bodyParser from "koa-bodyparser"; import * as Router from "koa-router"; const SERVER_PORT = 3002; (async () => { const app = new Koa(); const router = new Router(); app.use(bodyParser()); router.get("/", (ctx: BaseContext, next: Function) => { console.log("Root loaded!") }); app .use(router.routes()) .use(router.allowedMethods()); app.listen(SERVER_PORT); console.log(`Server listening on http://localhost:${SERVER_PORT} ...`); })();
ãã®ãµãŒãã¹ãéå§ãããšãRESTãµãŒããŒãçºçããŸããããããŸã§ã®ãšããã©ã®ããã«ãªã£ãŠããã®ãããããŸããã ãããžã§ã¯ãã®ã¢ãŒããã¯ãã£ã«ã€ããŠå°ã説æããŸãã JavaããNode.JSã«åãæ¿ãããããããã§åãã¬ã€ã€ãŒã䜿çšããŠãµãŒãã¹ãæ§ç¯ããããšããŸããã
- ã³ã³ãããŒã©ãŒ
- ãµãŒãã¹
- ãªããžããª
Koa-Joi-Swagger-TSã®æ¥ç¶ã
å§ããŸãããã åœç¶ã€ã³ã¹ããŒã«ããŸãã
npm install koa-joi-swagger-ts --save
ãcontrollersããã©ã«ããŒãšãã®äžã«
ãschemasããã©ã«ããŒãäœæããŸãã controllersãã©ã«ããŒã§ãæåã®ã³ã³ãããŒã©ãŒ
base.controller.tsãäœæããŸãã
base.controller.ts import { BaseContext } from "koa"; import { controller, description, get, response, summary, tag } from "koa-joi-swagger-ts"; import { ApiInfoResponseSchema } from "./schemas/apiInfo.response.schema"; @controller("/api/v1") export abstract class BaseController { @get("/") @response(200, { $ref: ApiInfoResponseSchema }) @tag("GET") @description("Returns text info about version of API") @summary("Show API index page") public async index(ctx: BaseContext, next: Function): Promise<void> { console.log("GET /api/v1/"); ctx.status = 200; ctx.body = { code: 200, data: { appVersion: "1.0.0", build: "1001", apiVersion: 1, reqHeaders: ctx.request.headers, apiDoc: "/api/v1/swagger.json" } } }; }
ãã³ã¬ãŒã¿ïŒJavaã®ã¢ãããŒã·ã§ã³ïŒãããããããã«ããã®ã¯ã©ã¹ã¯ãã¹ã/ api / v1ãã«é¢é£ä»ããããå
éšã®ãã¹ãŠã®ã¡ãœããã¯ãã®ãã¹ã«é¢é£ããŸãã
ãã®ã¡ãœããã«ã¯ããã¡ã€ã«ã./schemas/apiInfo.response.schemaãã«èšèŒãããŠããå¿ç圢åŒã®èª¬æããããŸãã
apiInfo.response.schema import * as Joi from "joi"; import { definition } from "koa-joi-swagger-ts"; import { BaseAPIResponseSchema } from "./baseAPI.response.schema"; @definition("ApiInfo", "Information data about current application and API version") export class ApiInfoResponseSchema extends BaseAPIResponseSchema { public data = Joi.object({ appVersion: Joi.string() .description("Current version of application") .required(), build: Joi.string().description("Current build version of application"), apiVersion: Joi.number() .positive() .description("Version of current REST api") .required(), reqHeaders: Joi.object().description("Request headers"), apiDoc: Joi.string() .description("URL path to swagger document") .required() }).required(); }
ãã®ãããªJoiã§ã®ã¹ããŒã ã®èšè¿°ã®å¯èœæ§ã¯éåžžã«åºç¯å²ã§ãããããã§ãã詳现ã«èšè¿°ãããŠããŸãïŒ
www.npmjs.com/package/joi-to-swaggerãããŠãããã«èšè¿°ãããã¯ã©ã¹ã®ç¥å
ããããŸãïŒå®éãããã¯ç§ãã¡ã®ãµãŒãã¹ã®ãã¹ãŠã®çãã®åºæ¬ã¯ã©ã¹ã§ãïŒïŒ
baseAPI.response.schema import * as Joi from "joi"; import { definition } from "koa-joi-swagger-ts"; @definition("BaseAPIResponse", "Base response entity with base fields") export class BaseAPIResponseSchema { public code = Joi.number() .required() .strict() .only(200, 400, 500) .example(200) .description("Code of operation result"); public message = Joi.string().description("message will be filled in some causes"); }
次ã«ããããã®åè·¯ãšã³ã³ãããŒã©ãŒãKoa-Joi-Swagger-TSã·ã¹ãã ã«ç»é²ããŸãã
index.tsã®æšªã«ãå¥ã®
routing.tsãã¡ã€ã«ãäœæããŸãã
routing.ts import { KJSRouter } from "koa-joi-swagger-ts"; import { BaseController } from "./controllers/base.controller"; import { BaseAPIResponseSchema } from "./controllers/schemas/baseAPI.response.schema"; import { ApiInfoResponseSchema } from "./controllers/schemas/apiInfo.response.schema"; const SERVER_PORT = 3002; export const loadRoutes = () => { const router = new KJSRouter({ swagger: "2.0", info: { version: "1.0.0", title: "simple-rest" }, host: `localhost:${SERVER_PORT}`, basePath: "/api/v1", schemes: ["http"], paths: {}, definitions: {} }); router.loadDefinition(ApiInfoResponseSchema); router.loadDefinition(BaseAPIResponseSchema); router.loadController(BaseController); router.setSwaggerFile("swagger.json"); router.loadSwaggerUI("/api/docs"); return router.getRouter(); };
ããã§ã¯ãKJSRouterã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸããããã¯ãæ¬è³ªçã«ã³ã¢ã«ãŒã¿ãŒã§ãããããã«ãŠã§ã¢ãšãââã³ãã©ãŒãè¿œå ãããŠããŸãã
ãããã£ãŠã
index.tsãã¡ã€ã«ã§
ã¯ãåã«å€æŽããŸã
const router = new Router();
ã«
const router = loadRoutes();
ããŠãäžèŠãªãã³ãã©ãŒãåé€ããŸãã
index.ts import * as Koa from "koa"; import * as bodyParser from "koa-bodyparser"; import { loadRoutes } from "./routing"; const SERVER_PORT = 3002; (async () => { const app = new Koa(); const router = loadRoutes(); app.use(bodyParser()); app .use(router.routes()) .use(router.allowedMethods()); app.listen(SERVER_PORT); console.log(`Server listening on http://localhost:${SERVER_PORT} ...`); })();
ãã®ãµãŒãã¹ãéå§ãããšã3ã€ã®ã«ãŒããå©çšå¯èœã«ãªããŸãã
1. / api / v1-ææžåãããã«ãŒã
ç§ã®å Žåãããã¯ç€ºãããŠããŸãïŒ
httpïŒ// localhostïŒ3002 / api / v1 { code: 200, data: { appVersion: "1.0.0", build: "1001", apiVersion: 1, reqHeaders: { host: "localhost:3002", connection: "keep-alive", cache-control: "max-age=0", upgrade-insecure-requests: "1", user-agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", accept-encoding: "gzip, deflate, br", accept-language: "uk-UA,uk;q=0.9,ru;q=0.8,en-US;q=0.7,en;q=0.6" }, apiDoc: "/api/v1/swagger.json" } }
ãããŠ2ã€ã®ãµãŒãã¹ã«ãŒãïŒ
2. /api/v1/swagger.jsonswagger.json { swagger: "2.0", info: { version: "1.0.0", title: "simple-rest" }, host: "localhost:3002", basePath: "/api/v1", schemes: [ "http" ], paths: { /: { get: { tags: [ "GET" ], summary: "Show API index page", description: "Returns text info about version of API", consumes: [ "application/json" ], produces: [ "application/json" ], responses: { 200: { description: "Information data about current application and API version", schema: { type: "object", $ref: "#/definitions/ApiInfo" } } }, security: [ ] } } }, definitions: { BaseAPIResponse: { type: "object", required: [ "code" ], properties: { code: { type: "number", format: "float", enum: [ 200, 400, 500 ], description: "Code of operation result", example: { value: 200 } }, message: { type: "string", description: "message will be filled in some causes" } } }, ApiInfo: { type: "object", required: [ "code", "data" ], properties: { code: { type: "number", format: "float", enum: [ 200, 400, 500 ], description: "Code of operation result", example: { value: 200 } }, message: { type: "string", description: "message will be filled in some causes" }, data: { type: "object", required: [ "appVersion", "apiVersion", "apiDoc" ], properties: { appVersion: { type: "string", description: "Current version of application" }, build: { type: "string", description: "Current build version of application" }, apiVersion: { type: "number", format: "float", minimum: 1, description: "Version of current REST api" }, reqHeaders: { type: "object", properties: { }, description: "Request headers" }, apiDoc: { type: "string", description: "URL path to swagger document" } } } } } } }
3. / api / docsããã¯Swagger UIãåããããŒãžã§ããããã¯Swaggerã¹ããŒã ãéåžžã«äŸ¿å©ã«èŠèŠçã«è¡šçŸãããã®ã§ãèŠãããã ãã§ãªãããµãŒããŒãããªã¯ãšã¹ããçæããŠå®éã®åçãååŸããããšãã§ããŸãã
ãã®UIã«ã¯swagger.jsonãã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ãå¿
èŠã§ããããã以åã®ã«ãŒããå«ãŸããŠããŸããã
ãŸãããã¹ãŠãããã«ããããã§ããã¹ãŠãæ©èœããŸãããïŒ..
æéãçµã€ã«ã€ããŠããã®ãããªå®è£
ã§ã¯ãããªãå€ãã®ã³ãŒãã®éè€ãããããšãäžžã§å²ã¿ãŸããã ã³ã³ãããŒã©ãŒãåãããšãããå¿
èŠãããå Žåã ãã®ãããåŸã§ããã±ãŒãžãå®æãããã³ã³ãããŒã©ãŒã®ãã©ãããŒããèšè¿°ããæ©èœãè¿œå ããŸããã
ãã®ãããªãµãŒãã¹ã®äŸãèããŠã¿ãŸãããã
ããã€ãã®ã¡ãœãããæã€ãUsersãã³ã³ãããŒã©ãŒããããšããŸãã
ãã¹ãŠã®ãŠãŒã¶ãŒãååŸãã @get("/") @response(200, { $ref: UsersResponseSchema }) @response(400, { $ref: BaseAPIResponseSchema }) @response(500, { $ref: BaseAPIResponseSchema }) @tag("User") @description("Returns list of all users") @summary("Get all users") public async getAllUsers(ctx: BaseContext): Promise<void> { console.log("GET /api/v1/users"); let message = "Get all users error"; let code = 400; let data = null; try { let serviceResult = await getAllUsers(); if (serviceResult) { data = serviceResult; code = 200; message = null; } } catch (e) { console.log("Error while getting users list"); code = 500; } ctx.status = code; ctx.body = TransferObjectUtils.createResponseObject(code, message, data); };
ãŠãŒã¶ãŒãæŽæ° @post("/") @parameter("body", { $ref: UsersRequestSchema }, ENUM_PARAM_IN.body) @response(200, { $ref: BaseAPIResponseSchema }) @response(400, { $ref: BaseAPIResponseSchema }) @response(500, { $ref: BaseAPIResponseSchema }) @tag("User") @description("Update user data") @summary("Update user data") public async updateUser(ctx: BaseContext): Promise<void> { console.log("POST /api/v1/users"); let message = "Update user data error"; let code = 400; let data = null; try { let serviceResult = await updateUser(ctx.request.body.data); if (serviceResult) { code = 200; message = null; } } catch (e) { console.log("Error while updating user"); code = 500; } ctx.status = code; ctx.body = TransferObjectUtils.createResponseObject(code, message, data); };
ãŠãŒã¶ãŒãæ¿å
¥ @put("/") @parameter("body", { $ref: UsersRequestSchema }, ENUM_PARAM_IN.body) @response(200, { $ref: BaseAPIResponseSchema }) @response(400, { $ref: BaseAPIResponseSchema }) @response(500, { $ref: BaseAPIResponseSchema }) @tag("User") @description("Insert new user") @summary("Insert new user") public async insertUser(ctx: BaseContext): Promise<void> { console.log("PUT /api/v1/users"); let message = "Insert new user error"; let code = 400; let data = null; try { let serviceResult = await insertUser(ctx.request.body.data); if (serviceResult) { code = 200; message = null; } } catch (e) { console.log("Error while inserting user"); code = 500; } ctx.status = code; ctx.body = TransferObjectUtils.createResponseObject(code, message, data); };
ã芧ã®ãšããã3ã€ã®ã³ã³ãããŒã©ãŒã¡ãœããã«ã¯éè€ããã³ãŒããå«ãŸããŠããŸãã ãã®ãããªå Žåã®ããã«ãç§ãã¡ã¯ä»ãã®æ©äŒãå©çšããŠããŸãã
æåã«ãäŸãã°
routing.tsãã¡ã€ã«ã«çŽæ¥ãã©ãããŒé¢æ°ãäœæããŸãã
const controllerDecorator = async (controller: Function, ctx: BaseContext, next: Function, summary: string): Promise<void> => { console.log(`${ctx.request.method} ${ctx.request.url}`); ctx.body = null; ctx.status = 400; ctx.statusMessage = `Error while executing '${summary}'`; try { await controller(ctx); } catch (e) { console.log(e, `Error while executing '${summary}'`); ctx.status = 500; } ctx.body = TransferObjectUtils.createResponseObject(ctx.status, ctx.statusMessage, ctx.body); };
次ã«ãã³ã³ãããŒã©ãŒã«æ¥ç¶ããŸãã
亀æ
router.loadController(UserController);
ã«
router.loadController(UserController, controllerDecorator);
ããŠãã³ã³ãããŒã©ãŒã®ã¡ãœãããåçŽåããŸããã
ãŠãŒã¶ãŒã³ã³ãããŒã©ãŒ @get("/") @response(200, { $ref: UsersResponseSchema }) @response(400, { $ref: BaseAPIResponseSchema }) @response(500, { $ref: BaseAPIResponseSchema }) @tag("User") @description("Returns list of all users") @summary("Get all users") public async getAllUsers(ctx: BaseContext): Promise<void> { let serviceResult = await getAllUsers(); if (serviceResult) { ctx.body = serviceResult; ctx.status = 200; ctx.statusMessage = null; } }; @post("/") @parameter("body", { $ref: UsersRequestSchema }, ENUM_PARAM_IN.body) @response(200, { $ref: BaseAPIResponseSchema }) @response(400, { $ref: BaseAPIResponseSchema }) @response(500, { $ref: BaseAPIResponseSchema }) @tag("User") @description("Update user data") @summary("Update user data") public async updateUser(ctx: BaseContext): Promise<void> { let serviceResult = await updateUser(ctx.request.body.data); if (serviceResult) { ctx.status = 200; ctx.statusMessage = null; } }; @put("/") @parameter("body", { $ref: UsersRequestSchema }, ENUM_PARAM_IN.body) @response(200, { $ref: BaseAPIResponseSchema }) @response(400, { $ref: BaseAPIResponseSchema }) @response(500, { $ref: BaseAPIResponseSchema }) @tag("User") @description("Insert new user") @summary("Insert new user") public async insertUser(ctx: BaseContext): Promise<void> { let serviceResult = await insertUser(ctx.request.body.data); if (serviceResult) { ctx.status = 200; ctx.statusMessage = null; } };
ãã®
controllerDecoratorã§ã¯ããã§ãã¯ã®ããžãã¯ãŸãã¯å
¥å/åºåã®è©³çŽ°ãªãã°ãè¿œå ã§ããŸãã
å®æããã³ãŒããããã«æçš¿ããŸãã ã
ããã§ãCRUDã®æºåãã»ãŒå®äºããŸããã åé€ã¯ãé¡æšã«ãã£ãŠæžãããšãã§ããŸãã å®éãæ°ããã³ã³ãããŒã©ãŒãäœæããã«ã¯ã次ã®æé ãå®è¡ããå¿
èŠããããŸãã
- ã³ã³ãããŒã©ãŒãã¡ã€ã«ãäœæãã
- routing.tsã«è¿œå ããŸã
- ã¡ãœããã説æãã
- åæ¹æ³ã§ãå
¥å/åºååè·¯ã䜿çšããŸã
- ãããã®ãã¿ãŒã³ã説æããŠãã ãã
- ãããã®ã¹ããŒã ãrouting.tsã«æ¥ç¶ããŸã
çä¿¡ãã±ãããã¹ããŒã ãšäžèŽããªãå ŽåãRESTãµãŒãã¹ã®ãŠãŒã¶ãŒã¯ãäœãæ£ç¢ºã«ééã£ãŠãããã®èª¬æãå«ã400ãšã©ãŒãåãåããŸãã çºä¿¡ãã±ãããç¡å¹ãªå Žåã500ãšã©ãŒãçæãããŸãã
ãŸããŸã ãŸã 楜ããããããªããšãšããŠã Swagger UIã§ã¯ãã©ã®ã¡ãœããã§ãã
è©ŠããŠã¿ã ãæ©èœã䜿çšã§ããŸãã å®è¡äžã®ãµãŒãã¹ã«å¯ŸããŠcurlãä»ããŠãªã¯ãšã¹ããçæãããŸãããã¡ãããçµæã¯ããã«ç¢ºèªã§ããŸãã ãããŠããã®ããã ãã«ãåè·¯ã«ãã©ã¡ãŒã¿ã
äŸ ããèšè¿°ããããšã¯éåžžã«äŸ¿å©ã§ãã ãªã¯ãšã¹ãã¯ã説æãããäŸã«åºã¥ããŠæ¢è£œã®ããã±ãŒãžã§ããã«çæãããããã§ãã
çµè«
æçµçã«ã¯éåžžã«äŸ¿å©ã§äŸ¿å©ã§ããã æåã¯ãçºä¿¡ãã±ãããæ€èšŒããããããŸããã§ãããããã®æ€èšŒã®å©ããåããŠã圌ãã¯ããã€ãã®é倧ãªãã°ãçºèŠããŸããã ãã¡ãããJoiã®ãã¹ãŠã®æ©èœãå®å
šã«äœ¿çšããããšã¯ã§ããŸããïŒjoi-to-swaggerã«ãã£ãŠå¶éãããŠããããïŒããããã§ãååã§ãã
çŸåšãããã¥ã¡ã³ãã¯åžžã«ãªã³ã©ã€ã³ã§ãããåžžã«ã³ãŒãã«å³å¯ã«å¯Ÿå¿ããŠããŸãããããäž»ãªãã®ã§ãã
ä»ã«ã©ããªã¢ã€ãã¢ããããŸããïŒ..
ãšã¯ã¹ãã¬ã¹ãµããŒããè¿œå ããããšã¯ã§ããŸããïŒ
èªãã ã°ããã§ãã
ãšã³ãã£ãã£ã1ãæã§äžåºŠèšè¿°ããã®ã¯æ¬åœã«ã¯ãŒã«ã§ãã åè·¯ãšã€ã³ã¿ãŒãã§ãŒã¹ã®äž¡æ¹ãç·šéããå¿
èŠãããããã§ãã
ãã¶ããããªãã¯ããã€ãã®èå³æ·±ãã¢ã€ãã¢ãæã£ãŠããã§ãããã ããè¯ããŸã ãã«ãªã¯ãšã¹ã:)
è²¢ç®è
ãžããããã