UNPKG

5.8 kBJavaScriptView Raw
1/**
2 * apeman app to handle restful endpoint.
3 * @function apemanAppRest
4 * @param {object} models - Model objects.
5 * @param {object} [options] - Optional settings.
6 * @param {function} [options.pathname='/'+apemanmodel.toType(model)] - Spec path name.
7 * @param {Endpoint|boolean} [options.knock]
8 * @param {Endpoint|boolean} [options.spec]
9 * @param {Endpoint|boolean} [options.list]
10 * @param {Endpoint|boolean} [options.create]
11 * @param {Endpoint|boolean} [options.bulkUpdate]
12 * @param {Endpoint|boolean} [options.bulkDestroy]
13 * @param {Endpoint|boolean} [options.one]
14 * @param {Endpoint|boolean} [options.update]
15 * @param {Endpoint|boolean} [options.destroy]
16 * @param {Endpoint|boolean} [options.relatedList]
17 * @param {Endpoint|boolean} [options.relatedCreate]
18 * @param {Endpoint|boolean} [options.relatedUpdateBulk]
19 * @param {Endpoint|boolean} [options.relatedDestroyBulk]
20 * @param {Endpoint|boolean} [options.relatedOne]
21 * @param {Endpoint|boolean} [options.relatedUpdate]
22 * @param {Endpoint|boolean} [options.relatedDestroy]
23 * @param {Endpoint|boolean} [options.relationList]
24 * @param {Endpoint|boolean} [options.relationCreate]
25 * @param {Endpoint|boolean} [options.relationUpdate]
26 * @param {Endpoint|boolean} [options.relationDestroy]
27 * @returns {function} - Defined app function.
28 */
29
30/**
31 * @typedef {Object} Endpoint
32 * @property {function} handle - Handler function
33 * @property {Object} schema - Validation schema
34 */
35
36'use strict'
37
38const route = require('apeman-app-route')
39const restSpec = require('./specifying/rest_spec')
40const assert = require('assert')
41const co = require('co')
42
43const apemanmodel = require('apemanmodel')
44const restRoute = require('./routing/rest_route')
45
46const {
47 CreateEndpoint,
48 DestroyEndpoint,
49 Endpoint,
50 ListEndpoint,
51 OneEndpoint,
52 RelatedCreateEndpoint,
53 RelatedDestroyEndpoint,
54 RelatedListEndpoint,
55 RelatedOneEndpoint,
56 RelatedUpdateEndpoint,
57 RelationCreateEndpoint,
58 RelationDestroyEndpoint,
59 RelationListEndpoint,
60 RelationUpdateEndpoint,
61 UpdateEndpoint,
62 SpecEndpoint
63} = require('./endpoints')
64
65const {
66 BulkCreateEndpoint,
67 BulkDestroyEndpoint,
68 BulkRelatedCreateEndpoint,
69 BulkRelatedDestroyEndpoint,
70 BulkRelatedUpdateEndpoint,
71 BulkRelationCreateEndpoint,
72 BulkRelationDestroyEndpoint,
73 BulkUpdateEndpoint
74} = require('./endpoints/bulk')
75
76const debug = require('debug')('apeman:app:rest')
77
78/** @lends create */
79function create (model, options = {}) {
80 assert.ok(model, 'model is required.')
81 debug(`Register rest for model: ${model}`)
82
83 let type = apemanmodel.toType(model)
84
85 let pathname = String(options.pathname || `/${type}`).replace(/\/$/, '')
86
87 let { associations } = model
88 let {
89 knock,
90 spec,
91 list,
92 create,
93 bulkUpdate,
94 bulkDestroy,
95 one,
96 update,
97 destroy,
98 relatedList,
99 relatedCreate,
100 relatedUpdateBulk,
101 relatedDestroyBulk,
102 relatedOne,
103 relatedUpdate,
104 relatedDestroy,
105 relationList,
106 relationCreate,
107 relationUpdate,
108 relationDestroy
109 } = options
110
111 let rest = restRoute.bind(restRoute, model)
112
113 let routes = {
114 [`${pathname || '/'}`]: {
115 'HEAD': rest('knock', knock, true),
116 'OPTIONS': rest('spec', spec, new SpecEndpoint({pathname})),
117 'GET': rest('list', list, new ListEndpoint({}), {}),
118 'POST': rest('create', create, new CreateEndpoint({})),
119 'PATCH': rest('bulkUpdate', bulkUpdate, new BulkUpdateEndpoint({})),
120 'DELETE': rest('bulkDestroy', bulkDestroy, new BulkDestroyEndpoint({}))
121 },
122 [`${pathname}/:id`]: {
123 'GET': rest('one', one, new OneEndpoint({})),
124 'PATCH': rest('update', update, new UpdateEndpoint({})),
125 'DELETE': rest('destroy', destroy, new DestroyEndpoint({}))
126 }
127 }
128
129 for (let name of Object.keys(associations || {})) {
130 let association = associations[ name ]
131
132 let associate = co.wrap(function * associate (ctx, next) {
133 ctx.state.association = association
134 yield next()
135 })
136
137 routes[ `${pathname}/:id/${name}` ] = {
138 'GET': [
139 associate,
140 ...rest('relatedList', relatedList, new RelatedListEndpoint({}))
141 ],
142 'POST': [
143 associate,
144 ...rest('relatedCreate', relatedCreate, new RelatedCreateEndpoint({}))
145 ],
146 'PATCH': [
147 associate,
148 ...rest('relatedUpdateBulk', relatedUpdateBulk, new BulkRelatedUpdateEndpoint({})),
149 ],
150 'DELETE': [
151 associate,
152 ...rest('relatedDestroyBulk', relatedDestroyBulk, new BulkRelatedDestroyEndpoint({}))
153 ]
154 }
155
156 routes[ `${pathname}/:id/${name}/:related_id` ] = {
157 'GET': [
158 associate,
159 ...rest('relatedOne', relatedOne, new RelatedOneEndpoint({}))
160 ],
161 'PATCH': [
162 associate,
163 ...rest('relatedUpdate', relatedUpdate, new RelatedUpdateEndpoint({}))
164 ],
165 'DELETE': [
166 associate,
167 ...rest('relatedDestroy', relatedDestroy, new RelatedDestroyEndpoint({}))
168 ]
169 }
170
171 routes[ `${pathname}/:id/relationships/${name}` ] = {
172 'GET': [
173 associate,
174 ...rest('relationList', relationList, new RelationListEndpoint({}))
175 ],
176 'POST': [
177 associate,
178 ...rest('relationCreate', relationCreate, new RelationCreateEndpoint({}))
179 ],
180 'PATCH': [
181 associate,
182 ...rest('relationUpdate', relationUpdate, new RelationUpdateEndpoint({}))
183 ],
184 'DELETE': [
185 associate,
186 ...rest('relationDestroy', relationDestroy, new RelationDestroyEndpoint({}))
187 ]
188 }
189 }
190
191 let app = route(routes)
192
193 Object.assign(app, {
194 /**
195 * Application description.
196 */
197 $desc: 'Restful endpoint.',
198 /**
199 * Endpoint specification.
200 */
201 $spec: restSpec(model, { pathname })
202
203 })
204 return app
205}
206
207module.exports = create