Skip to content

Commit ebf8538

Browse files
Include firebase app id header (#9)
1 parent 52e39a8 commit ebf8538

File tree

3 files changed

+72
-9
lines changed

3 files changed

+72
-9
lines changed

Sources/DataConnect.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class DataConnect {
2424
private var app: FirebaseApp
2525
private var settings: DataConnectSettings
2626

27-
private var grpcClient: GrpcClient
27+
private(set) var grpcClient: GrpcClient
2828
private var operationsManager: OperationsManager
2929

3030
private static var instanceStore = InstanceStore()
@@ -57,12 +57,12 @@ public class DataConnect {
5757
// self.grpcClient.close
5858
// self.operations.close
5959

60-
guard let projectID = app.options.projectID else {
60+
guard app.options.projectID != nil else {
6161
fatalError("Firebase DataConnect requires the projectID to be set in the app options")
6262
}
6363

6464
grpcClient = GrpcClient(
65-
projectId: projectID,
65+
app: app,
6666
settings: settings,
6767
connectorConfig: connectorConfig,
6868
auth: Auth.auth(app: app),
@@ -79,12 +79,12 @@ public class DataConnect {
7979
self.settings = settings
8080
self.connectorConfig = connectorConfig
8181

82-
guard let projectID = app.options.projectID else {
82+
guard app.options.projectID != nil else {
8383
fatalError("Firebase DataConnect requires the projectID to be set in the app options")
8484
}
8585

8686
grpcClient = GrpcClient(
87-
projectId: projectID,
87+
app: self.app,
8888
settings: settings,
8989
connectorConfig: connectorConfig,
9090
auth: Auth.auth(app: app),

Sources/Internal/GrpcClient.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import Foundation
1616

1717
import FirebaseAppCheck
1818
import FirebaseAuth
19-
import FirebaseCoreInternal
19+
import FirebaseCore
2020
import GRPC
2121
import NIOCore
2222
import NIOHPACK
@@ -28,6 +28,8 @@ import SwiftProtobuf
2828
actor GrpcClient: CustomStringConvertible {
2929
nonisolated let description: String
3030

31+
private let app: FirebaseApp
32+
3133
private let projectId: String
3234

3335
private let threadPoolSize = 1
@@ -42,10 +44,11 @@ actor GrpcClient: CustomStringConvertible {
4244

4345
private let appCheck: AppCheck?
4446

45-
private enum RequestHeaders {
47+
enum RequestHeaders {
4648
static let googRequestParamsHeader = "x-goog-request-params"
4749
static let authorizationHeader = "x-firebase-auth-token"
4850
static let appCheckHeader = "X-Firebase-AppCheck"
51+
static let firebaseAppId = "x-firebase-gmpid"
4952
}
5053

5154
private let googRequestHeaderValue: String
@@ -69,10 +72,16 @@ actor GrpcClient: CustomStringConvertible {
6972
}
7073
}()
7174

72-
init(projectId: String, settings: DataConnectSettings, connectorConfig: ConnectorConfig,
75+
init(app: FirebaseApp, settings: DataConnectSettings, connectorConfig: ConnectorConfig,
7376
auth: Auth,
7477
appCheck: AppCheck?) {
78+
self.app = app
79+
80+
guard let projectId = app.options.projectID else {
81+
fatalError("Data Connect requires a Firebase project ID to be specified.")
82+
}
7583
self.projectId = projectId
84+
7685
serverSettings = settings
7786
self.connectorConfig = connectorConfig
7887
self.auth = auth
@@ -173,10 +182,11 @@ actor GrpcClient: CustomStringConvertible {
173182
}
174183
}
175184

176-
private func createCallOptions() async -> CallOptions {
185+
func createCallOptions() async -> CallOptions {
177186
var headers = HPACKHeaders()
178187

179188
headers.add(name: RequestHeaders.googRequestParamsHeader, value: googRequestHeaderValue)
189+
headers.add(name: RequestHeaders.firebaseAppId, value: app.options.googleAppID)
180190

181191
// Add Auth token if available
182192
do {

Tests/Unit/HeaderTests.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import FirebaseCore
16+
@testable import FirebaseDataConnect
17+
import Foundation
18+
import GRPC
19+
20+
import XCTest
21+
22+
final class HeaderTests: XCTestCase {
23+
static var defaultApp: FirebaseApp?
24+
25+
static var options: FirebaseOptions = {
26+
let options = FirebaseOptions(googleAppID: "0:0000000000000:ios:testAppId",
27+
gcmSenderID: "00000000000000000-00000000000-000000000")
28+
options.projectID = "fdc-test"
29+
options.apiKey = "testDummyApiKey"
30+
return options
31+
}()
32+
33+
var fakeConnectorConfigOne = ConnectorConfig(
34+
serviceId: "dataconnect",
35+
location: "us-central1",
36+
connector: "kitchensink"
37+
)
38+
39+
override class func setUp() {
40+
FirebaseApp.configure(options: options)
41+
defaultApp = FirebaseApp.app()
42+
}
43+
44+
func testGmpAppIdHeader() async throws {
45+
let dcOne = DataConnect.dataConnect(connectorConfig: fakeConnectorConfigOne)
46+
let callOptions = await dcOne.grpcClient.createCallOptions()
47+
let values = callOptions.customMetadata.values(
48+
forHeader: GrpcClient.RequestHeaders.firebaseAppId, canonicalForm: false
49+
)
50+
let contains = values.contains { $0 == HeaderTests.defaultApp!.options.googleAppID }
51+
XCTAssertTrue(contains)
52+
}
53+
}

0 commit comments

Comments
 (0)