Skip to content

Commit

Permalink
refactor(server): update environment configuration and enhance API st…
Browse files Browse the repository at this point in the history
…ructure

- Refactored environment configuration by introducing a new ConfigProviderLayer for improved management of environment variables.
- Updated API structure by renaming the SuperTokens class to SupertokensService for better clarity.
- Enhanced API middleware by implementing a custom authentication middleware for improved user context handling.
- Cleaned up unused code and comments to streamline the codebase.
- Improved logging and server address handling in the HTTP server setup.
  • Loading branch information
guillempuche committed Dec 6, 2024
1 parent 5917cb3 commit 1178d43
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 63 deletions.
48 changes: 25 additions & 23 deletions apps/server/src/api/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import {
HttpApiBuilder,
HttpApiEndpoint,
HttpApiGroup,
HttpApiMiddleware,
HttpRouter,
OpenApi,
} from '@effect/platform'
import { Effect, Layer } from 'effect'
import Session from 'supertokens-node/recipe/session'
import SupertokensUserMetadata from 'supertokens-node/recipe/usermetadata'
import type { UserContext } from 'supertokens-node/types'

import { AuthMiddleware } from './auth_middleware.js'
import { SupertokensMiddleware } from './middleware_old.js'
import { withAuthMiddleware } from './auth_middleware_custom.js'
import { ResponseHello, ResponseProtected, UserMetadata } from './responses.js'
import { SessionService } from './session.js'
import { CurrentUser } from './types.js'
// import { UserMetadataService } from './user_metadata.js'

// ================================================
Expand All @@ -28,7 +29,7 @@ const apiDemo = HttpApiGroup.make('demo')
.add(
HttpApiEndpoint.get('protected', '/protected')
.addSuccess(ResponseProtected)
.middleware(SupertokensMiddleware)
.middleware(withAuthMiddleware)
.annotate(OpenApi.Description, 'Returns user ID for authenticated users'),
)
.annotateContext(
Expand All @@ -46,7 +47,8 @@ const apiUsers = HttpApiGroup.make('users')
OpenApi.Description,
'Get SuperTokens metadata for authenticated user',
),
).middlewareEndpoints(AuthMiddleware)
)
.middleware(withAuthMiddleware)
.annotateContext(
OpenApi.annotations({
title: 'Users API',
Expand All @@ -73,33 +75,33 @@ const ApiDemoLive = HttpApiBuilder.group(api, 'demo', handlers =>
Effect.succeed(new ResponseHello({ message: 'Hello from Effect!' })),
)
.handle('protected', () =>
// Effect.gen(function* () {
// const session = yield* SessionService
// return new ResponseProtected({ userId: session.getUserId() })
// }),
{
const session = await Session.getSession(req, res);
Effect.succeed(new ResponseProtected({ userId: session.getUserId() })),
}
Effect.gen(function* () {
const user = yield* CurrentUser
return new ResponseProtected({ userId: user.id })
}),
),
)

const ApiUsersLive = HttpApiBuilder.group(api, 'users', handlers =>
handlers.handle('metadata', () =>
Effect.gen(function* () {
const session = yield* SessionService
const userMetadata = yield* UserMetadataService

const userId = session.getUserId()
const user = yield* CurrentUser
const userContext: UserContext = {} as UserContext

const metadata = Effect.tryPromise(() =>
userMetadata.getUserMetadata({ userId, userContext }),
)
// const metadata = Effect.tryPromise(() =>
// SupertokensUserMetadata.getUserMetadata(user.id),
// ).pipe(Effect.from, Effect.flatMap(el => Effect.succeed(el)))

// if (Effect.isSuccess(metadata)) {
// return new UserMetadata({
// userId: user.id,
// metadata: metadata,
// })
// }

return new UserMetadata({
userId: session.getUserId(),
metadata: metadata,
userId: user.id,
metadata: {},
})
}),
),
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/api/auth_middleware_custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { CurrentUser, Forbidden, Unauthorized } from './types.js'
type NextFunction = (err?: any) => void

// Inspired from https://github.com/supertokens/supertokens-node/blob/1896eabb0aac587f8b5f7a9bede8cc4b0a17a229/examples/cloudflare-workers/with-email-password-hono-be-only/middleware.ts
export const authMiddleware = HttpMiddleware.make(app =>
export const withAuthMiddleware = HttpMiddleware.make(app =>
Effect.gen(function* () {
const request = yield* ServerRequest.HttpServerRequest

Expand Down
42 changes: 23 additions & 19 deletions apps/server/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { Config, Effect, Layer } from 'effect'
import { Config, ConfigProvider, Effect, Layer } from 'effect'

// Environment configuration layer
export class Env {
static readonly Live = Layer.mergeAll(
Layer.setConfigProvider(
Effect.succeed({
load: (path: string) => Effect.succeed(process.env[path]),
}),
),
)
export const ConfigProviderLayer = Layer.setConfigProvider(
ConfigProvider.fromJson(process.env),
)

static readonly load = Effect.all({
NODE_ENV: Config.string('NODE_ENV'),
SERVER_PORT: Config.number('SERVER_PORT'),
SUPERTOKENS_API_KEY: Config.string('SUPERTOKENS_API_KEY'),
SUPERTOKENS_URL: Config.string('SUPERTOKENS_URL'),
SERVER_URL: Config.string('SERVER_URL'),
WEBSITE_URL: Config.string('WEBSITE_URL'),
})
}
// // Environment configuration layer
// export class Env {
// static readonly Live = Layer.mergeAll(
// Layer.setConfigProvider(
// Effect.succeed({
// load: (path: string) => Effect.succeed(process.env[path]),
// }),
// ),
// )

// static readonly load = Effect.all({
// NODE_ENV: Config.string('NODE_ENV'),
// SERVER_PORT: Config.number('SERVER_PORT'),
// SUPERTOKENS_API_KEY: Config.string('SUPERTOKENS_API_KEY'),
// SUPERTOKENS_URL: Config.string('SUPERTOKENS_URL'),
// SERVER_URL: Config.string('SERVER_URL'),
// WEBSITE_URL: Config.string('WEBSITE_URL'),
// })
// }
45 changes: 27 additions & 18 deletions apps/server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
import { createServer } from 'node:http'
import { HttpApiBuilder, HttpApiSwagger } from '@effect/platform'
import {
HttpApiBuilder,
HttpApiSwagger,
HttpMiddleware,
HttpServer,
} from '@effect/platform'
import { NodeHttpServer, NodeRuntime } from '@effect/platform-node'
import { Effect, Layer } from 'effect'
import { Config, Layer } from 'effect'

import { ApiLive } from './api/apis.js'
import { withCorsMiddleware } from './api/cors.js'
import { Env } from './env.js'
import { SuperTokens } from './supertokens.js'
import { MiddlewareCorsLive } from './api/cors.js'
import { SupertokensService } from './supertokens.js'
// import { Env } from './env.js'

// TODO: init SuperTokens
// const ServerConfig = Config.all({
// SERVER_PORT: Config.number('SERVER_PORT'),
// })

const program = Effect.gen(function* () {
const config = yield* Env.load
// HTTP server implementation
const ServerLive = NodeHttpServer.layer(() => createServer(), {
port: 4040,
})

const ServerLive = NodeHttpServer.layer(() => createServer(), {
port: config.SERVER_PORT,
})

const HttpLive = HttpApiBuilder.serve(withCorsMiddleware).pipe(
Layer.provide(HttpApiSwagger.layer({ path: '/docs' })),
// Register API with HTTP server
const HttpLive = HttpApiBuilder.serve(HttpMiddleware.logger)
.pipe(
Layer.provide(MiddlewareCorsLive),
Layer.provide(SupertokensService.layer),
Layer.provide(ApiLive),
Layer.provide(ServerLive),
HttpServer.withLogAddress, // Log server address
Layer.provide(HttpApiSwagger.layer({ path: '/docs' })),
)
.pipe(Layer.provide(ServerLive))

return yield* Layer.launch(HttpLive)
}).pipe(Effect.provide(Env.Live))

NodeRuntime.runMain(program)
// Run server
NodeRuntime.runMain(Layer.launch(HttpLive))
4 changes: 2 additions & 2 deletions apps/server/src/supertokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ const make = (config: SuperTokensConfig) =>
})
})

export class SuperTokens extends Context.Tag('SuperTokens')<
SuperTokens,
export class SupertokensService extends Context.Tag('SupertokensService')<
SupertokensService,
void
>() {
static readonly Config = Config.all({
Expand Down

0 comments on commit 1178d43

Please sign in to comment.