Skip to content

Commit

Permalink
updated firestore demo
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyler Ayers committed Oct 8, 2020
1 parent b702dc6 commit 6aad76c
Show file tree
Hide file tree
Showing 35 changed files with 871 additions and 0 deletions.
77 changes: 77 additions & 0 deletions tutorial-demos/firestore-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Apigee Firestore Quickstart & Adapter
This repository contains a quickstart proxy for the [Apige API Management](cloud.google.com/apigee) platform to connect to a collection in a [Firestore](cloud.google.com/firestore) database. The API provided by the proxy can then be easily used by any REST clients, including [AppSheet](cloud.google.com/appsheet) no-code apps.

## Prerequisites
Firestore is a great document database for storing any kind of unstructured data, however we do need some structures to automatically use any database with this quickstart.
* An **id** field in each document, which should match the document key. This makes identifying the record quick and easy. It's easiest if this field is also called **id** in the document.
* Supported data types - we only support these data types in the documents for now:
* string
* boolean
* geopoint (locations)
* timestamp
* Not-supported data types - we don't support these data types, since they would be recursive and be difficult for REST clients like AppSheet to work with.
* array - It is recommended to have sub-array collections as separate collections (using an id field as link).
* map - This could be easily added and flattened into the REST response object, but on the other hand makes life difficult for clients like AppSheet, so it is recommended to also model sub-map structures as separate collections (using an id field as link).

As you can see, only primitive data types are supported in the Firestore documents, which makes it easy to map into REST resource structures.

## Quickstart deploy
The fastest way to deploy and spin up an API offering CRUD operations on your Firestore database is to import the **Firestore Quickstart** proxy bundle in Apigee, and then set these properties:

1. In the default Endpoint PreFlow, replace the following variables in the 1st policy **Set-Firestore-Variables** to your own values:
1. **GCP_PROJECT** - replace with the GCP project name where your Firestore database is located.
2. **firestore.key** - in case the **id** index field isn't named **id** in the Firestore documents (see prerequisites above), then you should set the correct name here (it is recommended to just use **id**).
3. **GCP_SVC_KEY** - set this to your GCP service account private key (which has the permissions to access Firestore in your GCP project) from the **private_key** field in the key JSON file (beginning with -----BEGIN PRIVATE KEY----- and ending with -----END PRIVATE KEY-----)
4. **GCP_SVC_EMAIL** - set this to the GCP service account email address from the **client_email** field in the private key JSON file.
2. Change the proxy basepath to something meaningful (default is **/importantstuff**, for no particular reason)
3. Deploy the proxy. By default an API key is activated for the proxy, disable the 2nd policy in the PreFlow if you want to test without one. Now you can call https://host/basepath/collection/document to all CRUD operations on your Firestore data, using simple JSON payload messages. WooHoo!
4. You can also use this proxy as an API data source in an AppSheet app, it will just work.

## Example
An example is deployed for this Firestore data structure:
```json
{
"name": "projects/tyler-240211/databases/(default)/documents/jokes/8ebb59f9",
"fields": {
"funny": {
"booleanValue": true
},
"imagePath": {
"stringValue": "https://dakiniland.files.wordpress.com/2011/05/102-0907085235-simpsons-mutant-fish-blinky.jpg"
},
"location": {
"geoPointValue": {
"latitude": 29.987294,
"longitude": -39.6875
}
},
"punchline": {
"stringValue": "A fiiish."
},
"text": {
"stringValue": "What do you call a fish with 3 eyes?"
},
"id": {
"stringValue": "8ebb59f9"
},
"timestamp": {
"timestampValue": "2020-10-08T13:05:29Z"
}
},
"createTime": "2020-10-08T11:06:55.234785Z",
"updateTime": "2020-10-08T11:21:56.903039Z"
}
```
This proxy then offers REST CRUD APIs with this much nicer structure:
```json
{
"id": "8ebb59f9",
"funny": true,
"text": "What do you call a fish with 3 eyes?",
"imagePath": "https://dakiniland.files.wordpress.com/2011/05/102-0907085235-simpsons-mutant-fish-blinky.jpg",
"timestamp": "2020-10-08T13:05:29Z",
"punchline": "A fiiish.",
"location": "29.987294, -39.6875"
}
```
The OpenAPI spec for the example is under /specs, and can also be used to create an AppSheet app based on the API.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<APIProxy revision="2" name="Firestore Quickstart">
<Basepaths>/importantstuff</Basepaths>
<ConfigurationVersion majorVersion="4" minorVersion="0"/>
<CreatedAt>1602160821771</CreatedAt>
<CreatedBy>defaultUser</CreatedBy>
<Description></Description>
<DisplayName>Firestore Quickstart</DisplayName>
<LastModifiedAt>1602163293230</LastModifiedAt>
<LastModifiedBy>defaultUser</LastModifiedBy>
<ManifestVersion>SHA-512:f55c15016835194ad271386c01805f23ab7de0f0150b4fe54abdbef4e3234c63d192850e55867d31fcce62f54651cbbc1858305b57ebd95a7743dd1b455c5087</ManifestVersion>
<Policies>
<Policy>Add-Bearer-Token</Policy>
<Policy>Assign-Message-2</Policy>
<Policy>Extract-Token</Policy>
<Policy>Generate-JWT-1</Policy>
<Policy>Get-Token</Policy>
<Policy>Get-Url-Variables</Policy>
<Policy>Remove-Key</Policy>
<Policy>Set-Firestore-Variables</Policy>
<Policy>Set-Verb</Policy>
<Policy>Verify-API-Key-1</Policy>
<Policy>set-request</Policy>
<Policy>set-response</Policy>
</Policies>
<ProxyEndpoints>
<ProxyEndpoint>default</ProxyEndpoint>
</ProxyEndpoints>
<Resources>
<Resource>jsc://set-request.js</Resource>
<Resource>jsc://set-response.js</Resource>
</Resources>
<Spec></Spec>
<TargetServers/>
<TargetEndpoints>
<TargetEndpoint>default</TargetEndpoint>
</TargetEndpoints>
</APIProxy>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest name="manifest">
<Policies>
<VersionInfo resourceName="Add-Bearer-Token" version="SHA-512:0a42e948dc886f1ee94cf3a6cd2044a5b8004e5d239e8ebc4265f17e4dda90a2d9886429b233d78907cfb729e225c189c8ee241bb0fc8a636c052475f2c5c489"/>
<VersionInfo resourceName="Assign-Message-2" version="SHA-512:5c9a169578d7f452969b7dbb44a000475b0a61a6c7b739114963456a658337a098bdd7174bdd0651754e85489baaffe3db918628a3b689382d88d88466b827c2"/>
<VersionInfo resourceName="Extract-Token" version="SHA-512:4f4270a4ed5d1002201079227cadc3253ad782d975dac8c11fc008078fe9ea5b81f854997b65177b671eef415533a7c2ce3bd3f276c2e50bda3fb0a593b416b8"/>
<VersionInfo resourceName="Generate-JWT-1" version="SHA-512:d19b26a4a6c624a7796fb141d7e949b43efea04b044f26a39c14dac54a30543d8f31dd0cd0a0417415a05a806b9dae3a60bb94d46b837f8949f4b15533f858fe"/>
<VersionInfo resourceName="Get-Token" version="SHA-512:d4ac90e3b0ac6b99a90d6053f08eaccec7266a9f434653ea2790d035a6bb04f4408831cbf8c71725c1595ce1651a69847ae2764d9a6201647b0831ce78fd0770"/>
<VersionInfo resourceName="Get-Url-Variables" version="SHA-512:b4a5dd888e335d53285434fded8d4d84d7e40fe76657e4d3cc3e2d245662fd7048fec80317db35b3a4bd340f2be7ba2902f268176f8aef6201810c1180ff1edc"/>
<VersionInfo resourceName="Remove-Key" version="SHA-512:b6fb9136a1298dcf9ce8b43499a435b65036ccb75dfaf769e4fab75da31df42160aa3d2a15d1e785bc30680c9bdb236265177144d8643ac96622a2c876bfe164"/>
<VersionInfo resourceName="Set-Firestore-Variables" version="SHA-512:32babd2deb3befbf46befd4d854a55e7e9ceb9e3abfe39b54628fdccb944bec37df81473c78f5205eda90ca1f1dd83dd850f652e71072d074b53f00dc96dcb0f"/>
<VersionInfo resourceName="Set-Verb" version="SHA-512:76784cb53c1295f9e2ac251f02e6eb26d9286347fb2fdfb90e82e72d294013f7d78cf5c0d33168bcb9f9dd2f6b9f557b8a6254c237ba8cc20ff74c0faa35c1f6"/>
<VersionInfo resourceName="Verify-API-Key-1" version="SHA-512:28cb2309eaccd38bee6b4efc4faa587ed762418dd22ff3bf3ae55660878f593e73af43854dfe0dd2b482a3522a59862620f935e366755089b2494bbde894ae4f"/>
<VersionInfo resourceName="set-request" version="SHA-512:0237b172885d6edaa7e8d2c84707e6dd4fbc62ed5e8ee69064db009c47a0622ae92946d3115df780055157e373bbed0d16f7c9f51afa81e9d2d3c20d6cde278a"/>
<VersionInfo resourceName="set-response" version="SHA-512:4c83ad5e2bb224e89afef7a4b97bb86c5d35619f27380745a928847a0d2ac4a3252d5e2d48fe622aedbbfda4741e6f1d44da98a43601622b946506e90ac92c2d"/>
</Policies>
<ProxyEndpoints>
<VersionInfo resourceName="default" version="SHA-512:827d0169b798a0c16bf27a591965504cc89b7c6ef6d466a799650926710922ddd73af8d6568148f5894742ef0dcbcc1240fce32923f6db53f0eb4da180a56049"/>
</ProxyEndpoints>
<Resources>
<VersionInfo resourceName="jsc://set-request.js" version="SHA-512:273a744f438d33ebf0349b156593fa9bdf972caaaefc3acc96bffedcd8cecb43e13c4b7b5ab8df4a8703f90967249f3ec5780896fcc5c9ec6edb1afb20b2cef2"/>
<VersionInfo resourceName="jsc://set-response.js" version="SHA-512:8406be79fa657b8c9ba3d755b27129b71395fba86b146eb37b6884fc000efba05ed287cac997c056834ebeb39f35f2bf4928c1fa4d36daa2c4142acaddee0d57"/>
</Resources>
<SharedFlows/>
<TargetEndpoints>
<VersionInfo resourceName="default" version="SHA-512:396130306b0d6d56e456ef651457aa11677bc4d2092fe7a57580aa2cd593ad1d116cc5cc94ca0684914093d8700cae1492c2474a8b0d0b5deb4e77bb4b3abe55"/>
</TargetEndpoints>
</Manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Add-Bearer-Token">
<DisplayName>Add Bearer Token</DisplayName>
<Properties/>
<Set>
<Headers>
<Header name="Authorization">Bearer {firestore.token}</Header>
</Headers>
<Path/>
</Set>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-2">
<DisplayName>Assign Message-2</DisplayName>
<Properties/>
<AssignVariable>
<Name>target.copy.pathsuffix</Name>
<Value>false</Value>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Token">
<DisplayName>Extract Token</DisplayName>
<Properties/>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<JSONPayload>
<Variable name="firestore.token">
<JSONPath>$.access_token</JSONPath>
</Variable>
</JSONPayload>
<Source clearPayload="false">google-token-response</Source>
<VariablePrefix/>
</ExtractVariables>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GenerateJWT async="false" continueOnError="false" enabled="true" name="Generate-JWT-1">
<Algorithm>RS256</Algorithm>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<PrivateKey>
<Value ref="private.gkey"/>
</PrivateKey>
<Subject ref="firestore.serviceemail"/>
<Issuer ref="firestore.serviceemail"/>
<Audience>https://www.googleapis.com/oauth2/v4/token</Audience>
<ExpiresIn>60m</ExpiresIn>
<Id/>
<AdditionalClaims>
<Claim name="scope">https://www.googleapis.com/auth/datastore</Claim>
</AdditionalClaims>
<OutputVariable>google-jwt</OutputVariable>
</GenerateJWT>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="Get-Token">
<DisplayName>Get-Google-Token</DisplayName>
<Properties/>
<Request clearPayload="true" variable="googletokenrequest">
<Set>
<Headers>
<Header name="Content-Type">application/x-www-form-urlencoded</Header>
</Headers>
<QueryParams>
<QueryParam name="grant_type">urn:ietf:params:oauth:grant-type:jwt-bearer</QueryParam>
<QueryParam name="assertion">{google-jwt}</QueryParam>
</QueryParams>
<FormParams/>
<Payload/>
<ReasonPhrase/>
<StatusCode/>
<Path/>
<Version>1.1</Version>
<Verb>POST</Verb>
</Set>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>google-token-response</Response>
<HTTPTargetConnection>
<Properties/>
<URL>https://www.googleapis.com/oauth2/v4/token</URL>
</HTTPTargetConnection>
</ServiceCallout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Get-Url-Variables">
<DisplayName>Get Url Variables</DisplayName>
<URIPath>
<Pattern ignoreCase="true">/{collection}</Pattern>
<Pattern ignoreCase="true">/{collection}/{document}</Pattern>
</URIPath>
<VariablePrefix>firestore</VariablePrefix>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<Source clearPayload="false">request</Source>
</ExtractVariables>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Remove-Key">
<DisplayName>Remove Key</DisplayName>
<Properties/>
<Remove>
<Headers>
<Header name="x-apikey"/>
</Headers>
</Remove>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Set-Firestore-Variables">
<DisplayName>Set Firestore Variables</DisplayName>
<Properties/>
<AssignVariable>
<Name>firestore.project</Name>
<Value>GCP_PROJECT</Value>
</AssignVariable>
<AssignVariable>
<Name>firestore.document</Name>
<Value/>
</AssignVariable>
<AssignVariable>
<Name>firestore.input</Name>
<Ref>request.content</Ref>
</AssignVariable>
<AssignVariable>
<Name>firestore.key</Name>
<Value>id</Value>
</AssignVariable>
<AssignVariable>
<Name>private.gkey</Name>
<Value>
GCP_SVC_KEY
</Value>
</AssignVariable>
<AssignVariable>
<Name>firestore.serviceemail</Name>
<Value>GCP_SVC_EMAIL</Value>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Set-Verb">
<DisplayName>Set-Verb</DisplayName>
<Properties/>
<Set>
<Verb>PATCH</Verb>
</Set>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyAPIKey async="false" continueOnError="false" enabled="false" name="Verify-API-Key-1">
<DisplayName>Verify API Key-1</DisplayName>
<Properties/>
<APIKey ref="request.header.x-apikey"/>
</VerifyAPIKey>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" name="set-request">
<DisplayName>set-request</DisplayName>
<Properties/>
<ResourceURL>jsc://set-request.js</ResourceURL>
</Javascript>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" name="set-response">
<DisplayName>set-response</DisplayName>
<Properties/>
<ResourceURL>jsc://set-response.js</ResourceURL>
</Javascript>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
<PreFlow name="PreFlow">
<Request>
<Step>
<Name>Set-Firestore-Variables</Name>
</Step>
<Step>
<Name>Verify-API-Key-1</Name>
</Step>
<Step>
<Name>Remove-Key</Name>
</Step>
<Step>
<Name>Get-Url-Variables</Name>
</Step>
<Step>
<Name>Generate-JWT-1</Name>
</Step>
<Step>
<Name>Get-Token</Name>
</Step>
<Step>
<Name>Extract-Token</Name>
</Step>
<Step>
<Condition>request.verb = "PUT" or request.verb = "POST"</Condition>
<Name>set-request</Name>
</Step>
<Step>
<Condition>request.verb = "PUT" or request.verb = "POST"</Condition>
<Name>Set-Verb</Name>
</Step>
</Request>
<Response/>
</PreFlow>
<Flows/>
<PostFlow name="PostFlow">
<Request/>
<Response>
<Step>
<Name>set-response</Name>
</Step>
</Response>
</PostFlow>
<HTTPProxyConnection>
<BasePath>/importantstuff</BasePath>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
</ProxyEndpoint>
Loading

0 comments on commit 6aad76c

Please sign in to comment.