<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Developer Journey</title>
	<atom:link href="http://devjourney.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://devjourney.com</link>
	<description>Kevin Hazzard&#039;s Blog</description>
	<lastBuildDate>Mon, 10 Sep 2018 18:00:16 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.1</generator>
	<item>
		<title>Cosmos DB Server-Side Primer &#8211; Episode 1</title>
		<link>http://devjourney.com/2018/09/10/cosmos-db-server-side-primer-episode-1/</link>
					<comments>http://devjourney.com/2018/09/10/cosmos-db-server-side-primer-episode-1/#comments</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Mon, 10 Sep 2018 18:00:16 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[CosmosDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[cosmosdb]]></category>
		<category><![CDATA[database]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=743</guid>

					<description><![CDATA[Stored procedures in Cosmos DB are JavaScript functions that run close to the data to ensure high performance. In addition to great performance, stored procedures provide multi-operation transaction support with automatic rollback when things don&#8217;t go as planned. In this episode, we&#8217;ll look at the server-side Collection and Response classes to learn how to create and update&#8230; <a class="more-link" href="http://devjourney.com/2018/09/10/cosmos-db-server-side-primer-episode-1/">Continue reading <span class="screen-reader-text">Cosmos DB Server-Side Primer &#8211; Episode 1</span></a>]]></description>
										<content:encoded><![CDATA[<p>Stored procedures in Cosmos DB are JavaScript functions that run close to the data to ensure high performance. In addition to great performance, stored procedures provide multi-operation transaction support with automatic rollback when things don&#8217;t go as planned. In this episode, we&#8217;ll look at the server-side <a href="https://azure.github.io/azure-cosmosdb-js-server/Collection.html" target="_blank" rel="noopener">Collection</a> and <a href="https://azure.github.io/azure-cosmosdb-js-server/Response.html" target="_blank" rel="noopener">Response</a> classes to learn how to create and update documents. Then we&#8217;ll practice deploying a stored procedure to Cosmos DB and executing it. Let&#8217;s start with a very simple example that demonstrates how to save a new document:</p>
<pre class="nums:false lang:js decode:true">__.createDocument(
  __.getSelfLink(),
  { name: "Oppenheimer" },
  function (err, newDoc) {
    __.response.setBody(newDoc.id)
  });</pre>
<p>This JavaScript creates a new, hard-coded document in the collection with &#8220;Oppenheimer&#8221; as the name value. The callback responds to the caller with the unique ID assigned to the document. If you&#8217;ve worked with JavaScript libraries like <a href="https://lodash.com/" target="_blank" rel="noopener">Lodash</a> or <a href="https://underscorejs.org/" target="_blank" rel="noopener">Underscore.js</a>, the double underscores in this example will feel familiar. However, if you haven&#8217;t worked libraries like those, the __ symbol might be off-putting. What is that?</p>
<p>Well, the __ symbol is just an alias for some important objects in the Cosmos DB server-side model. When you read other articles about authoring Cosmos DB stored procedures, you&#8217;ll sometimes see code expressed in a more verbose form. Here&#8217;s the same code shown above without using the __ alias:</p>
<pre class="nums:false lang:js decode:true">var context = getContext();
var collection = context.getCollection();
collection.createDocument(
  collection.getSelfLink(),
  { name: "Oppenheimer" },
  function (err, newDoc) {
    context.getResponse().setBody(newDoc.id)
  });</pre>
<p>Comparing the two versions side-by-side will help you understand how the __ alias works. There&#8217;s nothing right or wrong about either style. My advice is to use the one that gives you better comprehension. For me, the __ alias helps to clear away the visual clutter which improves my understanding when I&#8217;m composing server-side code in Cosmos DB so I use it all the time. In this example, the __ alias is being used for three operations:</p>
<ul>
<li>Creating a new document &#8211; __.createDocument(),</li>
<li>Getting the address of the current collection &#8211; __.getSelfLink(), and</li>
<li>Sending a response back to the caller &#8211; __.response.setBody().</li>
</ul>
<p>The intent of the code is to create a new database document and return the assigned unique identifier back to the caller. So calling __.createDocument() and __.response.setBody() to get those tasks accomplished makes sense. However, you may be wondering about that __.getSelfLink() call. What does that do? What is a <em>self link</em>, anyway? You can think of Cosmos DB links as unique addresses that refer to various objects in the ecosystem. Every object in Cosmos DB has a link. Databases have links. Collections have links. Documents have links. Attachments have links. Every linked object maintains a link to itself which are called a self-links, of course. As an example, here&#8217;s a simple document as it might be stored in Cosmos DB:</p>
<pre class="lang:default highlight:0 decode:true">{
    "message": "Hello Cosmos DB",
    "timestamp": "2018-09-08T21:01:25.494Z",
    "id": "bbd8d3db-8655-a7da-286e-50586cd39289",
    "_rid": "KqgHAMaKS9QBAAAAAAAAAA==",
    "_self": "dbs/KqgHAA==/colls/KqgHAMaKS9Q=/docs/KqgHAMaKS9QBAAAAAAAAAA==/",
    "_etag": "\"0100b33c-0000-0000-0000-5b9438a60000\"",
    "_attachments": "attachments/",
    "_ts": 1536440486
}</pre>
<p>Line 6 shows the self-link to the document, appropriately named <em>_self</em>. Let&#8217;s look at the shape of the document self-link:</p>
<pre class="nums:false lang:default highlight:0 decode:true">dbs/{db_id}/colls/{collection_id}/docs/{doc_id}/</pre>
<p>If you have a document link in hand, its self-link is the document link minus the <strong>docs</strong> portion:</p>
<pre class="nums:false lang:default highlight:0 decode:true">dbs/{db_id}/colls/{collection_id}/</pre>
<p>And similarly, the collection&#8217;s database link is its self-link minus the <strong>colls</strong> part:</p>
<pre class="nums:false lang:default highlight:0 decode:true">dbs/{db_id}/</pre>
<p>Now it&#8217;s time to make the code snippet deployable. To transform it into a valid stored procedure, first place it into a parameterized function:</p>
<pre class="nums:false lang:js decode:true">function(doc) {
  __.createDocument(__.getSelfLink(),
    doc,
    function (err, newDoc) {
        __.response.setBody(newDoc.id)
    });
}</pre>
<p>Instead of saving hard-coded documents about Oppenheimer, we can call this stored procedure to save any sort of JSON document to the collection. But how? The function is anonymous. How can we call the stored procedure from an external system if it has no name?</p>
<p>When you create stored procedures in Cosmos DB, the names by which they are published and invoked isn&#8217;t expressed in JavaScript. Instead, the names are bits of metadata that can be described in JSON like this:</p>
<pre class="lang:js decode:true ">var procedureDef = {
  id: "SaveADocument",
  body: function(doc) {
    __.createDocument(__.getSelfLink(),
      doc,
      function (err, newDoc) {
        __.response.setBody(newDoc.id)
      });
  }
}</pre>
<p>See the source code in the body while the name of the procedure is the id property. In other languages that don&#8217;t speak JSON natively, the body (the source code) will be expressed as a string whenever you create or update a stored procedure. Now, let&#8217;s use <a href="https://code.visualstudio.com/" target="_blank" rel="noopener">Visual Studio Code</a> and a small <a href="https://nodejs.org/" target="_blank" rel="noopener">Node.js</a> application to deploy the stored procedure and invoke it.</p>
<blockquote><p>You might want to use Python, Java or C# to interact with Cosmos DB instead. All those languages are at home in Visual Studio Code and all of them have first-class SDKs. Check out <a href="https://www.gotcosmos.com/" target="_blank" rel="noopener">GotCosmos.com</a> for some great samples and tutorials for working with Cosmos DB from those languages.</p></blockquote>
<p>With both Code and Node installed on your Windows, Mac or Linux workstation, issue the following commands in a terminal window to create a new project directory, initialize it, and start the Code editor:</p>
<pre class="nums:false lang:default highlight:0 decode:true ">mkdir UpsertCosmosSP
cd UpsertCosmosSP
touch index.js config.js
npm init
npm install @azure/cosmos
code .</pre>
<p>If you&#8217;re running Windows which has no touch command, try these two statements to create the empty index.js and config.js files instead:</p>
<pre class="nums:false lang:default highlight:0 decode:true ">type nul &gt;&gt; index.js
type nul &gt;&gt; config.js</pre>
<p>In Code, add these exports to the config.js file:</p>
<pre class="lang:js decode:true ">exports.connection = {
    endpoint: 'https://localhost:8081',
    authKey: 'C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=='
};

exports.names = {
    database: 'DELETE_ME_SOON',
    collection: 'Playground',
};</pre>
<p>This configuration assumes that you&#8217;re using the <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator" target="_blank" rel="noopener">Cosmos DB Emulator</a> running on port 8081 of the local machine and using the default master key. However, the emulator only runs on Windows 10 or Windows Server 2016 at the time of this writing.</p>
<p>If you want or need to use a real Cosmos DB account in the Azure cloud, you&#8217;ll have to replace the connection endpoint and authKey with your own. In that case, use the Cosmos DB blade in the <a href="https://portal.azure.com" target="_blank" rel="noopener">Azure Portal</a> to create a new account or locate an existing one where you have read-write access. From the account&#8217;s Keys page, fetch the read-write endpoint URI and the primary or secondary key, replacing the endpoint and authKey values in the config.js file.</p>
<p>You may also change the database name and the collection name in the configuration file if you like. If you leave them as shown, the application will automatically create a new database called DELETE_ME_SOON in your Cosmos DB account. In that new database, a collection named Playground will also be created as needed. That&#8217;s where the stored procedure will be deployed along with any documents you create during the test runs of the application below.</p>
<p>In the index.js file, add the following application code. The full source code for this example is also available <a href="https://gist.github.com/devjourney/34c7b514f8f86b28b6a079354b80182b" target="_blank" rel="noopener">on Github</a>.</p>
<pre class="lang:js decode:true">var CosmosClient = require('@azure/cosmos').CosmosClient;
var config = require('./config.js');
var client = new CosmosClient({
    endpoint: config.connection.endpoint,
    auth: { masterKey: config.connection.authKey }
});

async function upsertProcedureAndExecute(sprocDef, docToInsert) {
    const { database } = await client.databases
        .createIfNotExists({ id: config.names.database });
    const { container } = await database.containers
        .createIfNotExists({ id: config.names.collection });
    const { sproc } = await container.storedProcedures.upsert(sprocDef);
    const { body: results, headers } = await sproc.execute(docToInsert);
    if (headers &amp;&amp; headers['x-ms-request-charge'])
        console.log(`Charge = ${headers['x-ms-request-charge']} RU`);
    if (results)
        console.log(`DocID = ${JSON.stringify(results)}`);
    // comment in the next line to delete the database
    // await database.delete();
}

var docToSave = {
    message: 'Hello Cosmos DB',
    timestamp: (new Date()).toISOString()
};

var procedureDef = {
    id: 'saveDocument',
    body: function (doc) {
        __.createDocument(__.getSelfLink(),
            doc,
            function (err, newDoc) {
                __.response.setBody(newDoc.id)
            });
    }
};

upsertProcedureAndExecute(procedureDef, docToSave)
    .catch((err) =&gt; { console.error(JSON.stringify(err)); });</pre>
<p>Lines 1 &#8211; 6 load the configuration file and instantiate the Cosmos DB client. Lines 8  &#8211; 21 define the upsertProcedureAndExecute function which starts by creating the database named in the configuration file if it doesn&#8217;t already exist. Similarly, the collection will be created as necessary. Then the stored procedure is upserted to the collection. The term <em>upsert</em> in the context of deploying a stored procedure means that if the procedure doesn&#8217;t already exist by the provided id, it will be created. If it does exist, it will be overwritten with the source code you provide.</p>
<p>Lastly, the stored procedure is invoked with the document to be saved. The request charge (expressed in Cosmos DB <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/request-units" target="_blank" rel="noopener">Resource Units</a>) will be fetched from a response header and logged to the console along with the unique ID assigned to the new document.</p>
<blockquote><p>When I&#8217;m doing development in Cosmos DB, I find that it&#8217;s useful to watch the request charges. Knowing how expensive various operations are as you move along is a good way to stay connected to the performance of your database.</p></blockquote>
<p>You can run the application from the command line by executing &#8220;node index.js&#8221; in a terminal window which should output something like this to the console:</p>
<pre class="nums:false lang:default highlight:0 decode:true">Charge = 5.45 RU
DocID = "8c6ec318-ed0a-3c02-216b-bc5161bfc5ba"</pre>
<p>You can also run the application in the Visual Studio Code debugger by pressing F5 or clicking Debug / Start Debugging from the menu. The Code debugger for Node.js is very rich, allowing you to set breakpoints, interactively inspect variables and the call stack, evaluate expressions and much more.</p>
<p>You&#8217;ve observed that if you save a document to a Cosmos DB collection without an <strong>id</strong> property, an id will be created for it, as a <a href="https://en.wikipedia.org/wiki/Universally_unique_identifier" target="_blank" rel="noopener">GUID</a> in string form. However, while every document saved to a Cosmos DB collection must have a unique id, they aren&#8217;t required to be GUIDs or follow any other specific pattern for that matter. They only need to have unique values. Try saving a document with an id of your own by replacing the docToSave object in the sample app with something like this:</p>
<pre class="nums:false lang:js highlight:0 decode:true">var docToSave = {
    message: 'Hello Cosmos DB',
    id: 'testing123',
    timestamp: (new Date()).toISOString()
};</pre>
<p>The first time you save the document by invoking the SaveADocument stored procedure, it will work correctly because no document with the id &#8216;testing123&#8217; already exists. However, if you run it again, you&#8217;ll get an exception saying something like:</p>
<pre class="nums:false lang:default highlight:0 decode:true">TypeError: Unable to get property 'id' of undefined or null reference</pre>
<p>The error message isn&#8217;t super helpful but it does indicate that there&#8217;s something wrong with the &#8216;id&#8217; property. In this case, we&#8217;ve attempted to violate a uniqueness constraint within the collection during the second invocation of the  __.createDocument() method. If it&#8217;s your intent to allow callers to replace existing documents that way, simply change the stored procedure definition to call __.upsertDocument() instead of __.createDocument() like this:</p>
<pre class="lang:js decode:true ">var procedureDef = {
    id: 'saveDocument',
    body: function (doc) {
        __.upsertDocument(__.getSelfLink(),
            doc,
            function (err, newDoc) {
                __.response.setBody(newDoc.id)
            });
    }
};</pre>
<p>Now you can call the stored procedure over and over with documents having the same id value without errors and watch the timestamps and other properties change each time you do so.</p>
<p>Before I finish this article, I need to address something I&#8217;ve been doing wrong from the beginning. As it turns out, things can go wrong when you use complex, networked computing systems. We need to account for the various error conditions that might occur. Moreover, as a multi-tenant database, Cosmos DB has a range of constraints that dictate how stored procedures must behave. Based on so-called bounded execution rules, Cosmos DB may decide that it cannot accept your request at the current time. If that happens, we should obey and convey that information back to the caller. Here&#8217;s an updated procedure definition that handles both the error and non-acceptance cases:</p>
<pre class="lang:js decode:true ">var procedureDef = {
    id: 'saveDocument',
    body: function (doc) {
        var accepted = __.upsertDocument(__.getSelfLink(),
            doc,
            function (err, newDoc) {
                if (err) throw err;
                __.response.setBody({ id: newDoc.id, completed: true })
            });
        if (!accepted) __.response.setBody({ completed: false });
    }
};</pre>
<p>If you save this version of the stored procedure, you&#8217;ll see that a Boolean flag is returned in non-error cases that indicates whether or not the upsert operation was allowed to complete. Also, if errors occur, they&#8217;ll be thrown back to the server-side engine which will roll back the current transaction. Cosmos DB&#8217;s automatic rollback of transactions depends on our throwing exceptions when things don&#8217;t go as planned.</p>
<blockquote><p>A gentle reminder: if you created a Cosmos DB collection in the cloud as part of this exercise, please be sure to delete it if you don&#8217;t want to incur any ongoing charges once you&#8217;ve completed the exercise.</p></blockquote>
<p>In the next article in this series, we&#8217;ll round out our examination of the basic document-oriented functions in the Collection class like __.queryDocuments and __.deleteDocument. We&#8217;ll also dive into continuations, another key concept related to working nicely within Cosmos DB&#8217;s bounded execution rules.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2018/09/10/cosmos-db-server-side-primer-episode-1/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Shape CosmosDB Output with JMESPath</title>
		<link>http://devjourney.com/2018/09/02/shape-cosmosdb-output-with-jmespath/</link>
					<comments>http://devjourney.com/2018/09/02/shape-cosmosdb-output-with-jmespath/#comments</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Sun, 02 Sep 2018 17:24:34 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[CosmosDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[cosmosdb]]></category>
		<category><![CDATA[database]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=733</guid>

					<description><![CDATA[According to James Saryerwinie, his truly awesome query language for JSON is pronounced James Path. I trust him on the pronunciation of JMESPath. Besides, when I used to say &#8220;Jay-mezz Path,&#8221; it just sounded wrong to me. I fell in love with JMESPath using the Azure CLI. Many of the Azure CLI commands support a&#8230; <a class="more-link" href="http://devjourney.com/2018/09/02/shape-cosmosdb-output-with-jmespath/">Continue reading <span class="screen-reader-text">Shape CosmosDB Output with JMESPath</span></a>]]></description>
										<content:encoded><![CDATA[<p>According to <a href="https://github.com/jamesls" target="_blank" rel="noopener">James Saryerwinie</a>, his truly awesome query language for JSON is pronounced <a href="https://github.com/jmespath/jmespath.py" target="_blank" rel="noopener"><em>James Path</em></a>. I trust him on the pronunciation of <a href="http://jmespath.org/" target="_blank" rel="noopener">JMESPath</a>. Besides, when I used to say &#8220;Jay-mezz Path,&#8221; it just sounded wrong to me.</p>
<p>I fell in love with JMESPath using the <a href="https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest" target="_blank" rel="noopener">Azure CLI</a>. Many of the Azure CLI commands support a &#8211;query parameter which can be used to filter and shape the output using JMESPath expressions. Adam Raffe has a good blog post on <a href="https://adamraffe.com/2017/11/22/the-wonderful-world-of-azure-cli-jmespath-queries/" target="_blank" rel="noopener">using JMESPath in the Azure CLI</a> which you should read to learn more. But here&#8217;s a sample to illustrate how useful JMESPath is. Imagine that you want to list all the Redis Cache instances in a subscription. Maybe you start with this command:</p>
<pre class="striped:false nums:false wrap:true lang:default highlight:0 decode:true" title="The Azure CLI command to list all Redis Cache instances in the current subscription.">$ az redis list</pre>
<p>The output is large. Here&#8217;s the JSON for a single node:</p>
<pre class="lang:default decode:true" title="One Redis Cache node from the Azure CLI command to list all instances.">[
  {
    "accessKeys": null,
    "enableNonSslPort": false,
    "hostName": "abc01.redis.cache.windows.net",
    "id": "/subscriptions/432a801f-3521-4752-9445-40610812027e/resourceGroups/ABC-WebApp/providers/Microsoft.Cache/Redis/abc01",
    "linkedServers": [],
    "location": "West US",
    "name": "abc01",
    "port": 6379,
    "provisioningState": "Succeeded",
    "redisConfiguration": {
      "maxclients": "256",
      "maxmemory-delta": "2",
      "maxmemory-reserved": "2"
    },
    "redisVersion": "3.2.7",
    "resourceGroup": "ABC-WebApp",
    "shardCount": null,
    "sku": {
      "capacity": 0,
      "family": "C",
      "name": "Basic"
    },
    "sslPort": 6380,
    "staticIp": null,
    "subnetId": null,
    "tags": {},
    "tenantSettings": null,
    "type": "Microsoft.Cache/Redis",
    "zones": null
  }
]</pre>
<p>Imagine if you had many Redis Cache instances in your subscription. The output would be unwieldy. The chances are good that you don&#8217;t need all the information that&#8217;s returned. Perhaps you&#8217;re only interested in name of the server and the SSL port. And let&#8217;s suppose that you only want information on instances that have &#8220;abc&#8221; in the name. JMESPath to the rescue:</p>
<pre class="striped:false nums:false wrap:true lang:default highlight:0 decode:true" title="Adding a JMESPath query to the Azure CLI command to filter and shape the output.">$ az redis list --query "[?contains(name,'abc')].{ server: hostName, port: sslPort }"</pre>
<p>This query returns only those elements in the response that contain &#8220;abc&#8221; in the name. It then shapes the output to include only the hostName and sslPort, naming them server and port. The simplified output looks like this:</p>
<pre class="lang:default decode:true">[
  {
    "port": 6380,
    "server": "abc01.redis.cache.windows.net"
  }
]</pre>
<p>That&#8217;s both nice for reading and skinny on the wire. What if you could offer the callers of your Cosmos DB-based APIs the ability to filter and shape the output like this? If I were using the Cosmos DB Table API, <a href="https://docs.microsoft.com/en-us/azure/cosmos-db/tutorial-query-table" target="_blank" rel="noopener">OData and LINQ</a> are available to accomplish that sort of thing. But with the SQL API, we&#8217;ll have to write a bit of code. Consider this simple <a href="https://gist.github.com/devjourney/3993db636d9670d6fb7fd9b6657a2924" target="_blank" rel="noopener">Node.js function</a> to fetch information about U.S. weather stations:</p>
<pre class="lang:js decode:true" title="Node.js function to fetch weather data.">let documentClient = require('documentdb').DocumentClient;
let cosmos_uri = process.env["STATION_COSMOS_URI"];
let cosmos_key = process.env["STATION_COSMOS_READONLY_KEY"];
let databaseId = process.env["STATION_COSMOS_DATABASE_NAME"];
let collectionId = process.env["STATION_COSMOS_COLLECTION_NAME"];
let client = new documentClient(cosmos_uri, { 'masterKey': cosmos_key });
let collectionLink = "/dbs/" + databaseId + "/colls/" + collectionId + "/";

module.exports = function (context, req) {
  let filterQuery = `SELECT * FROM c WHERE c.State = "${req.params.state}"`;
  try {
    let queryIterator = client.queryDocuments(collectionLink, filterQuery);
    queryIterator.toArray(function (err, matchingDocuments) {
      if (err) {
        context.done(err);
        return;
      }
      context.done(null, { status: 200, body: matchingDocuments, headers: { 'Content-Type': 'application/json' }});
    });
  } catch (ex) {
    context.done(ex);
  }
};</pre>
<p>The function requires that you pass the U.S. state to limit the results. Let&#8217;s fetch the weather stations in the state of Virginia:</p>
<pre class="striped:false nums:false lang:default highlight:0 decode:true " title="Invoking the weather station API with a state code.">https://weatherapi.azurewebsites.net/api/StationQuery/state/VA</pre>
<p>This operation returns information about several dozen weather stations in Virginia. It&#8217;s a long list but here&#8217;s the first one to show you how the records are shaped:</p>
<pre class="lang:default decode:true">[
    {
        "WBAN": "00120",
        "WMO": null,
        "CallSign": "JFZ",
        "ClimateDivisionCode": null,
        "ClimateDivisionStateCode": 44,
        "ClimateDivisionStationCode": null,
        "Name": "CLAYPOOL HILL",
        "State": "VA",
        "Location": "TAZEWELL COUNTY AIRPORT",
        "Latitude": 37.067,
        "Longitude": -81.8,
        "GroundHeight": 2651,
        "StationHeight": 0,
        "Barometer": 0,
        "TimeZone": -5,
        "id": "655785f7-92d5-74cb-c1db-52df225a2ee5"
    }
]</pre>
<p>Now suppose we want to query only for the stations below 20 feet of ground elevation. Of course, we could modify the Node.js function to accept extra predicates, attaching them to the WHERE clause. With Cosmos DB, that&#8217;s a pretty safe thing to do since there are no INSERT, UPDATE, DELETE, ALTER and DROP statements in the language that could be injected to do harm. In fact, appending the U.S. state to the SELECT statement as shown above is quite safe in Cosmos DB. If a hacker tried to inject something malicious through the URL, at best they&#8217;d get back junk. More likely than not, the query would just fail since there&#8217;s no way to modify the data or the configuration of a Cosmos DB with a classic SQL injection attack.</p>
<p>In considering whether or not to allow API users to add new SQL predicates, we must ask ourselves:</p>
<ol>
<li>Why make our API users learn how to construct SQL predicates?</li>
<li>What if we want to change the implementation from SQL API to something else?</li>
</ol>
<p>Having an abstraction like OData or JMESPath that sits atop the API for filtering and projection makes a lot of sense. Using JMESPath, here&#8217;s the URL we&#8217;d like to be able to send to fetch all the weather stations in Virginia below 20 feet of ground elevation:</p>
<pre class="striped:false nums:false wrap:true lang:default highlight:0 decode:true" title="Query for the weather stations in Virginia below 20 feet of ground elevation.">https://weatherapi.azurewebsites.net/api/StationQuery/state/VA?query=[?GroundHeight &lt; `20`]</pre>
<p>It&#8217;s surprisingly easy to add this functionality to the Node.js function. After importing JMESPath, check for the new query parameter in the iterator and execute it as a JMESPath search:</p>
<pre class="lang:default decode:true" title="Look for a query parameter named query and execute it on the results as a JMESPath expression.">if (req.query &amp;&amp; req.query.query) {
  try {
    matchingDocuments = jmespath.search(matchingDocuments, req.query.query);
  }
  catch (ex) {
    context.done(ex);
    return;
  }
}</pre>
<p>Here&#8217;s <a href="https://gist.github.com/devjourney/35451c0eb50f48f58f2b10780bc06a53" target="_blank" rel="noopener">the full source code</a> of the updated function on GitHub. With that change in place, the URL that restricts the results to those weather stations below 20 feet of elevation now returns only six stations in Virginia, not dozens of them. However, we&#8217;re not quite done. Imagine that we want to trim down the JSON response to include only the location and the geographic coordinates of the matching records. Let&#8217;s try this URL and see how JMESPath handles it:</p>
<pre class="striped:false nums:false wrap:true lang:default highlight:0 decode:true" title="For the weather stations in Virginia below 20 feet of elevation, return only the location and geo data.">https://weatherapi.azurewebsites.net/api/StationQuery/state/VA?query=[?GroundHeight &lt; `20`].{ description: Location, geo: { latitude: Latitude, longitude: Longitude } }</pre>
<p>Here&#8217;s the much smaller output:</p>
<pre class="lang:default decode:true" title="Just the location and geo data for weather stations in Virginia below 20 feet of ground elevation.">[
    {
        "description": "LANGLEY AFB AIRPORT",
        "geo": {
            "latitude": 37.0828,
            "longitude": -76.3603
        }
    },
    {
        "description": "RONALD REAGAN WASHINGTON NATL AP",
        "geo": {
            "latitude": 38.8472,
            "longitude": -77.0345
        }
    },
    {
        "description": "NORFOLK NAS",
        "geo": {
            "latitude": 36.9375,
            "longitude": -76.2893
        }
    },
    {
        "description": "NAVAL AUXILIARY LANDING FIELD",
        "geo": {
            "latitude": 36.695,
            "longitude": -76.1356
        }
    },
    {
        "description": "QUANTICO MCAF",
        "geo": {
            "latitude": 38.5036,
            "longitude": -77.305
        }
    },
    {
        "description": "FELKER ARMY AIRFIELD",
        "geo": {
            "latitude": 37.1333,
            "longitude": -76.6
        }
    }
]</pre>
<p>Excellent. I&#8217;ll leave you with a few tips. First of all, executing an extra filtering type operation on result sets that have already been reduced with server-side query predicates can be wasteful. For this article, I deliberately chose to layer JMESPath functionality on top of a U.S. state-based weather station API because I know that the result sets from the original query will always be very small. Each U.S. state has a few dozen official weather stations, most of them positioned at medium- to large-sized airports or government buildings. Even California, which has the largest number of weather stations among all the states, has only about 100 of them. Querying for a few dozen records and filtering some of them out with JMESPath isn&#8217;t terribly wasteful in the grand scheme of things.</p>
<p>However, if your API is going to query against larger result sets or if the volume of activity on your filtering API is high enough, you should consider attaching the user&#8217;s predicates and/or their output-shaping projections onto the original database queries for efficiency. In parting, I&#8217;ll leave you with the Cosmos DB query that implements the filtering and projection from the example above:</p>
<pre class="striped:false nums:false wrap:true lang:tsql highlight:0 decode:true " title="The Cosmos DB query for Virginia weather station below 20 feet of ground elevation, returning only the location and geo data.">SELECT VALUE { description: c.Location, geo: { latitude: c.Latitude, longitude: c.Longitude } } FROM c WHERE c.State = "VA" AND c.GroundHeight &lt; 20</pre>
<p>This produces an output that&#8217;s identical to our JMESPath powered API. If this query expression were passed through to Cosmos DB, we wouldn&#8217;t need JMESPath at all. But your application (or your users) would need to understand SQL syntax. And you would have some difficulty moving away from SQL-based queries in the future if you wanted to do so. Food for thought, as we say.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2018/09/02/shape-cosmosdb-output-with-jmespath/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Generating Cosmos DB Auth Tokens in Postman</title>
		<link>http://devjourney.com/2018/07/31/generating-cosmos-db-auth-tokens-in-postman/</link>
					<comments>http://devjourney.com/2018/07/31/generating-cosmos-db-auth-tokens-in-postman/#respond</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Tue, 31 Jul 2018 05:46:52 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[CosmosDB]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[cosmosdb]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[serverless]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=716</guid>

					<description><![CDATA[If you read the official article that describes how access control works in Cosmos DB, you&#8217;ll see this handy Node.js function for generating authentication tokens using a master key: var crypto = require("crypto"); function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceId, date, masterKey) { var key = new Buffer(masterKey, "base64"); var text = (verb &#124;&#124; "").toLowerCase() + "\n" + (resourceType&#8230; <a class="more-link" href="http://devjourney.com/2018/07/31/generating-cosmos-db-auth-tokens-in-postman/">Continue reading <span class="screen-reader-text">Generating Cosmos DB Auth Tokens in Postman</span></a>]]></description>
										<content:encoded><![CDATA[<p>If you read the official <a href="https://docs.microsoft.com/en-us/rest/api/cosmos-db/access-control-on-cosmosdb-resources" target="_blank" rel="noopener noreferrer">article that describes how access control works</a> in Cosmos DB, you&#8217;ll see this handy Node.js function for generating authentication tokens using a master key:</p>
<pre class="lang:js decode:true" title="JavaScript for Generating Cosmos DB Auth Tokens">var crypto = require("crypto");  

function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceId, date, masterKey) {  
    var key = new Buffer(masterKey, "base64");  
    var text = (verb || "").toLowerCase() + "\n" +   
               (resourceType || "").toLowerCase() + "\n" +   
               (resourceId || "") + "\n" +   
               date.toLowerCase() + "\n" +   
               "" + "\n";  
    var body = new Buffer(text, "utf8");  
    var signature = crypto.createHmac("sha256", key).update(body).digest("base64");  
    var MasterToken = "master";  
    var TokenVersion = "1.0";  
    return encodeURIComponent("type=" + MasterToken + "&amp;ver=" + TokenVersion + "&amp;sig=" + signature);  
}</pre>
<p>That&#8217;s nice. However, what if I want to generate a Cosmos DB auth token in a Postman pre-request script? The built-in Node.js crypto module isn&#8217;t available in Postman but CryptoJS is. This <a href="https://gist.github.com/devjourney/04468859b7d6e1171a802ee5d4c79092" target="_blank" rel="noopener">version of the script</a> which does a few encodings the CryptoJS way should do the trick:</p>
<pre class="lang:js decode:true" title="Postman Script for Generating a Cosmos DB Auth Token">var now = new Date().toUTCString();
pm.environment.set("utcDate", now);

var verb = 'GET';
var resourceType = pm.variables.get("resourceType");
var resourceId = pm.variables.get("resourceId");

var text = (verb || "").toLowerCase() + "\n" + (resourceType || "").toLowerCase() + "\n" + (resourceId || "") + "\n" + now.toLowerCase() + "\n" + "" + "\n";
var key = CryptoJS.enc.Base64.parse(pm.variables.get("masterKey"));
var signature = CryptoJS.HmacSHA256(text, key).toString(CryptoJS.enc.Base64);

var MasterToken = "master";
var TokenVersion = "1.0";
var authToken = encodeURIComponent("type=" + MasterToken + "&amp;ver=" + TokenVersion + "&amp;sig=" + signature);

pm.environment.set("authToken", authToken);
</pre>
<p>For the script to work, you&#8217;ll need to define a few variables in a Postman environment file:</p>
<ul>
<li>utcDate &#8211; this will be set by the script. It&#8217;s used in the calculation of the auth token and will also be placed into an HTTP header named x-ms-date.</li>
<li>masterKey &#8211; don&#8217;t be stupid. Production secrets shouldn&#8217;t be stored in a Postman environment file. Copy the primary or secondary master key from your Cosmos DB account into this variable. If you&#8217;re only performing GET operations, you should be able to use a read-only key here.</li>
<li>authToken &#8211; this will be computed by the script and placed into the Authorization HTTP header.</li>
<li>resourceId &#8211; the path to the object(s) you want to reference. For example, I have a database named Finance with a collection named Investors. The resourceId would be set to &#8220;dbs/Finance/colls/Investors&#8221; in that case.</li>
<li>resourceType &#8211; the type of resource you wish to access. If I&#8217;m after documents, I&#8217;ll save &#8220;docs&#8221; here. See the Cosmos DB documentation for other resource types such as &#8220;dbs&#8221; or &#8220;colls&#8221;.</li>
</ul>
<p>One value I was not able to fetch from the Postman Sandbox was the HTTP method of the current request. Unfortunately I hard-coded that in the script to &#8220;GET&#8221; for now. If you know how to obtain that value using the <a href="https://www.getpostman.com/docs/v6/postman/scripts/postman_sandbox_api_reference" target="_blank" rel="noopener noreferrer">Sandbox API</a>, let me know and I&#8217;ll update this article.</p>
<p>As the Cosmos DB <a href="https://docs.microsoft.com/en-us/rest/api/cosmos-db/common-cosmosdb-rest-request-headers" target="_blank" rel="noopener noreferrer">documentation explains</a>, there are a few required headers when making calls through Cosmos DB&#8217;s REST API. It&#8217;s worth mentioning a few of them here:</p>
<ul>
<li>x-ms-date &#8211; the UTC date that&#8217;s also used in the computation of the auth token. Since the pre-request script captures this and places it in the environment file, that same variable can (and should be) used to send this header.</li>
<li>x-ms-version &#8211; the latest version of the Cosmos DB REST API is 2017-02-22 so I hard-coded that. See the <a href="https://docs.microsoft.com/en-us/rest/api/cosmos-db/" target="_blank" rel="noopener noreferrer">Cosmos DB documentation</a> for other versions and the features they introduced.</li>
<li>Authorization &#8211; set by the execution of the pre-request script. Interestingly, Cosmos DB Authorization headers have no <em>scheme</em> named in them which is something of a no-no <a href="https://tools.ietf.org/html/rfc7235#page-9" target="_blank" rel="noopener noreferrer">per the HTTP specification</a>.</li>
</ul>
<p>Now, set the address for Postman to fetch to:</p>
<p><strong>https://&lt;&lt;account&gt;&gt;.documents.azure.com/{{resourceId}}/{{resourceType}}</strong></p>
<p>Where &lt;&lt;account&gt;&gt; is your Cosmos DB account name and {{resourceId}} and {{resouceType}} are resolved from the environment file as described above. When you send the request, you should get back the objects you&#8217;ve requested. If you&#8217;ve requested a lot of documents with your query, you may get an HTTP response header called x-ms-continuation <a href="https://docs.microsoft.com/en-us/rest/api/cosmos-db/common-cosmosdb-rest-response-headers" target="_blank" rel="noopener noreferrer">as described here</a> which would require you to use the continuation pattern to get more results.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2018/07/31/generating-cosmos-db-auth-tokens-in-postman/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>HTTP 404 for Missing API Resources</title>
		<link>http://devjourney.com/2017/05/22/http-404-for-missing-api-resources/</link>
					<comments>http://devjourney.com/2017/05/22/http-404-for-missing-api-resources/#comments</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Tue, 23 May 2017 01:53:06 +0000</pubDate>
				<category><![CDATA[API Management Policy Language]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[cloud]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=505</guid>

					<description><![CDATA[Should an API return HTTP 404 status when the specified resource cannot be found? Of course, that&#8217;s exactly what (Not Found) means. As RFC2616 states pretty clearly, 404 Not Found means: The server has not found anything matching the Request-URI. However, if you think APIs are like web pages, you might be perplexed by such&#8230; <a class="more-link" href="http://devjourney.com/2017/05/22/http-404-for-missing-api-resources/">Continue reading <span class="screen-reader-text">HTTP 404 for Missing API Resources</span></a>]]></description>
										<content:encoded><![CDATA[<p>Should an API return HTTP 404 status when the specified resource cannot be found? Of course, that&#8217;s exactly what (Not Found) means. As <a href="https://www.ietf.org/rfc/rfc2616.txt" target="_blank" rel="noopener noreferrer">RFC2616</a> states pretty clearly, 404 Not Found means:</p>
<blockquote><p>The server has not found anything matching the Request-URI.</p></blockquote>
<p>However, if you think APIs are like web pages, you might be perplexed by such an interpretation. Maybe 404 <em>feels</em> like an error because it connotes that something went wrong with the <em>web app</em>. Oh no, the page wasn&#8217;t found! The world is coming to an end! Run for the hills! Save the women and children!</p>
<p>But APIs aren&#8217;t web apps, are they? They aren&#8217;t pages at all. APIs are cacheable, uniformly-addressable, resource-oriented interfaces. Given the address for a resource, if it&#8217;s not available, the API should return the HTTP 404 status in most cases.</p>
<p>Unfortunately, there&#8217;s so much momentum around the idea of 404 being an error condition that it&#8217;s really hard to get developers to think differently about how the web is supposed to work. Monitoring tools, log indexers and server health checks don&#8217;t help much for changing minds. So many of these tools dutifully treat 404 as an error condition that well-meaning API developers can&#8217;t see outside of the little boxes into which they&#8217;ve been coaxed.</p>
<p>One of the most troubling manifestations of this page-oriented bias is Microsoft Azure&#8217;s App Service server health check. Deploying a pure Web API to an Azure App Service, you&#8217;ll find that you&#8217;re subject to all sorts of page-specific constructs related to health. Most notably, if you return HTTP 404 from a server too often, the health checks will mark the instance as failing. Obviously, if pages are missing, something&#8217;s clearly wrong with that one naughty instance out of ten. The sheer narrow-mindedness of that idea just boggles my mind given that all the servers run the same code and connect to the same resources by definition.</p>
<p>If this incorrect behavior meant that Azure simply recycled instances more often than it needed to, that wouldn&#8217;t be too high a price to pay for their pedantic interpretation of the HTTP specification. Unfortunately, we don&#8217;t stop paying the price there. The standard load balancer for Azure App Service seems to be completely perplexed when specific server instances are marked as unhealthy. Performance degrades quickly as more and more instances are quarantined and taken out of rotation while new ones have to be created and spun up. What a mess!</p>
<p>If you&#8217;re using a managed API gateway like Azure API Management (APIM), there&#8217;s a fairly elegant way to deal with this particular problem. Have your API return 200-series statuses for these conditions, keeping the health checks ignorant and happy, then translate the outbound HTTP statuses to the ones you really want to convey at the edge. Here&#8217;s some outbound policy you can add to your API to pick up a special response header named RealHttpStatus and return that instead.</p>
<pre class="lang:default decode:true" title="API Management Outbound Policy to Return 404 Status">&lt;outbound&gt;
  &lt;set-variable name="realHttpStatus" value="@(Convert.ToInt32(context.Response.Headers.GetValueOrDefault("RealHttpStatus", "0")))" /&gt;
  &lt;set-header name="RealHttpStatus" exists-action="delete" /&gt;
  &lt;base /&gt;
  &lt;choose&gt;
    &lt;when condition="@(context.Variables.GetValueOrDefault&lt;int&gt;("realHttpStatus") == 404)"&gt;
      &lt;set-status code="@(context.Variables.GetValueOrDefault&lt;int&gt;("realHttpStatus"))" reason="Not Found" /&gt;
    &lt;/when&gt;
    &lt;otherwise&gt;&lt;/otherwise&gt;
  &lt;/choose&gt;
&lt;/outbound&gt;</pre>
<p>The policy begins by fetching the special response header called RealHttpStatus if it exists. The API should inject this header whenever it means to return something that might be misinterpreted or mishandled by the application server&#8217;s management tools. Next, the policy removes the special header so clients won&#8217;t see how our chicanery was perpetrated. Lastly, if the integer value of the special header is 404, the actual status returned by APIM will be 404, regardless of what the back end actually provided via the actual HTTP status code.</p>
<p>Of course, this policy&#8217;s &lt;choose&gt; element can be extended to include as many other interesting HTTP status types as you might require. Your API can go on respecting HTTP for all its beauty and prescience while keeping those fossilized ne&#8217;er-do-wells completely in the dark about your villainous plans.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2017/05/22/http-404-for-missing-api-resources/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Create SAS Tokens for Azure API Management with an Azure Function</title>
		<link>http://devjourney.com/2017/03/28/create-sas-tokens-for-azure-api-management-with-an-azure-function/</link>
					<comments>http://devjourney.com/2017/03/28/create-sas-tokens-for-azure-api-management-with-an-azure-function/#respond</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Tue, 28 Mar 2017 20:07:56 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=467</guid>

					<description><![CDATA[Shared Access Signature (SAS) tokens are required to call Azure API Management&#8217;s original REST API. We can generate these manually on the Azure portal for testing. However, in production, if you want to invoke the APIM REST APIs programmatically, you&#8217;ll need to generate these tokens with a bit of code. There&#8217;s a snippet available in&#8230; <a class="more-link" href="http://devjourney.com/2017/03/28/create-sas-tokens-for-azure-api-management-with-an-azure-function/">Continue reading <span class="screen-reader-text">Create SAS Tokens for Azure API Management with an Azure Function</span></a>]]></description>
										<content:encoded><![CDATA[<p>Shared Access Signature (SAS) tokens are required to call Azure API Management&#8217;s original REST API. We can generate these manually on the Azure portal for testing. However, in production, if you want to invoke the APIM REST APIs programmatically, you&#8217;ll need to generate these tokens with a bit of code. There&#8217;s a snippet available in the <a href="https://docs.microsoft.com/en-us/rest/api/apimanagement/">APIM documentation</a> that shows how to do this but it&#8217;s (possibly) got a flaw that I&#8217;ll address below. Moreover, with Azure Functions available these days, it makes sense to expose this token generator as a service. Here&#8217;s the code for an Azure Function to do just that:</p>
<pre class="lang:c# decode:true" title="Azure Function that implements APIM SAS Token as a Service">using System;   
using System.Net;
using System.Text;   
using System.Globalization;   
using System.Security.Cryptography;

public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    string id = Environment.GetEnvironmentVariable("APIM_SAS_ID", EnvironmentVariableTarget.Process);
    string key = Environment.GetEnvironmentVariable("APIM_SAS_KEY", EnvironmentVariableTarget.Process);
    DateTime then = DateTime.UtcNow.AddMinutes(10);
    // seconds must be zero for this to work
    DateTime expiry = new DateTime(then.Year, then.Month, then.Day, then.Hour, then.Minute, 0, DateTimeKind.Utc);
    using (HMACSHA512 hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key)))
    {
        string dataToSign = id + "\n" + expiry.ToString("O", CultureInfo.InvariantCulture);
        byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
        string signature = Convert.ToBase64String(hash);
        return req.CreateResponse(HttpStatusCode.OK, new {
            SharedAccessSignature = $"{id}&amp;{expiry:yyyyMMddHHmm}&amp;{signature}"
        });
    }
}
</pre>
<p>This Azure Function requires two web application settings named APIM_SAS_ID and APIM_SAS_KEY to be used in the hashing process. You can fetch those from the APIM publisher portal (and wherever they may be on the main Azure portal once APIM is fully integrated there). The token that gets generated from this code will be good for ten minutes. You can add more time if you like by modifying the line of code that calls DateTime.AddMinutes(). Currently, APIM SAS tokens can be generated to last up to thirty days although it&#8217;s not good practice to make them last that long.</p>
<p>The problem that I found with the snippet of code that was shown in the APIM documentation is that the inclusion of the seconds in the expiration time caused it to fail validation no matter how the middle (EX) portion of the SAS token was formulated. Perhaps I was doing something else wrong but I found that by setting the seconds to zero in the expiration date, I was able to generate SAS tokens that are honored by the APIM REST API. Here&#8217;s a GET operation that fetches the value of a property in APIM named SOME_APIM_PROP using the SharedAccessSignature Authorization schema:</p>
<pre class="lang:default decode:true">GET /properties/?$filter=name eq 'SOME_APIM_PROP'&amp;api-version=2016-10-10 HTTP/1.1
Host: apimftw.management.azure-api.net
Authorization: SharedAccessSignature 57d83b84fe7a801&amp;201703281726&amp;1Zvq5h...
Cache-Control: no-cache</pre>
<p>With this Azure Function in place (and the credentials to access it), I can generate SAS tokens for APIM any time I like using a simple, clean HTTP interface. Azure Functions are great architectural building blocks for any modern, API-centric design. If you agree or disagree with that assertion, let me know by reaching me on <a href="https://twitter.com/kevinhazzard">Twitter @KevinHazzard</a>. Enjoy.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2017/03/28/create-sas-tokens-for-azure-api-management-with-an-azure-function/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Extract JWT Claims in Azure API Management Policy</title>
		<link>http://devjourney.com/2017/03/23/extract-jwt-claims-in-azure-api-management-policy/</link>
					<comments>http://devjourney.com/2017/03/23/extract-jwt-claims-in-azure-api-management-policy/#respond</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Thu, 23 Mar 2017 19:42:08 +0000</pubDate>
				<category><![CDATA[API Management Policy Language]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[security]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=461</guid>

					<description><![CDATA[JSON Web Tokens (JWT) are easy to validate in Azure API Management (APIM) using policy statements. This makes integration with Azure Active Directory and other OpenID providers nearly foolproof. For example, one might add the following directive to the &#60;inbound&#62; policy for an API to ensure that the caller has attached a bearer token with&#8230; <a class="more-link" href="http://devjourney.com/2017/03/23/extract-jwt-claims-in-azure-api-management-policy/">Continue reading <span class="screen-reader-text">Extract JWT Claims in Azure API Management Policy</span></a>]]></description>
										<content:encoded><![CDATA[<p>JSON Web Tokens (JWT) are easy to validate in Azure API Management (APIM) using policy statements. This makes integration with Azure Active Directory and other OpenID providers nearly foolproof. For example, one might add the following directive to the &lt;inbound&gt; policy for an API to ensure that the caller has attached a bearer token with acceptable audience, issuer and application ID values in the signed JWT:</p>
<pre class="lang:default mark:12-16 decode:true">&lt;validate-jwt
    header-name="Authorization"
    failed-validation-httpcode="401"
    require-scheme="Bearer"&gt;
  &lt;openid-config url="https://login.windows.net/contoso.onmicrosoft.com/.well-known/openid-configuration" /&gt;
  &lt;audiences&gt;  
    &lt;audience&gt;80123615-1afd-48b7-b897-77273a479532&lt;/audience&gt;
  &lt;/audiences&gt;
  &lt;issuers&gt;
    &lt;issuer&gt;https://sts.windows.net/ca4870f4-8639-4c87-ac58-7d7678dd33b6/&lt;/issuer&gt;
  &lt;/issuers&gt;
  &lt;required-claims&gt;
    &lt;claim name="appid" match="all"&gt;
      &lt;value&gt;3689a0f2-4bb0-419d-a384-62e1e4a9c6d8&lt;/value&gt;
    &lt;/claim&gt;
  &lt;/required-claims&gt;
&lt;/validate-jwt&gt;</pre>
<p>That&#8217;s nice. A little bit of markup and all that nasty security plumbing is handled outside the API. But what if we want to pass some individual claims named inside the token on to the API backend? Unfortunately, Azure APIM doesn&#8217;t have that built into JWT token validation policy. Ideally, we&#8217;d be able to extract claims during validation into variables and pass them in HTTP headers before the request is forwarded to the backing API. Until that feature is added, here&#8217;s how you can do that:</p>
<pre class="lang:default decode:true" title="Extracting the appid from a JWT in APIM Policy">&lt;set-header name="token-app-id" exists-action="override"&gt;
  &lt;value&gt;@{
  string appId = "NOAUTH";
  string authHeader = context.Request.Headers.GetValueOrDefault("Authorization", "");
  if (authHeader?.Length &gt; 0)
  {
    string[] authHeaderParts = authHeader.Split(' ');
    if (authHeaderParts?.Length == 2 &amp;&amp; authHeaderParts[0].Equals("Bearer", StringComparison.InvariantCultureIgnoreCase))
    {
      Jwt jwt;
      if (authHeaderParts[1].TryParseJwt(out jwt))
      {
        appId = jwt.Claims.GetValueOrDefault("appid", "NOAPPID");
      }
    }
    return appId;
}&lt;/value&gt;
&lt;/set-header&gt;</pre>
<p>In this code, I&#8217;ve added some script inside the &lt;set-header&gt; policy statement to fetch the Authorization header from the request, check that it&#8217;s a Bearer type token, attempt to parse it (which checks the token&#8217;s signature), then finally extracts the value of one specific claim. Most of that work already happens inside &lt;validate-jwt&gt; policy, as you can imagine. Until there&#8217;s an easier way to extract JWT claims individually, the solution shown here works nicely. Enjoy.</p>
<p>If you agree with me that this feature should be built right into the &lt;validate-jwt&gt; policy, please <a href="https://feedback.azure.com/forums/248703-api-management/suggestions/18671686-extract-jwt-claims-to-variables-during-validation">upvote the feature request</a> I wrote on the APIM feedback site.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2017/03/23/extract-jwt-claims-in-azure-api-management-policy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The Simplest Possible Thing Principle</title>
		<link>http://devjourney.com/2016/04/04/the-simplest-possible-thing-principle/</link>
					<comments>http://devjourney.com/2016/04/04/the-simplest-possible-thing-principle/#comments</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Mon, 04 Apr 2016 16:35:52 +0000</pubDate>
				<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[principles]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=395</guid>

					<description><![CDATA[I mentor lots of young developers. It became a passion for me in the 1990s when I started teaching computer programming at a local college. I was not a good teacher for the first couple of years, admittedly. But I studied pedagogy and learned how to balance lecture and lab time to maximize the understanding&#8230; <a class="more-link" href="http://devjourney.com/2016/04/04/the-simplest-possible-thing-principle/">Continue reading <span class="screen-reader-text">The Simplest Possible Thing Principle</span></a>]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify;">I mentor lots of young developers. It became a passion for me in the 1990s when I started teaching computer programming at a local college. I was not a good teacher for the first couple of years, admittedly. But I studied pedagogy and learned how to balance lecture and lab time to maximize the understanding of my students. More importantly, I learned how to prepare myself to help my students learn. Preparing yourself to teach often means boiling ideas down into simple, memorable principles. One of them is called the Simplest Possible Thing principle.</p>
<p><span id="more-395"></span></p>
<p style="text-align: justify;">When you&#8217;re trying to master something new, doing the Simplest Possible Thing (SPT) to demonstrate it working is often the best way to learn. It&#8217;s so easy when you&#8217;re applying new concepts to get wrapped up in the mechanics and muck of the tools and frameworks you&#8217;re using. For example, trying to add a new database interface to an existing web site can be frustrating if the machinery of the web engine makes it hard to tell what&#8217;s going wrong with your initial tests. SPT reminds us that integrating the new framework into a big application might not the best way to really understand it.</p>
<p style="text-align: justify;">SPT directs us to first create a small test application where we can integrate the database libraries without the cruft and ceremony of the larger web application. We can typically bake some clean, clear, consistent debug outputs into the test application in a matter of minutes. Very quickly, the Simplest Possible Thing shows how to do the integration into the larger application.</p>
<p style="text-align: justify;">And SPT isn&#8217;t just for students. I create test applications so often that several times per year, I&#8217;ll go through my projects folder and delete hundreds of tiny test projects that begin with the phrase <strong>Kill_{some specific test name}_{date of creation}</strong>. I started using that naming pattern for my SPT tests many years ago because I had created hundreds of them that ended up cluttering up my projects folder. With this consistent naming pattern in place, I can quickly go back to find specific pre-integration test that I did recently. Embedding the date in the project name also helps me to know which ones I can clean up. If they&#8217;re more than a few months old, they&#8217;re probably safe to discard.</p>
<p style="text-align: justify;">The next time you are coaching someone who seems to be struggling with integrating a new idea into a larger application, I hope you&#8217;ll instruct them to do the Simplest Possible Thing to prove or disprove that they&#8217;ve got it right. Oftentimes, I&#8217;m surprised by what SPT teaches me. And I&#8217;m a salty, old dog who loves to learn new tricks.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2016/04/04/the-simplest-possible-thing-principle/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>.NET Back to Basics &#8211; Delegates to Expression Trees</title>
		<link>http://devjourney.com/2016/02/05/net-back-to-basics-delegates-to-expression-trees/</link>
					<comments>http://devjourney.com/2016/02/05/net-back-to-basics-delegates-to-expression-trees/#respond</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Fri, 05 Feb 2016 15:46:14 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[basics]]></category>
		<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=387</guid>

					<description><![CDATA[I led a talk at the Richmond, Virginia .NET User Group on 2016/2/4 about how delegates have evolved in .NET since 2002. We had about 40 in attendance from my rough count and the discussion was energetic. Thanks to everyone who attended. Below, you&#8217;ll find the links for the presentation and source code from the meeting.&#8230; <a class="more-link" href="http://devjourney.com/2016/02/05/net-back-to-basics-delegates-to-expression-trees/">Continue reading <span class="screen-reader-text">.NET Back to Basics &#8211; Delegates to Expression Trees</span></a>]]></description>
										<content:encoded><![CDATA[<p>I led a talk at the Richmond, Virginia .NET User Group on 2016/2/4 about how delegates have evolved in .NET since 2002. We had about 40 in attendance from my rough count and the discussion was energetic. Thanks to everyone who attended. Below, you&#8217;ll find the links for the presentation and source code from the meeting. The slides are light on content but they&#8217;ll help connect you to the ten different examples in the attached source code, at least.</p>
<p><a href="http://blog.devjourney.com/wp-content/uploads/2016/02/BackToDotNetBasics-Delegates-Code.zip" target="_blank" rel="noopener">Get the Source Code</a></p>
<p><a href="http://blog.devjourney.com/wp-content/uploads/2016/02/dotNET-Back-to-Basics-Delegates.pdf" target="_blank" rel="noopener">Get the Slides</a></p>
<p>If you are a user group leader and would like me to deliver this presentation to your group, contact me on Twitter as <a href="https://twitter.com/KevinHazzard" target="_blank" rel="noopener">KevinHazzard</a>. Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2016/02/05/net-back-to-basics-delegates-to-expression-trees/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Kevin&#8217;s Career Upgrade v6.0 &#8211; Amazon AWS</title>
		<link>http://devjourney.com/2015/10/04/kevins-career-upgrade-v6-amazon-aws/</link>
					<comments>http://devjourney.com/2015/10/04/kevins-career-upgrade-v6-amazon-aws/#comments</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Mon, 05 Oct 2015 02:00:49 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[serverless]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=381</guid>

					<description><![CDATA[I started my career in software development 34 years ago. I was 16 years old and a relative needed a program that helped her with a file classification project at a local hospital. I wrote a really bad piece of software in BASIC that took hours to solve the problem each time it was needed. I&#8230; <a class="more-link" href="http://devjourney.com/2015/10/04/kevins-career-upgrade-v6-amazon-aws/">Continue reading <span class="screen-reader-text">Kevin&#8217;s Career Upgrade v6.0 &#8211; Amazon AWS</span></a>]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify;">I started my career in software development 34 years ago. I was 16 years old and a relative needed a program that helped her with a file classification project at a local hospital. I wrote a really bad piece of software in BASIC that took hours to solve the problem each time it was needed. I refactored the program over and over again until I got it to run in a few seconds instead. The process of refactoring the software to improve it was exciting to me. It wasn&#8217;t a battle with the machine. It was a battle in my mind and I believed, step by step, that I could win through intelligence and sheer will. My relative showed the program to the hospital staff and they bought it from me for $50. I was ecstatic. Moreover, I was hooked on software development for life.</p>
<p style="text-align: justify;">Over the past 3.5 decades, I&#8217;ve made four major shifts in my career. When I started out, I wrote code in assembly language and C language. If you don&#8217;t know what those are, no worries. Just suffice it to say that they are super low-level abstractions and close to the actual hardware. I was really good at understanding the machine architecture and using it to my advantage. I even claimed that for a few minutes in 1984, I knew everything there was to know about the PC. Since then, I&#8217;ve been slipping. That&#8217;s true of everyone in this field though. There is no person who can know everything about all the complex systems that make up the modern PC and the Internet. I know a lot more than the average developer given my background that reaches all the way back to those low-level language days. But truth be known, I rarely use that old knowledge about electrical engineering and processor architecture to get work done today.</p>
<p style="text-align: justify;">The first major shift in my career, which I&#8217;ll call v2.0, happened in the mid-1980s. The out-of-date mainframe pre-compiler I used during the metamorphosis was called <em>C with Classes</em> but the language had already been renamed C++. The idea of object-orientation was dazzlingly cool to me. Being able to hide data inside of objects that expose safe access methods was liberating and empowering. I became a real expert in object-oriented design and in the use of the C++ Standard Template Library, riding that wave for more than a decade to create some very cool software.</p>
<p style="text-align: justify;">Career v3.0 for me came in the late 1990s when Java appeared on the scene. This highly expressive but simpler derivative of C++ promised to make our code safer and portable from one processor architecture to another. I was working with a group within the Intel Architecture Lab (IAL) that was implementing a high-performance Java Virtual Machine for the Intel processors. My team was creating all sorts of system-level software in Java that was going to change everything about the PC ecosystem, we believed. Then, one day, high-level folks from Microsoft visited our campus in Hillsboro, Oregon and spent all day in conferences with our IAL managers. Within days, all of the Java projects in IAL, including the screamingly fast new Java compiler and virtual machine were shut down. It was a real tragedy that changed the history of the PC forever. I left Intel and spent the next few years doing all sorts of interesting Java work that I enjoyed.</p>
<p style="text-align: justify;">In 2001 while teaching C++ at a local college, a student asked what I thought of C# (pronounced C Sharp for those who don&#8217;t know). I had no idea what it was so I called a friend in IAL and he explained that the reason Microsoft had abandoned Java (and ostensibly got its partner Intel to do the same) was to make way for a new language that would compete with Java. I was intrigued so he put me in touch with someone at Microsoft who sent me a gold CD-R with &#8220;Cool&#8221; scrawled on it in red Sharpie ink. (Cool was the project code name for C#.) I popped the CD in a drive, ran the installer and started playing. In the matter of minutes, I could tell that C# was different from Java in some interesting ways. Over the next hour, I fell in love with it. Thus began v4.0 of my career. I dove head first into C# and into Microsoft&#8217;s .NET ecosystem. I was probably one of the first college professors to teach C# in the world, filling my first classroom with .NET fledglings in 2002. By 2008, I had become a Microsoft C# Most Valuable Professional (MVP) and stayed in the award program for the next seven years.</p>
<p style="text-align: justify;">At the height of my experience as an MVP, I started work on a very large scale database project. Every software developer works with data but this project was really huge, at least one hundred times the size of any data project I&#8217;d worked on to date. I discovered that my skills as a programmer were massively inadequate to operate in that environment. The big problem was that my programming brain was wired to be iterative and imperative. I had spent 20 years telling computers what to do. The problem with really big data is that it&#8217;s often so big and so unwieldy that you just can&#8217;t tell it what to do. Instead, you must work with languages that allow you to describe <em>what</em> you want done instead of <em>how</em> it must be done. This is called the declarative programming model which is essentially the opposite of the imperative (command-based) programming I&#8217;d been doing for a couple of decades.</p>
<p style="text-align: justify;">For the first time, I really needed to use declarative, set-based languages like Transact Structured Query Language (T-SQL) to get my work done. There was really no other way to pull it off in C# (or any other language I knew at the time). My mind was transformed through the process. I could never see the world in the same ways again. My job, which had always been to virtualize the world through silicon, became a search for patterns instead. There were scores of data patterns to be discovered. Code patterns emerged at every turn when I started looking for them. I became a pattern junkie in v5.0 of my career. I even wrote a book with my friend Jason Bock called <a href="https://www.manning.com/books/metaprogramming-in-dot-net" target="_blank" rel="noopener">Metaprogramming .NET</a> which focuses on techniques for generating code based on patterns to make software fault tolerant and adaptive to change.</p>
<p style="text-align: justify;">Version 6.0 of my career starts tomorrow. As I write this, I am sitting in a hotel room in Las Vegas, Nevada waiting for the start of Amazon.com&#8217;s 2015 <a href="https://aws.amazon.com/" target="_blank" rel="noopener">AWS</a> re:Invent conference. I am convinced that most companies will shift their infrastructures to the cloud in the next few years. And I&#8217;m sure that the way Amazon AWS products are structured, they will capture and keep the majority of cloud market for the next decade.</p>
<p style="text-align: justify;">The reasons for my beliefs about the success of AWS are complex but it boils down to this. AWS is all about micro-architecture at any scale. That may sound like gibberish to those who haven&#8217;t built an enterprise system but it&#8217;s demonstrably true that all successful, complex systems are built from small parts working in concert to create value. AWS has generally designed their products in this way, deliberately or otherwise. Each product is a kind of gear that can connected to the others to create really interesting new things. There are serious integration challenges remaining but the AWS products fit together quite well, in general. Moreover, they scale dynamically so there&#8217;s appeal to small companies and large ones, alike.</p>
<p style="text-align: justify;">We&#8217;re already seeing the leading edge of the conversion as small- and medium-sized companies are testing the waters of cloud computing in large numbers to gain some operational advantages over their larger competitors. In the next five years, the motivation for moving to the cloud will shift from operational, financial and tactical to strategic. Services will become available in the cloud that we could never even imagine in our racks of single-purpose servers sitting in private data centers. Machine learning will give way to what&#8217;s next: predictive analytics that permeates all of our data, all of our code naturally and automatically whether it&#8217;s shaped and purposed for that or not. Those companies trying to compete by running single-purpose, monolithic software will simply fall behind.</p>
<p style="text-align: justify;">In reality, I started the shift to v6.0 of my career a while back. I&#8217;ve been using Microsoft Azure and Amazon AWS for a couple of years for my clients. But I&#8217;ve been using these services in the old-school way. When AWS Lambda was released a few months ago, that&#8217;s when the light bulb in my mind really lit up brightly. AWS Lambda is the simplest idea. What if you could write functions that could be instantiated in microseconds to get any sort of generic work done? And what if the system could scale out the number of available <em>machines</em> for running those functions heuristically and automatically?</p>
<p style="text-align: justify;">Lastly, what if that system of scalable functions could be triggered from anywhere? Saving a file might run a function. That code might write to a database which invokes other functions. Et cetera. Suddenly, I saw a way to compose complex, scalable systems with simple, interconnected building blocks. Moreover, this is all done without owning a single server in the classical sense. In 34 years, I&#8217;ve come full circle from wanting to master everything about the machines I use to not wanting any machines at all. Version 6.0 of my career will be just as exciting as v1.0 was to me. For that, I&#8217;m truly grateful to be in this profession.</p>
<p style="text-align: justify;">Let me finish by saying that although I think Amazon AWS will dominate in this space, Microsoft and Google will also do quite well. I&#8217;m not ignoring them. But the elegance, simplicity and highly composable nature of Amazon&#8217;s AWS products will make them a great choice for my clients. Viva Las Vegas!</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2015/10/04/kevins-career-upgrade-v6-amazon-aws/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Technically-Oriented People</title>
		<link>http://devjourney.com/2015/08/04/technically-oriented-people/</link>
					<comments>http://devjourney.com/2015/08/04/technically-oriented-people/#respond</comments>
		
		<dc:creator><![CDATA[Kevin]]></dc:creator>
		<pubDate>Tue, 04 Aug 2015 18:14:03 +0000</pubDate>
				<category><![CDATA[Fun]]></category>
		<guid isPermaLink="false">http://devjourney.com/blog/?p=373</guid>

					<description><![CDATA[A friend recently asked me to describe the differences between the various species of technically-oriented people. I wrote this in an email in about five minutes so I&#8217;m sure I left out some key details. Please embellish. The Technical Enthusiast Someone who wears mock turtlenecks and probably like shiny things. They listen to ColdPlay (a&#8230; <a class="more-link" href="http://devjourney.com/2015/08/04/technically-oriented-people/">Continue reading <span class="screen-reader-text">Technically-Oriented People</span></a>]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify;">A friend recently asked me to describe the differences between the various <em>species</em> of technically-oriented people. I wrote this in an email in about five minutes so I&#8217;m sure I left out some key details. Please embellish.</p>
<h5>The Technical Enthusiast</h5>
<p style="text-align: justify;">Someone who wears mock turtlenecks and probably like shiny things. They listen to ColdPlay (a lot) and think it’s pure joy to make the lights blink at home by pressing buttons on the $5,000 Macbook Pro that they leave at the office every day at 4:30pm. They do no real work <em>per se</em> but they smell great and clients love the exotic coffees they bring to the office. Favorite board game: <a href="http://www.amazon.com/Euphoria-Build-a-Better-Dystopia/dp/B00EDTK266" target="_blank" rel="noopener">Euphoria, Build a Better Dystopia</a>.</p>
<h5>The Geek</h5>
<p style="text-align: justify;">Whether using a Mac or a PC,  they spend time at the terminal prompt getting stuff done. They wear shorts and flip flops to work because anything else takes too much maintenance and prep time. Besides, so-called “work” happens at 3 am many days because flashes of genius ain’t gonna be tamed by the clock, you know. Geeks make clients happy because they are often perfectionists who take pride in their work and have a modicum of social skills. They sport facial hair when the chromosomes allow for it and play <a href="http://www.amazon.com/Cards-Against-Humanity-LLC-CAHUS/dp/B004S8F7QM" target="_blank" rel="noopener">Cards Against Humanity</a> in their spare time. Geeks love a good India Pale Ale.</p>
<h5>The Nerd</h5>
<p style="text-align: justify;">Pretty much geeks with fewer social skills who are typically obsessive about one thing, e.g. making sure everyone understands why Batman is superior to Superman in every conceivable way. Whatever machines these folks are on, it’s definitely running Linux. They play <a href="http://www.amazon.com/Fantasy-Flight-Games-BSG01-Battlestar/dp/1589944607" target="_blank" rel="noopener">Battlestar Gallactica</a> for days on end, typically until the participants start needing medical attention. These folks get work done but it’s on their own terms. Probably best to stock up on Jolt Cola and slide pizzas under the door once in a while praying that they meet deadlines. Favorite beverage: kombucha served fresh at the <a href="http://www.renfair.com/index.asp" target="_blank" rel="noopener">Renaissance Faire</a>.</p>
<h5>The Dweeb</h5>
<p style="text-align: justify;">These are nerds with zero social skills and who alienate any potential clients based on the way they smell alone. They don’t bathe often because it takes time out of their MMORPG binges. They usually live in their Mom’s basement and suffer from vitamin D deficiency which leads to their peculiarly large foreheads (in both men and women alike). They might be brilliant but since nobody ever speaks to them outside of the context of BBS software they haunt to discuss rebuilds of various UNIX kernels, no one knows for sure. We’re also not sure if these folks eat or drink in the classical sense but the video of <a href="https://youtu.be/I25UeVXrEHQ?t=1m50s" target="_blank" rel="noopener">Richard Stallman eating something from his foot</a> during a recent FSF conference is an important clue to their means of sustenance.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://devjourney.com/2015/08/04/technically-oriented-people/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
