Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit ada6367

Browse files
author
Je
committed
breaking: rewrite api of APIs
1 parent ee1bcc5 commit ada6367

File tree

6 files changed

+113
-77
lines changed

6 files changed

+113
-77
lines changed

api.ts

Lines changed: 77 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,74 @@
11
import { gzipEncode } from 'https://deno.land/x/[email protected]/mod.ts'
22
import log from './log.ts'
33
import type { ServerRequest } from './std.ts'
4-
import type { APIRequest, APIRequestURL, APIResponse, RouterURL } from './types.ts'
4+
import type { APIRequest, APIRequestURL, Response } from './types.ts'
55

6-
export class AlephAPIRequest implements APIRequest {
6+
export class Request implements APIRequest {
77
#req: ServerRequest
88
#url: APIRequestURL
9-
#cookies: ReadonlyMap<string, string>
9+
#cookies: ReadonlyMap<string, string> = new Map()
10+
#resp = {
11+
status: 200,
12+
headers: new Headers({
13+
'Status': '200',
14+
'Server': 'Aleph.js',
15+
}),
16+
done: false
17+
}
1018

11-
constructor(req: ServerRequest, url: RouterURL) {
12-
const paramsMap = new Map<string, string>()
13-
for (const key in url.params) {
14-
paramsMap.set(key, url.params[key])
15-
}
19+
constructor(req: ServerRequest, url: APIRequestURL) {
1620
this.#req = req
17-
this.#url = {
18-
proto: this.#req.proto,
19-
protoMinor: this.#req.protoMinor,
20-
protoMajor: this.#req.protoMajor,
21-
pathname: url.pathname,
22-
params: paramsMap,
23-
query: url.query,
24-
}
25-
this.#cookies = new Map() // todo: parse cookies
21+
this.#url = url
2622
}
2723

2824
get method(): string {
2925
return this.#req.method
3026
}
3127

28+
get proto() {
29+
return this.#req.proto
30+
}
31+
32+
get protoMinor() {
33+
return this.#req.protoMinor
34+
}
35+
36+
get protoMajor() {
37+
return this.#req.protoMajor
38+
}
39+
40+
get conn() {
41+
return this.#req.conn
42+
}
43+
44+
get r() {
45+
return this.#req.r
46+
}
47+
48+
get w() {
49+
return this.#req.w
50+
}
51+
52+
get done() {
53+
return this.#req.done
54+
}
55+
56+
get contentLength() {
57+
return this.#req.contentLength
58+
}
59+
60+
get body() {
61+
return this.#req.body
62+
}
63+
64+
async respond(r: Response) {
65+
return this.#req.respond(r)
66+
}
67+
68+
async finalize() {
69+
return this.#req.finalize()
70+
}
71+
3272
get url(): APIRequestURL {
3373
return this.#url
3474
}
@@ -40,51 +80,34 @@ export class AlephAPIRequest implements APIRequest {
4080
get cookies(): ReadonlyMap<string, string> {
4181
return this.#cookies
4282
}
43-
}
44-
45-
export class AlephAPIResponse implements APIResponse {
46-
#req: ServerRequest
47-
#status: number
48-
#headers: Headers
49-
#sent: boolean
50-
51-
constructor(req: ServerRequest) {
52-
this.#req = req
53-
this.#status = 200
54-
this.#headers = new Headers({
55-
'Status': '200',
56-
'Server': 'Aleph.js',
57-
})
58-
this.#sent = false
59-
}
6083

6184
status(code: number): this {
62-
this.#headers.set('status', code.toString())
63-
this.#status = code
85+
this.#resp.headers.set('status', code.toString())
86+
this.#resp.status = code
6487
return this
6588
}
6689

6790
addHeader(key: string, value: string): this {
68-
this.#headers.append(key, value)
91+
this.#resp.headers.append(key, value)
6992
return this
7093
}
7194

7295
setHeader(key: string, value: string): this {
73-
this.#headers.set(key, value)
96+
this.#resp.headers.set(key, value)
7497
return this
7598
}
7699

77100
removeHeader(key: string): this {
78-
this.#headers.delete(key)
101+
this.#resp.headers.delete(key)
79102
return this
80103
}
81104

82-
async json(data: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number) {
105+
json(data: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number) {
83106
return this.send(JSON.stringify(data, replacer, space), 'application/json')
84107
}
85108

86109
async send(data: string | Uint8Array | ArrayBuffer, contentType?: string) {
87-
if (this.#sent) {
110+
if (this.#resp.done) {
88111
log.warn('ServerRequest: repeat respond calls')
89112
return
90113
}
@@ -99,9 +122,9 @@ export class AlephAPIResponse implements APIResponse {
99122
return
100123
}
101124
if (contentType) {
102-
this.#headers.set('Content-Type', contentType)
103-
} else if (this.#headers.has('Content-Type')) {
104-
contentType = this.#headers.get('Content-Type')!
125+
this.#resp.headers.set('Content-Type', contentType)
126+
} else if (this.#resp.headers.has('Content-Type')) {
127+
contentType = this.#resp.headers.get('Content-Type')!
105128
}
106129
let isText = false
107130
if (contentType) {
@@ -114,29 +137,29 @@ export class AlephAPIResponse implements APIResponse {
114137
}
115138
}
116139
if (isText && body.length > 1024 && this.#req.headers.get('accept-encoding')?.includes('gzip')) {
117-
this.#headers.set('Vary', 'Origin')
118-
this.#headers.set('Content-Encoding', 'gzip')
140+
this.#resp.headers.set('Vary', 'Origin')
141+
this.#resp.headers.set('Content-Encoding', 'gzip')
119142
body = gzipEncode(body)
120143
}
121-
this.#headers.set('Date', (new Date).toUTCString())
122-
this.#sent = true
144+
this.#resp.headers.set('Date', (new Date).toUTCString())
145+
this.#resp.done = true
123146
return this.#req.respond({
124-
status: this.#status,
125-
headers: this.#headers,
147+
status: this.#resp.status,
148+
headers: this.#resp.headers,
126149
body
127150
}).catch(err => log.warn('ServerRequest.respond:', err.message))
128151
}
129152

130153
async end(status: number) {
131-
if (this.#sent) {
154+
if (this.#resp.done) {
132155
log.warn('ServerRequest: repeat respond calls')
133156
return
134157
}
135-
this.#headers.set('Date', (new Date).toUTCString())
136-
this.#sent = true
158+
this.#resp.headers.set('Date', (new Date).toUTCString())
159+
this.#resp.done = true
137160
return this.#req.respond({
138161
status,
139-
headers: this.#headers,
162+
headers: this.#resp.headers,
140163
}).catch(err => log.warn('ServerRequest.respond:', err.message))
141164
}
142165
}

context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const RouterContext = createContext<RouterURL>({
55
locale: 'en',
66
pagePath: '/',
77
pathname: '/',
8-
params: {},
8+
params: new Map(),
99
query: new URLSearchParams(),
1010
})
1111
RouterContext.displayName = 'RouterContext'

project.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import marked from 'https://esm.sh/[email protected]'
22
import { minify } from 'https://esm.sh/[email protected]'
33
import { safeLoadFront } from 'https://esm.sh/[email protected]'
4-
import { AlephAPIRequest, AlephAPIResponse } from './api.ts'
4+
import { Request } from './api.ts'
55
import { EventEmitter } from './events.ts'
66
import { createHtml } from './html.ts'
77
import log from './log.ts'
88
import { getPagePath, RouteModule, Routing } from './routing.ts'
99
import { colors, ensureDir, path, ServerRequest, Sha1, walk } from './std.ts'
1010
import { compile } from './tsc/compile.ts'
11-
import type { AlephRuntime, APIHandle, Config, RouterURL } from './types.ts'
11+
import type { AlephRuntime, APIHandler, Config, RouterURL } from './types.ts'
1212
import util, { existsDirSync, existsFileSync, hashShort, MB, reHashJs, reHttp, reLocaleID, reMDExt, reModuleExt, reStyleModuleExt } from './util.ts'
1313
import { cleanCSS, Document, less } from './vendor/mod.ts'
1414
import { version } from './version.ts'
@@ -175,18 +175,15 @@ export class Project {
175175
}
176176
}
177177

178-
async callAPI(req: ServerRequest, loc: { pathname: string, search?: string }): Promise<APIHandle | null> {
178+
async callAPI(req: ServerRequest, loc: { pathname: string, search?: string }): Promise<APIHandler | null> {
179179
const [url] = this.#apiRouting.createRouter(loc)
180180
if (url.pagePath != '') {
181181
const moduleID = url.pagePath + '.js'
182182
if (this.#modules.has(moduleID)) {
183183
try {
184184
const { default: handle } = await import('file://' + this.#modules.get(moduleID)!.jsFile)
185185
if (util.isFunction(handle)) {
186-
await handle(
187-
new AlephAPIRequest(req, url),
188-
new AlephAPIResponse(req)
189-
)
186+
await handle(new Request(req, url))
190187
} else {
191188
req.respond({
192189
status: 500,
@@ -1275,7 +1272,7 @@ export class Project {
12751272
return ret
12761273
}
12771274

1278-
private async _render404Page(url: RouterURL = { locale: this.config.defaultLocale, pagePath: '', pathname: '/', params: {}, query: new URLSearchParams() }) {
1275+
private async _render404Page(url: RouterURL = { locale: this.config.defaultLocale, pagePath: '', pathname: '/', params: new Map(), query: new URLSearchParams() }) {
12791276
const ret: RenderResult = { url, status: 404, head: [], body: '<main></main>', data: null }
12801277
try {
12811278
const e404Module = this.#modules.get('/404.js')

routing.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export class Routing {
117117
let locale = this._defaultLocale
118118
let pathname = util.cleanPath(util.trimPrefix(loc.pathname, this._baseUrl))
119119
let pagePath = ''
120-
let params: Record<string, string> = {}
120+
let params: Map<string, string> = new Map
121121
let tree: RouteModule[] = []
122122

123123
if (pathname !== '/' && this._locales.length > 0) {
@@ -139,7 +139,9 @@ export class Routing {
139139
tree.push(c.module)
140140
}
141141
pagePath = path
142-
params = p
142+
for (const key in p) {
143+
params.set(key, p[key])
144+
}
143145
return false
144146
}
145147
}, true)

server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AlephAPIResponse } from './api.ts'
1+
import { Request } from './api.ts'
22
import { createHtml } from './html.ts'
33
import log from './log.ts'
44
import { getContentType } from './mime.ts'
@@ -17,7 +17,7 @@ export async function start(appDir: string, port: number, isDev = false, reload
1717
for await (const req of s) {
1818
const url = new URL('http://localhost/' + req.url)
1919
const pathname = util.cleanPath(url.pathname)
20-
const resp = new AlephAPIResponse(req)
20+
const resp = new Request(req, { pathname, params: new Map(), query: new URLSearchParams() })
2121

2222
try {
2323
// serve hmr ws

types.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,38 +29,52 @@ export interface Config {
2929
}
3030

3131
export interface APIRequestURL {
32-
readonly proto: string
33-
readonly protoMinor: number
34-
readonly protoMajor: number
3532
readonly pathname: string
3633
readonly params: ReadonlyMap<string, string>
3734
readonly query: URLSearchParams
3835
}
3936

37+
export interface Response {
38+
status?: number
39+
headers?: Headers
40+
trailers?: () => Promise<Headers> | Headers
41+
body?: Uint8Array | Deno.Reader | string
42+
}
43+
4044
export interface APIRequest {
4145
readonly method: string
42-
readonly url: APIRequestURL
46+
readonly proto: string
47+
readonly protoMinor: number
48+
readonly protoMajor: number
4349
readonly headers: Headers
50+
readonly conn: Deno.Conn
51+
readonly r: Deno.Reader
52+
readonly w: Deno.Writer
53+
readonly done: Promise<Error | undefined>
54+
readonly contentLength: number | null
55+
readonly body: Deno.Reader
56+
respond(r: Response): Promise<void>
57+
finalize(): Promise<void>
58+
// plus
59+
readonly url: APIRequestURL
4460
readonly cookies: ReadonlyMap<string, string>
45-
}
46-
47-
export interface APIResponse {
4861
status(code: number): this
4962
addHeader(key: string, value: string): this
5063
setHeader(key: string, value: string): this
5164
removeHeader(key: string): this
5265
send(data: string | Uint8Array | ArrayBuffer): Promise<void>
5366
json(data: any): Promise<void>
67+
end(code: number): Promise<void>
5468
}
5569

56-
export interface APIHandle {
57-
(req: APIRequest, res: APIResponse): void
70+
export interface APIHandler {
71+
(req: APIRequest): void
5872
}
5973

6074
export interface RouterURL {
6175
readonly locale: string
6276
readonly pathname: string
6377
readonly pagePath: string
64-
readonly params: Record<string, string>
78+
readonly params: ReadonlyMap<string, string>
6579
readonly query: URLSearchParams
6680
}

0 commit comments

Comments
 (0)