Use generated iOS SDKs

Firebase Data Connect client SDKs let you call your server-side queries and mutations directly from a Firebase app. You generate a custom client SDK in parallel as you design the schemas, queries and mutations you deploy to your Data Connect service. Then, you integrate methods from this SDK into your client logic.

As we've mentioned elsewhere, it's important to note that Data Connect queries and mutations are not submitted by client code and executed on the server. Instead, when deployed, Data Connect operations are stored on the server like Cloud Functions. This means you need to deploy corresponding client-side changes to avoid breaking existing users (for example, on older app versions).

That's why Data Connect provides you with a developer environment and tooling that lets you prototype your server-deployed schemas, queries and mutations. It also generates client-side SDKs automatically, while you prototype.

When you've iterated updates to your service and client apps, both server- and client-side updates are ready to deploy.

What is the client development workflow?

If you followed the Get started , you were introduced to the overall development flow for Data Connect . In this guide, you'll find more detailed information about generating Swift SDKs from your schema and working with client queries and mutations.

To summarize, to use generated Swift SDKs in your client apps, you'll follow these prerequisite steps:

  1. Add Firebase to your iOS app.
  2. To use the generated SDK, configure it as a dependency in Xcode.

    In the Xcode top navigation bar, select File > Add Package Dependencies > Add Local, and choose the folder containing the generated Package.swift .

Then:

  1. Develop your app schema.
  2. Set up SDK generation:

  3. Initialize your client code and import libraries .

  4. Implement calls to queries and mutations .

  5. Set up and use the Data Connect emulator and iterate.

Generate your Swift SDK

Use the Firebase CLI to set up Data Connect generated SDKs in your apps. The init command should detect all apps in the current folder and install generated SDKs automatically.

 firebase init dataconnect:sdk 

Update SDKs while prototyping

If you have Data Connect VS Code extension installed, it will always keep generated SDKs up to date.

If you don't use Data Connect VS Code extension, you can use Firebase CLI to keep generated SDKs up to date.

 firebase  
dataconnect:sdk:generate  
--watch 

Generate SDKs in build pipelines

You can use the Firebase CLI to generate Data Connect SDKs in CI/CD build processes.

 firebase  
dataconnect:sdk:generate 

Initialize the Data Connect iOS SDK

Initialize your Data Connect instance using the information you used to set up Data Connect (all available in the Firebase console Data Connect tab).

Getting a connector instance

The code for your connector will be generated by the Data Connect emulator. If your connector name is movies and the package is movies , as specified in connector.yaml , then retrieve the connector object by calling:

  let 
  
 connector 
  
 = 
  
 DataConnect 
 . 
 moviesConnector 
 

Implement queries and mutations

With the connector object, you can run queries and mutations as defined in the GraphQL source code. Suppose your connector has these operations defined:

  mutation 
  
 createMovie 
 ( 
 $title 
 : 
  
 String 
 !, 
  
 $releaseYear 
 : 
  
 Int 
 !, 
  
 $genre 
 : 
  
 String 
 !, 
  
 $rating 
 : 
  
 Int 
 !) 
  
 { 
  
 movie_insert 
 ( 
 data 
 : 
  
 { 
  
 title 
 : 
  
 $title 
  
 releaseYear 
 : 
  
 $releaseYear 
  
 genre 
 : 
  
 $genre 
  
 rating 
 : 
  
 $rating 
  
 }) 
 } 
 query 
  
 getMovieByKey 
 ( 
 $key 
 : 
  
 Movie_Key 
 !) 
  
 { 
  
 movie 
 ( 
 key 
 : 
  
 $key 
 ) 
  
 { 
  
 id 
  
 title 
  
 } 
 } 
 query 
  
 listMoviesByGenre 
 ( 
 $genre 
 : 
  
 String 
 !) 
  
 { 
  
 movies 
 ( 
 where 
 : 
  
 { 
 genre 
 : 
  
 { 
 eq 
 : 
  
 $genre 
 }}) 
  
 { 
  
 id 
  
 title 
  
 } 
 } 
 

You can then create a movie as follows:

  let 
  
 mutationResult 
  
 = 
  
 try 
  
 await 
  
 connector 
 . 
 createMovieMutation 
 . 
 execute 
 ( 
  
 title 
 : 
  
 "Empire Strikes Back" 
 , 
  
 releaseYear 
 : 
  
 1980 
 , 
  
 genre 
 : 
  
 "Sci-Fi" 
 , 
  
 rating 
 : 
  
 5 
 ) 
 print 
 ( 
 "Movie ID: 
 \( 
 mutationResult 
 . 
 data 
 . 
 movie_insert 
 . 
 id 
 ) 
 " 
 ) 
 

To retrieve a movie, you will use a query reference. All query refs are Observable publishers. Depending on the configured publisher (see connector.yaml) , they either support the @Observable macro (iOS 17+) or implement the ObservableObject protocol. The default, if none is specified, is the @Observable macro supported on iOS 17+.

In a SwiftUI view, you can bind the query results using the published data variable of the query ref and call the query's execute() method to update the data. The data variable will match the shape of data that was defined in your GQL query definition.

All retrieved results comply with the Decodable protocol. If you included the object's primary key in your GQL fetch, the objects are also Identifiable , allowing you to use them in iterators.

  struct 
  
 ListMovieView 
 : 
  
 View 
  
 { 
  
 @ 
 StateObject 
  
 private 
  
 var 
  
 queryRef 
  
 = 
  
 connector 
 . 
 listMoviesByGenreQuery 
 . 
 ref 
 ( 
 genre 
 : 
  
 "Sci-Fi" 
 ) 
  
 var 
  
 body 
 : 
  
 some 
  
 View 
  
 { 
  
 VStack 
  
 { 
  
 Button 
  
 { 
  
 Task 
  
 { 
  
 do 
  
 { 
  
 try 
  
 await 
  
 refresh 
 () 
  
 } 
  
 catch 
  
 { 
  
 print 
 ( 
 "Failed to refresh: 
 \( 
 error 
 ) 
 " 
 ) 
  
 } 
  
 } 
  
 } 
  
 label 
 : 
  
 { 
  
 Text 
 ( 
 "Refresh" 
 ) 
  
 } 
  
 // use the query results in a view 
  
 ForEach 
 ( 
 queryRef 
 . 
 data 
 ?. 
 movies 
  
 ?? 
  
 [], 
  
 id 
 : 
  
 \ 
 . 
 self 
 . 
 id 
 ) 
  
 { 
  
 movie 
  
 in 
  
 Text 
 ( 
 movie 
 . 
 title 
 ) 
  
 } 
  
 } 
  
 } 
  
 @ 
 MainActor 
  
 func 
  
 refresh 
 () 
  
 async 
  
 throws 
  
 { 
  
 _ 
  
 = 
  
 try 
  
 await 
  
 queryRef 
 . 
 execute 
 () 
  
 } 
 } 
 

Queries also support one-shot execution.

  let 
  
 resultData 
  
 = 
  
 try 
  
 await 
  
 DataConnect 
 . 
 moviesConnector 
 . 
 listMoviesByGenreQuery 
 . 
 execute 
 ( 
 genre 
 : 
  
 "Sci-Fi" 
 ) 
 

Handle changes to enumeration fields

An app's schema can contain enumerations , which can be accessed by your GraphQL queries .

As an app's design changes, you may add new enum supported values. For example, imagine that later in your application’s lifecycle you decide to add a FULLSCREEN value to the AspectRatio enum.

In the Data Connect workflow, you can use local development tooling to update your queries and SDKs.

However, before you release an updated version of your clients, older deployed clients may break.

Example resilient implementation

The generated SDK forces handling of unknown values as the generated enums contain an _UNKNOWN value, and Swift enforces exhaustive switch statements.

  do 
  
 { 
  
 let 
  
 result 
  
 = 
  
 try 
  
 await 
  
 DataConnect 
 . 
 moviesConnector 
 . 
 listMovies 
 . 
 execute 
 () 
  
 if 
  
 let 
  
 data 
  
 = 
  
 result 
 . 
 data 
  
 { 
  
 for 
  
 movie 
  
 in 
  
 data 
 . 
 movies 
  
 { 
  
 switch 
  
 movie 
 . 
 aspectratio 
  
 { 
  
 case 
  
 . 
 ACADEMY 
 : 
  
 print 
 ( 
 "academy" 
 ) 
  
 case 
  
 . 
 WIDESCREEN 
 : 
  
 print 
 ( 
 "widescreen" 
 ) 
  
 case 
  
 . 
 ANAMORPHIC 
 : 
  
 print 
 ( 
 "anamorphic" 
 ) 
  
 case 
  
 . 
 _UNKNOWN 
 ( 
 let 
  
 unknownAspect 
 ): 
  
 print 
 ( 
 unknownAspect 
 ) 
  
 } 
  
 } 
  
 } 
 } 
  
 catch 
  
 { 
  
 // handle error 
 } 
 

Enable client-side caching

Data Connect has an optional client-side caching feature, which you can enable by editing the connector.yaml file. When this feature is enabled, the generated client SDKs will locally cache query responses, which can reduce the number of database requests your app makes and enables the database-dependent portions of your app to work when network availability is interrupted.

To enable client-side caching, add a client caching configuration to your connector configuration:

  generate 
 : 
  
 swiftSdk 
 : 
  
 outputDir 
 : 
  
 "../ios" 
  
 package 
 : 
  
 "FirebaseDataConnectGenerated" 
  
  clientCache 
 : 
  
 maxAge 
 : 
  
 5s 
  
 storage 
 : 
  
 persistent 
 

This configuration has two parameters, both optional:

  • maxAge : The maximum age a cached response can be before the client SDK fetches fresh values. Examples: "0", "30s", "1h30m".

    The default value for maxAge is 0 , which means that responses are cached, but the client SDK will always fetch fresh values. The cached values will only be used when CACHE_ONLY is specified to execute() .

  • storage : The client SDK can be configured to cache responses either in persistent storage or in memory . Results cached in persistent storage will persist across app restarts. In iOS SDKs, the default is persistent .

After you update your connector's caching configuration, regenerate your client SDKs and rebuild your app. Once you have done so, execute() will cache responses and use cached values according to the policy you configured. This generally happens automatically, without any additional steps on your part; however, note the following:

  • The default behavior of execute() is as described above: if a result is cached for a query and the cached value is not older than maxAge , then use the cached value. This default behavior is called the PREFER_CACHE policy.

    You can also specify to individual invocations of execute() to either only serve cached values ( CACHE_ONLY ) or to unconditionally fetch fresh values from the server ( SERVER_ONLY ).

      try 
      
     await 
      
     execute 
     ( 
     fetchPolicy 
     : 
      
     . 
     cacheOnly 
     ) 
     
    
      try 
      
     await 
      
     execute 
     ( 
     fetchPolicy 
     : 
      
     . 
     serverOnly 
     ) 
     
    

    Prototype and test your iOS application

    Instrument clients to use a local emulator

    You can use the Data Connect emulator, whether from the Data Connect VS Code extension or from the CLI.

    Instrumenting the app to connect to the emulator is the same for both scenarios.

      let 
      
     connector 
      
     = 
      
     DataConnect 
     . 
     moviesConnector 
     // Connect to the emulator on "127.0.0.1:9399" 
     connector 
     . 
     useEmulator 
     () 
     // (alternatively) if you're running your emulator on non-default port: 
     connector 
     . 
     useEmulator 
     ( 
     port 
     : 
      
     9999 
     ) 
     // Make calls from your app 
     
    

    Data types in Data Connect SDKs

    The Data Connect server represents common and custom GraphQL data types. These are represented in the SDK as follows.

    Data Connect Type Swift
    String String
    Int Int
    Float Double
    Boolean Bool
    UUID UUID
    Date FirebaseDataConnect.LocalDate
    Timestamp FirebaseCore.Timestamp
    Int64 Int64
    Any FirebaseDataConnect.AnyValue
Design a Mobile Site
View Site in Mobile | Classic
Share by: