Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add handling for downloading schema from registry to Swift Scripting #1691

Merged
merged 4 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 54 additions & 11 deletions Sources/ApolloCodegenLib/ApolloSchemaOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,48 @@ public struct ApolloSchemaOptions {
case schemaDefinitionLanguage = "graphql"
}

let apiKey: String?
let endpointURL: URL
/// How to attempt to download your schema
public enum DownloadMethod: Equatable {

case registry(_ settings: RegistrySettings)
/// - endpointURL: The endpoint to hit to download your schema.
case introspection(endpointURL: URL)

public struct RegistrySettings: Equatable {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a separate object so that it can have new parameters added without breaking the enum.

public let apiKey: String
public let graphID: String
public let variant: String?

/// Designated initializer
///
/// - Parameters:
/// - apiKey: The API key to use when retrieving your schema.
/// - graphID: The identifier of the graph to fetch. Can be found in Apollo Studio.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's nothing explicitly named "graph id" in Apollo Studio that I can see, but I'm guessing it's the dynamic part of the URL (after "/graph/"). If so, this is also the part between "service:" and the key itself in the token.

I've changed the name of our graph in Apollo Studio, but the name in the URL and token retains the old name so I'm guessing the "graph id" is the full thing and not just the id-looking part after the old name. I'll give it a shot and see what works!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thoughts above were accurate, and it works 👍 An internet-savvy person can probably figure it out, but it's not entirely obvious what to put as the graphID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's being addressed on the Studio end shortly.

/// - variant: [Optional] The variant of the graph to fetch. Defaults to nil, which will return whatever is set to the current variant.
public init(apiKey: String,
graphID: String,
variant: String? = nil) {
self.apiKey = apiKey
self.graphID = graphID
self.variant = variant
}
}

public static func == (lhs: DownloadMethod, rhs: DownloadMethod) -> Bool {
switch (lhs, rhs) {
case (.introspection(let lhsURL), introspection(let rhsURL)):
return lhsURL == rhsURL
case (.registry(let lhsSettings),
.registry(let rhsSettings)):
return lhsSettings == rhsSettings
default:
return false
}
}

}

let downloadMethod: DownloadMethod
let headers: [String]
let outputURL: URL

Expand All @@ -21,21 +61,18 @@ public struct ApolloSchemaOptions {
/// - Parameters:
/// - schemaFileName: The name, without an extension, for your schema file. Defaults to `"schema"`
/// - schemaFileType: The `SchemaFileType` to download the schema as. Defaults to `.json`.
/// - apiKey: [optional] The API key to use when retrieving your schema. Defaults to nil.
/// - endpointURL: The endpoint to hit to download your schema.
/// - downloadMethod: How to download your schema.
/// - headers: [optional] Any additional headers to include when retrieving your schema. Defaults to nil
/// - outputFolderURL: The URL of the folder in which the downloaded schema should be written
/// - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds.
public init(schemaFileName: String = "schema",
schemaFileType: SchemaFileType = .json,
apiKey: String? = nil,
endpointURL: URL,
downloadMethod: DownloadMethod,
headers: [String] = [],
outputFolderURL: URL,
downloadTimeout: Double = 30.0) {
self.apiKey = apiKey
self.downloadMethod = downloadMethod
self.headers = headers
self.endpointURL = endpointURL
self.outputURL = outputFolderURL.appendingPathComponent("\(schemaFileName).\(schemaFileType.rawValue)")

self.downloadTimeout = downloadTimeout
Expand All @@ -44,11 +81,17 @@ public struct ApolloSchemaOptions {
var arguments: [String] {
var arguments = [
"client:download-schema",
"--endpoint=\(self.endpointURL.absoluteString)"
]

if let key = self.apiKey {
arguments.append("--key=\(key)")
switch self.downloadMethod {
case .introspection(let endpointURL):
arguments.append("--endpoint=\(endpointURL.absoluteString)")
case .registry(let settings):
arguments.append("--key=\(settings.apiKey)")
arguments.append("--graph=\(settings.graphID)")
if let providedVariant = settings.variant {
arguments.append("--variant=\(providedVariant)")
}
}

arguments.append("'\(outputURL.path)'")
Expand Down
12 changes: 11 additions & 1 deletion SwiftScripts/Sources/SchemaDownload/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,20 @@ let output = sourceRootURL
.appendingPathComponent("Sources")
.appendingPathComponent("UploadAPI")

// Introspection download:
let options = ApolloSchemaOptions(schemaFileName: "schema",
endpointURL: endpoint,
downloadMethod: .introspection(endpointURL: endpoint),
outputFolderURL: output)

// Registry download:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is left commented out for end to end testing in the future - not a great way to end to end test this without setting up a whole way of getting secrets into the repo.

//let registrySettings = ApolloSchemaOptions.DownloadMethod.RegistrySettings(apiKey: <#Replace Me For Testing#>,
// graphID: "Apollo-Fullstack-8zo5jl")
//
//let options = ApolloSchemaOptions(schemaFileName: "schema",
// schemaFileType: .schemaDefinitionLanguage,
// downloadMethod: .registry(registrySettings),
// outputFolderURL: output)

do {
try ApolloSchemaDownloader.run(with: cliFolderURL,
options: options)
Expand Down
55 changes: 42 additions & 13 deletions Tests/ApolloCodegenTests/ApolloSchemaTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ import ApolloTestSupport

class ApolloSchemaTests: XCTestCase {

func testCreatingOptionsWithDefaultParameters() throws {
func testCreatingIntrospectionOptionsWithDefaultParameters() throws {
let sourceRoot = CodegenTestHelper.sourceRootURL()
let options = ApolloSchemaOptions(endpointURL: TestURL.starWarsServer.url,

let options = ApolloSchemaOptions(downloadMethod: .introspection(endpointURL: TestURL.starWarsServer.url),
outputFolderURL: sourceRoot)

let expectedOutputURL = sourceRoot.appendingPathComponent("schema.json")
XCTAssertEqual(options.endpointURL, TestURL.starWarsServer.url)

XCTAssertEqual(options.downloadMethod, .introspection(endpointURL: TestURL.starWarsServer.url))
XCTAssertEqual(options.outputURL, expectedOutputURL)
XCTAssertNil(options.apiKey)
XCTAssertTrue(options.headers.isEmpty)

XCTAssertEqual(options.arguments, [
Expand All @@ -29,31 +30,59 @@ class ApolloSchemaTests: XCTestCase {
"'\(expectedOutputURL.path)'"
])
}

func testCreatingOptionsWithAllParameters() throws {

func testCreatingRegistryOptionsWithDefaultParameters() throws {
let sourceRoot = CodegenTestHelper.sourceRootURL()
let apiKey = "Fake_API_Key"
let graphID = "Fake_Graph_ID"

let settings = ApolloSchemaOptions.DownloadMethod.RegistrySettings(apiKey: apiKey, graphID: graphID)

let options = ApolloSchemaOptions(downloadMethod: .registry(settings),
outputFolderURL: sourceRoot)

let expectedOutputURL = sourceRoot.appendingPathComponent("schema.json")

XCTAssertEqual(options.downloadMethod, .registry(settings))
XCTAssertEqual(options.outputURL, expectedOutputURL)
XCTAssertTrue(options.headers.isEmpty)

XCTAssertEqual(options.arguments, [
"client:download-schema",
"--key=\(apiKey)",
"--graph=\(graphID)",
"'\(expectedOutputURL.path)'"
])
}

func testCreatingRegistryOptionsWithAllParameters() throws {
let sourceRoot = CodegenTestHelper.sourceRootURL()
let apiKey = "Fake_API_Key"
let graphID = "Fake_Graph_ID"
let variant = "Fake_Variant"
let firstHeader = "Authorization: Bearer tokenGoesHere"
let secondHeader = "Custom-Header: Custom_Customer"
let headers = [firstHeader, secondHeader]

let settings = ApolloSchemaOptions.DownloadMethod.RegistrySettings(apiKey: apiKey,
graphID: graphID, variant: variant)

let options = ApolloSchemaOptions(schemaFileName: "different_name",
schemaFileType: .schemaDefinitionLanguage,
apiKey: apiKey,
endpointURL: TestURL.starWarsServer.url,
downloadMethod: .registry(settings),
headers: headers,
outputFolderURL: sourceRoot)
XCTAssertEqual(options.apiKey, apiKey)
XCTAssertEqual(options.endpointURL, TestURL.starWarsServer.url)
XCTAssertEqual(options.downloadMethod, .registry(settings))
XCTAssertEqual(options.headers, headers)

let expectedOutputURL = sourceRoot.appendingPathComponent("different_name.graphql")
XCTAssertEqual(options.outputURL, expectedOutputURL)

XCTAssertEqual(options.arguments, [
"client:download-schema",
"--endpoint=http://localhost:8080/graphql",
"--key=\(apiKey)",
"--graph=\(graphID)",
"--variant=\(variant)",
"'\(expectedOutputURL.path)'",
"--header='\(firstHeader)'",
"--header='\(secondHeader)'"
Expand All @@ -63,7 +92,7 @@ class ApolloSchemaTests: XCTestCase {
func testDownloadingSchemaAsJSON() throws {
let testOutputFolderURL = CodegenTestHelper.outputFolderURL()

let options = ApolloSchemaOptions(endpointURL: TestURL.starWarsServer.url,
let options = ApolloSchemaOptions(downloadMethod: .introspection(endpointURL: TestURL.starWarsServer.url),
outputFolderURL: testOutputFolderURL)

// Delete anything existing at the output URL
Expand Down Expand Up @@ -97,7 +126,7 @@ class ApolloSchemaTests: XCTestCase {
let testOutputFolderURL = CodegenTestHelper.outputFolderURL()

let options = ApolloSchemaOptions(schemaFileType: .schemaDefinitionLanguage,
endpointURL: TestURL.starWarsServer.url,
downloadMethod: .introspection(endpointURL: TestURL.starWarsServer.url),
outputFolderURL: testOutputFolderURL)

// Delete anything existing at the output URL
Expand Down