Skip to content

Commit

Permalink
Improve code cohesion
Browse files Browse the repository at this point in the history
Refs: #2186
  • Loading branch information
erkannt committed Jan 24, 2025
1 parent ffb62f8 commit 7a794ee
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 52 deletions.
4 changes: 2 additions & 2 deletions integration/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
} from 'zenodo-ts'
import type { ConfigEnv } from '../src/app.js'
import { AuthorInviteC } from '../src/author-invite.js'
import * as CachingHttpClient from '../src/CachingHttpClient/index.js'
import {
ContactEmailAddressC,
UnverifiedContactEmailAddress,
Expand All @@ -53,7 +54,6 @@ import type {
import * as FeatureFlags from '../src/feature-flags.js'
import { GhostApi } from '../src/ghost.js'
import { rawHtml } from '../src/html.js'
import * as HttpCache from '../src/HttpCache.js'
import type {
AuthorInviteStoreEnv,
ContactEmailAddressStoreEnv,
Expand Down Expand Up @@ -1327,7 +1327,7 @@ const appFixtures: Fixtures<AppFixtures, Record<never, never>, PlaywrightTestArg
Effect.provide(Nodemailer.layer(nodemailer)),
Effect.provideService(PublicUrl, new URL(`http://localhost:${port}`)),
Effect.provideService(SessionSecret, Redacted.make('')),
Effect.provide(HttpCache.layerInMemory()),
Effect.provide(CachingHttpClient.layerInMemory()),
Effect.provide(FetchHttpClient.layer),
Effect.provideService(FetchHttpClient.Fetch, fetch as unknown as typeof globalThis.fetch),
Effect.provide(LibsqlClient.layer({ url: `file:${testInfo.outputPath('database.db')}` })),
Expand Down
78 changes: 41 additions & 37 deletions src/HttpCache.ts → src/CachingHttpClient/HttpCache.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Headers, HttpClientResponse, UrlParams, type HttpClientRequest } from '@effect/platform'
import { Cause, Context, Effect, Layer, Option, pipe, Schema, type DateTime } from 'effect'
import * as Redis from './Redis.js'
import * as Redis from '../Redis.js'
import { serializationErrorChecking } from './SerializationErrorChecking.js'

interface CacheValue {
staleAt: DateTime.Utc
Expand Down Expand Up @@ -43,43 +44,46 @@ export const layerPersistedToRedis = Layer.effect(
Effect.gen(function* () {
const redis = yield* Redis.HttpCacheRedis

return {
get: request =>
pipe(
Effect.tryPromise(() => redis.get(keyForRequest(request))),
Effect.andThen(Option.fromNullable),
Effect.andThen(Schema.decode(CacheValueFromStringSchema)),
Effect.map(({ staleAt, response }) => ({
staleAt,
response: HttpClientResponse.fromWeb(
request,
new Response(response.body, {
status: response.status,
headers: Headers.fromInput(response.headers),
}),
),
})),
Effect.mapError(() => new Cause.NoSuchElementException()),
),
set: (response, staleAt) =>
pipe(
Effect.gen(function* () {
return {
return pipe(
{
get: request =>
pipe(
Effect.tryPromise(() => redis.get(keyForRequest(request))),
Effect.andThen(Option.fromNullable),
Effect.andThen(Schema.decode(CacheValueFromStringSchema)),
Effect.map(({ staleAt, response }) => ({
staleAt,
response: {
status: response.status,
headers: response.headers,
body: yield* response.text,
},
}
}),
Effect.andThen(Schema.encode(CacheValueFromStringSchema)),
Effect.andThen(value => {
return redis.set(keyForRequest(response.request), value)
}),
),
delete: () => Effect.void,
}
response: HttpClientResponse.fromWeb(
request,
new Response(response.body, {
status: response.status,
headers: Headers.fromInput(response.headers),
}),
),
})),
Effect.mapError(() => new Cause.NoSuchElementException()),
),
set: (response, staleAt) =>
pipe(
Effect.gen(function* () {
return {
staleAt,
response: {
status: response.status,
headers: response.headers,
body: yield* response.text,
},
}
}),
Effect.andThen(Schema.encode(CacheValueFromStringSchema)),
Effect.andThen(value => {
return redis.set(keyForRequest(response.request), value)
}),
),
delete: () => Effect.void,
},
serializationErrorChecking,
)
}),
)

Expand Down
2 changes: 1 addition & 1 deletion src/CachingHttpClient/SerializationErrorChecking.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type HttpClientResponse, UrlParams } from '@effect/platform'
import { diff } from 'deep-object-diff'
import { type DateTime, Effect, pipe } from 'effect'
import type * as HttpCache from '../HttpCache.js'
import type * as HttpCache from './HttpCache.js'

export const serializationErrorChecking = (
httpCache: typeof HttpCache.HttpCache.Service,
Expand Down
7 changes: 4 additions & 3 deletions src/CachingHttpClient/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import {
type HttpClientResponse,
} from '@effect/platform'
import { DateTime, Effect, Option, pipe, type Scope } from 'effect'
import * as HttpCache from '../HttpCache.js'
import { serializationErrorChecking } from './SerializationErrorChecking.js'
import * as HttpCache from './HttpCache.js'

export * from './HttpCache.js'

export const CachingHttpClient: Effect.Effect<
HttpClient.HttpClient,
never,
HttpCache.HttpCache | HttpClient.HttpClient
> = Effect.gen(function* () {
const httpClient = yield* HttpClient.HttpClient
const cache = yield* HttpCache.HttpCache.pipe(Effect.andThen(serializationErrorChecking))
const cache = yield* HttpCache.HttpCache

const cachingBehaviour = (
request: Effect.Effect<HttpClientRequest.HttpClientRequest>,
Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { Config, Effect, Function, Layer, Logger, LogLevel, Schema } from 'effec
import { pipe } from 'fp-ts/lib/function.js'
import { createServer } from 'http'
import fetch from 'make-fetch-happen'
import * as CachingHttpClient from './CachingHttpClient/index.js'
import { DeprecatedEnvVars, DeprecatedLoggerEnv, ExpressConfig, SessionSecret } from './Context.js'
import { DeprecatedLogger, makeDeprecatedEnvVars, makeDeprecatedLoggerEnv } from './DeprecatedServices.js'
import { ExpressConfigLive } from './ExpressServer.js'
import * as FeatureFlags from './feature-flags.js'
import * as FptsToEffect from './FptsToEffect.js'
import { GhostApi } from './ghost.js'
import * as HttpCache from './HttpCache.js'
import * as Nodemailer from './nodemailer.js'
import { Program } from './Program.js'
import { PublicUrl } from './public-url.js'
Expand All @@ -23,13 +23,13 @@ pipe(
Program,
Layer.merge(Layer.effectDiscard(verifyCache)),
Layer.launch,
Effect.provide(HttpCache.layerInMemory()),
Effect.provide(CachingHttpClient.layerInMemory()),
Effect.provide(
Layer.mergeAll(
NodeHttpServer.layerConfig(() => createServer(), { port: Config.succeed(3000) }),
Layer.effect(ExpressConfig, ExpressConfigLive),
NodeHttpClient.layer,
HttpCache.layerPersistedToRedis,
CachingHttpClient.layerPersistedToRedis,
Layer.effect(
FetchHttpClient.Fetch,
Effect.gen(function* () {
Expand Down
11 changes: 5 additions & 6 deletions test/CachingHttpClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { describe, expect } from '@jest/globals'
import { type Duration, Effect, Either, Fiber, Option, pipe, TestClock, TestContext } from 'effect'
import { StatusCodes } from 'http-status-codes'
import * as _ from '../src/CachingHttpClient/index.js'
import * as HttpCache from '../src/HttpCache.js'
import * as fc from './fc.js'

const stubbedClient = (
Expand All @@ -27,7 +26,7 @@ describe('there is no cache entry', () => {
const client = yield* pipe(
_.CachingHttpClient,
Effect.provideService(HttpClient.HttpClient, stubbedClient(successfulResponse)),
Effect.provide(HttpCache.layerInMemory(cache)),
Effect.provide(_.layerInMemory(cache)),
)

const actualResponse = yield* client.get(url)
Expand All @@ -42,7 +41,7 @@ describe('there is no cache entry', () => {
const client = yield* pipe(
_.CachingHttpClient,
Effect.provideService(HttpClient.HttpClient, stubbedClient(successfulResponse)),
Effect.provideService(HttpCache.HttpCache, {
Effect.provideService(_.HttpCache, {
get: () => Option.none(),
set: () => Effect.fail(error),
delete: () => Effect.void,
Expand All @@ -62,7 +61,7 @@ describe('there is no cache entry', () => {
const client = yield* pipe(
_.CachingHttpClient,
Effect.provideService(HttpClient.HttpClient, stubbedClient(successfulResponse, '3 seconds')),
Effect.provide(HttpCache.layerInMemory(cache)),
Effect.provide(_.layerInMemory(cache)),
)

const fiber = yield* pipe(client.get(url), Effect.either, Effect.fork)
Expand All @@ -81,7 +80,7 @@ describe('there is no cache entry', () => {
const client = yield* pipe(
_.CachingHttpClient,
Effect.provideService(HttpClient.HttpClient, stubbedFailingClient(error)),
Effect.provide(HttpCache.layerInMemory(cache)),
Effect.provide(_.layerInMemory(cache)),
)

const actualResponse = yield* Effect.either(client.get(url))
Expand All @@ -100,7 +99,7 @@ describe('there is no cache entry', () => {
const client = yield* pipe(
_.CachingHttpClient,
Effect.provideService(HttpClient.HttpClient, stubbedClient(response)),
Effect.provide(HttpCache.layerInMemory(cache)),
Effect.provide(_.layerInMemory(cache)),
)

const actualResponse = yield* client.get(url)
Expand Down

0 comments on commit 7a794ee

Please sign in to comment.