Skip to content

Commit

Permalink
chore!: remove x- prefix from custom HTTP headers (#1739)
Browse files Browse the repository at this point in the history
This PR removes the x- prefix from Electric's custom headers, as
essentially the x- prefix has been deprecated for a while. **This is a
breaking change** as it changes the names of the headers. Fixes
#1737.
  • Loading branch information
kevin-dp authored Sep 23, 2024
1 parent 4603e9e commit b0d258d
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 34 deletions.
6 changes: 6 additions & 0 deletions .changeset/lucky-crabs-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@electric-sql/client": minor
"@core/sync-service": minor
---

Rename Electric's custom HTTP headers to remove the x- prefix.
10 changes: 5 additions & 5 deletions packages/sync-service/lib/electric/plug/serve_shape_plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ defmodule Electric.Plug.ServeShapePlug do
conn
|> assign(:active_shape_id, active_shape_id)
|> assign(:last_offset, last_offset)
|> put_resp_header("x-electric-shape-id", active_shape_id)
|> put_resp_header("electric-shape-id", active_shape_id)
end

defp handle_shape_info(
Expand All @@ -225,7 +225,7 @@ defmodule Electric.Plug.ServeShapePlug do
# TODO: discuss returning a 307 redirect rather than a 409, the client
# will have to detect this and throw out old data
conn
|> put_resp_header("x-electric-shape-id", active_shape_id)
|> put_resp_header("electric-shape-id", active_shape_id)
|> put_resp_header(
"location",
"#{conn.request_path}?shape_id=#{active_shape_id}&offset=-1"
Expand All @@ -246,7 +246,7 @@ defmodule Electric.Plug.ServeShapePlug do
# Only adds schema header when not in live mode
defp put_schema_header(conn, _) when not conn.assigns.live do
shape = conn.assigns.shape_definition
put_resp_header(conn, "x-electric-schema", schema(shape))
put_resp_header(conn, "electric-schema", schema(shape))
end

defp put_schema_header(conn, _), do: conn
Expand All @@ -261,7 +261,7 @@ defmodule Electric.Plug.ServeShapePlug do

conn
|> assign(:chunk_end_offset, chunk_end_offset)
|> put_resp_header("x-electric-chunk-last-offset", "#{chunk_end_offset}")
|> put_resp_header("electric-chunk-last-offset", "#{chunk_end_offset}")
end

defp generate_etag(%Conn{} = conn, _) do
Expand Down Expand Up @@ -477,7 +477,7 @@ defmodule Electric.Plug.ServeShapePlug do
|> assign(:last_offset, latest_log_offset)
|> assign(:chunk_end_offset, latest_log_offset)
# update last offset header
|> put_resp_header("x-electric-chunk-last-offset", "#{latest_log_offset}")
|> put_resp_header("electric-chunk-last-offset", "#{latest_log_offset}")
|> serve_log_or_snapshot([])

{^ref, :shape_rotation} ->
Expand Down
16 changes: 8 additions & 8 deletions packages/sync-service/test/electric/plug/router_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,8 @@ defmodule Electric.Plug.RouterTest do

conn = conn("GET", "/v1/shape/large_rows_table?offset=-1") |> Router.call(opts)
assert %{status: 200} = conn
[shape_id] = Plug.Conn.get_resp_header(conn, "x-electric-shape-id")
[next_offset] = Plug.Conn.get_resp_header(conn, "x-electric-chunk-last-offset")
[shape_id] = Plug.Conn.get_resp_header(conn, "electric-shape-id")
[next_offset] = Plug.Conn.get_resp_header(conn, "electric-chunk-last-offset")

assert [_] = Jason.decode!(conn.resp_body)

Expand Down Expand Up @@ -660,7 +660,7 @@ defmodule Electric.Plug.RouterTest do
}
] = Jason.decode!(conn.resp_body)

[next_offset] = Plug.Conn.get_resp_header(conn, "x-electric-chunk-last-offset")
[next_offset] = Plug.Conn.get_resp_header(conn, "electric-chunk-last-offset")

conn =
conn("GET", "/v1/shape/large_rows_table?offset=#{next_offset}&shape_id=#{shape_id}")
Expand Down Expand Up @@ -695,7 +695,7 @@ defmodule Electric.Plug.RouterTest do
assert conn.resp_body != ""

shape_id = get_resp_shape_id(conn)
[next_offset] = Plug.Conn.get_resp_header(conn, "x-electric-chunk-last-offset")
[next_offset] = Plug.Conn.get_resp_header(conn, "electric-chunk-last-offset")

# Make the next request but forget to include the where clause
conn =
Expand All @@ -717,7 +717,7 @@ defmodule Electric.Plug.RouterTest do

assert %{status: 409} = conn
assert conn.resp_body == Jason.encode!([%{headers: %{control: "must-refetch"}}])
new_shape_id = get_resp_header(conn, "x-electric-shape-id")
new_shape_id = get_resp_header(conn, "electric-shape-id")

assert get_resp_header(conn, "location") ==
"/v1/shape/items?shape_id=#{new_shape_id}&offset=-1"
Expand Down Expand Up @@ -746,7 +746,7 @@ defmodule Electric.Plug.RouterTest do
|> Router.call(opts)

assert %{status: 409} = conn
[^shape_id] = Plug.Conn.get_resp_header(conn, "x-electric-shape-id")
[^shape_id] = Plug.Conn.get_resp_header(conn, "electric-shape-id")
end

@tag with_sql: [
Expand Down Expand Up @@ -797,8 +797,8 @@ defmodule Electric.Plug.RouterTest do
end
end

defp get_resp_shape_id(conn), do: get_resp_header(conn, "x-electric-shape-id")
defp get_resp_last_offset(conn), do: get_resp_header(conn, "x-electric-chunk-last-offset")
defp get_resp_shape_id(conn), do: get_resp_header(conn, "electric-shape-id")
defp get_resp_last_offset(conn), do: get_resp_header(conn, "electric-chunk-last-offset")

defp get_resp_header(conn, header) do
assert [val] = Plug.Conn.get_resp_header(conn, header)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ defmodule Electric.Plug.ServeShapePlugTest do
"#{@test_shape_id}:-1:#{next_offset}"
]

assert Plug.Conn.get_resp_header(conn, "x-electric-shape-id") == [@test_shape_id]
assert Plug.Conn.get_resp_header(conn, "electric-shape-id") == [@test_shape_id]
end

test "snapshot has correct cache control headers" do
Expand Down Expand Up @@ -208,7 +208,7 @@ defmodule Electric.Plug.ServeShapePlugTest do
conn(:get, %{"root_table" => "public.users"}, "?offset=-1")
|> ServeShapePlug.call([])

assert Plug.Conn.get_resp_header(conn, "x-electric-schema") == [
assert Plug.Conn.get_resp_header(conn, "electric-schema") == [
~s|{"id":{"type":"int8","pk_index":0}}|
]
end
Expand Down Expand Up @@ -264,9 +264,9 @@ defmodule Electric.Plug.ServeShapePlugTest do
"#{@test_shape_id}:#{@start_offset_50}:#{next_next_offset}"
]

assert Plug.Conn.get_resp_header(conn, "x-electric-shape-id") == [@test_shape_id]
assert Plug.Conn.get_resp_header(conn, "electric-shape-id") == [@test_shape_id]

assert Plug.Conn.get_resp_header(conn, "x-electric-chunk-last-offset") == [
assert Plug.Conn.get_resp_header(conn, "electric-chunk-last-offset") == [
"#{next_next_offset}"
]
end
Expand Down Expand Up @@ -357,8 +357,8 @@ defmodule Electric.Plug.ServeShapePlugTest do
"max-age=5, stale-while-revalidate=5"
]

assert Plug.Conn.get_resp_header(conn, "x-electric-chunk-last-offset") == [next_offset_str]
assert Plug.Conn.get_resp_header(conn, "x-electric-schema") == []
assert Plug.Conn.get_resp_header(conn, "electric-chunk-last-offset") == [next_offset_str]
assert Plug.Conn.get_resp_header(conn, "electric-schema") == []
end

test "handles shape rotation" do
Expand Down Expand Up @@ -463,7 +463,7 @@ defmodule Electric.Plug.ServeShapePlugTest do
assert conn.status == 409

assert Jason.decode!(conn.resp_body) == [%{"headers" => %{"control" => "must-refetch"}}]
assert get_resp_header(conn, "x-electric-shape-id") == [@test_shape_id]
assert get_resp_header(conn, "electric-shape-id") == [@test_shape_id]
assert get_resp_header(conn, "location") == ["/?shape_id=#{@test_shape_id}&offset=-1"]
end

Expand Down Expand Up @@ -491,7 +491,7 @@ defmodule Electric.Plug.ServeShapePlugTest do
assert conn.status == 409

assert Jason.decode!(conn.resp_body) == [%{"headers" => %{"control" => "must-refetch"}}]
assert get_resp_header(conn, "x-electric-shape-id") == [new_shape_id]
assert get_resp_header(conn, "electric-shape-id") == [new_shape_id]
assert get_resp_header(conn, "location") == ["/?shape_id=#{new_shape_id}&offset=-1"]
end

Expand Down
6 changes: 3 additions & 3 deletions packages/typescript-client/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const SHAPE_ID_HEADER = `x-electric-shape-id`
export const CHUNK_LAST_OFFSET_HEADER = `x-electric-chunk-last-offset`
export const SHAPE_SCHEMA_HEADER = `x-electric-schema`
export const SHAPE_ID_HEADER = `electric-shape-id`
export const CHUNK_LAST_OFFSET_HEADER = `electric-chunk-last-offset`
export const SHAPE_SCHEMA_HEADER = `electric-schema`
export const SHAPE_ID_QUERY_PARAM = `shape_id`
export const OFFSET_QUERY_PARAM = `offset`
export const WHERE_QUERY_PARAM = `where`
Expand Down
14 changes: 7 additions & 7 deletions packages/typescript-client/test/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ describe(`HTTP Proxy Cache`, { timeout: 30000 }, () => {
// add some data and follow with live request
await insertIssues({ title: `foo` })
const searchParams = new URLSearchParams({
offset: initialRes.headers.get(`x-electric-chunk-last-offset`)!,
shape_id: initialRes.headers.get(`x-electric-shape-id`)!,
offset: initialRes.headers.get(`electric-chunk-last-offset`)!,
shape_id: initialRes.headers.get(`electric-shape-id`)!,
live: `true`,
})

Expand Down Expand Up @@ -215,7 +215,7 @@ describe(`HTTP Initial Data Caching`, { timeout: 30000 }, () => {
)
expect(client1Res.status).toBe(200)
const originalShapeId =
client1Res.headers.get(`x-electric-shape-id`) ?? undefined
client1Res.headers.get(`electric-shape-id`) ?? undefined
assert(originalShapeId, `Should have shape ID`)
expect(getCacheStatus(client1Res)).toBe(CacheStatus.MISS)
//const messages = client1Res.status === 204 ? [] : await client1Res.json()
Expand All @@ -227,7 +227,7 @@ describe(`HTTP Initial Data Caching`, { timeout: 30000 }, () => {
{}
)
expect(client2Res.status).toBe(200)
const shapeId2 = client2Res.headers.get(`x-electric-shape-id`) ?? undefined
const shapeId2 = client2Res.headers.get(`electric-shape-id`) ?? undefined

expect(
originalShapeId,
Expand All @@ -236,7 +236,7 @@ describe(`HTTP Initial Data Caching`, { timeout: 30000 }, () => {

expect(getCacheStatus(client2Res)).toBe(CacheStatus.HIT)

const latestOffset = client2Res.headers.get(`x-electric-chunk-last-offset`)
const latestOffset = client2Res.headers.get(`electric-chunk-last-offset`)
assert(latestOffset, `latestOffset should be defined`)

// Now GC the shape
Expand All @@ -261,7 +261,7 @@ describe(`HTTP Initial Data Caching`, { timeout: 30000 }, () => {
expect(newCacheIgnoredSyncRes.status).toBe(200)
expect(getCacheStatus(newCacheIgnoredSyncRes)).toBe(CacheStatus.MISS)
const cacheBustedShapeId =
newCacheIgnoredSyncRes.headers.get(`x-electric-shape-id`)
newCacheIgnoredSyncRes.headers.get(`electric-shape-id`)
assert(cacheBustedShapeId)
expect(cacheBustedShapeId).not.toBe(originalShapeId)

Expand All @@ -271,7 +271,7 @@ describe(`HTTP Initial Data Caching`, { timeout: 30000 }, () => {
{}
)
const cachedShapeId =
newInitialSyncRes.headers.get(`x-electric-shape-id`) ?? undefined
newInitialSyncRes.headers.get(`electric-shape-id`) ?? undefined
expect(newInitialSyncRes.status).toBe(200)
expect(getCacheStatus(newInitialSyncRes)).toBe(CacheStatus.HIT)
expect(cachedShapeId, `Got old shape id that is out of scope`).not.toBe(
Expand Down
6 changes: 3 additions & 3 deletions packages/typescript-client/test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe(`HTTP Sync`, () => {
`${BASE_URL}/v1/shape/${issuesTableUrl}?offset=-1`,
{}
)
const shapeId = res.headers.get(`x-electric-shape-id`)
const shapeId = res.headers.get(`electric-shape-id`)
expect(shapeId).to.exist
})

Expand All @@ -126,7 +126,7 @@ describe(`HTTP Sync`, () => {
`${BASE_URL}/v1/shape/${issuesTableUrl}?offset=-1`,
{}
)
const lastOffset = res.headers.get(`x-electric-chunk-last-offset`)
const lastOffset = res.headers.get(`electric-chunk-last-offset`)
expect(lastOffset).to.exist
})

Expand Down Expand Up @@ -537,7 +537,7 @@ describe(`HTTP Sync`, () => {
const midMessage = messages.slice(-6)[0]
assert(`offset` in midMessage)
const midOffset = midMessage.offset
const shapeId = res.headers.get(`x-electric-shape-id`)
const shapeId = res.headers.get(`electric-shape-id`)
const etag = res.headers.get(`etag`)
assert(etag !== null, `Response should have etag header`)

Expand Down

0 comments on commit b0d258d

Please sign in to comment.