☁️ Notes on RESTful APIs as Proxified Azure Functions with Cosmos DBs

Mammatus clouds over Squaw Valley

Let’s consider some fundamentals for developing RESTful APIs in Microsoft’s cloud-based tech. The three tools required for this workflow are Azure Functions, their Proxies and Cosmos DB (as of April 2020, use SQL API, not the MongoDB API, as the MongoDB API is not actually functional). Microservices (a refinement to Service-oriented Architecture, SOA) sometimes involve the use of one database per service as a methodological assumption, leaving aside Command-Query Responsibility Segregation (CQRS; i.e. reads-writes separated: should no commands return data?) and Domain-Driven Design (DDD; i.e. Ubiquitous Language and contextualized domain model that informs logical boundaries).

Typically a microservice architecture structural style might look like the following:

Generated from YUML: microservice architecture structural style, considering Consul on Azure

The example provided here based on Azure Functions isn’t exactly the above diagram’s implementation, but it’s just a nice visual for thinking about the question: where would Azure Functions (what was once the “app”) live otherwise? (Answer: somewhere in the microservices.) As would the Consul Client and Proxy.

Anyway, a module might consist of various services, and that module’s logical and functional boundaries can be informed by CQRS and DDD, all interacting with Azure Functions (or AWS Lambda functions with S3 and DynamoDB?). You can configure these cloud functions to hit an app or an app can hit these functions. You can use stored procedures to query and programmatically treat states of entities as behavioral norms conformant to Ubiquitous Language (a domain expert might consider a behavior as logically equivalent across two models: planes and helicopters fly or onboard passengers).

Perhaps: /api/v1/helicopters/:id/$action -d '{ "key": "fly", "param": "start" }' or /api/v1/helicopters/:id/$action?key=onboard&param=start for HATEOAS (driving state of the application by links, as per Roy Fielding’s thesis; also consider how these links can be extended to IoT/machine-to-machine interaction).

Think of a service as a grouping of HTTP verbs under one entity, the noun in the URL, and that entity might possess actions (remember to use plural nouns for collections of entities):

Name                 Verb    Route
EntityCreated POST /api/v1/{entities}
EntitiesRead GET /api/v1/{entities}
EntityReadById GET /api/v1/{entities}/:id
""UpdatedById PUT /api/v1/{entities}/:id
""RemovedById DELETE /api/v1/{entities}/:id
EntityAction POST /api/v1/{entities}/:id/$action
EntityPartCreated POST /api/v1/{entities}/:id/{parts}
EntityPartsRead GET /api/v1/{entities}/:id/{parts}
EntityPartReadById GET /api/v1/{entities}/:id/{parts}/:partId
""UpdatedById PUT /api/v1/{entities}/:id/{parts}/:partId
""RemovedById DELETE /api/v1/{entities}/:id/{parts}/:partId

So consider the above layout as a basis for Proxies to front the Azure Functions. There might be one database that is inclusive of the Entity-Part (e.g. HotelRoom-Bed: HotelRoomBedsRead, ClassRoom-Seat: ClassRoomSeatsRead, etc) relation considered as a module. One might think in terms of a database per module, too, and also think in terms of a database per service (minimally a service has an entity without actions or parts). As mentioned above, we could think of a module as consisting of multiple services, which might be a case wherein the entity’s model has many parts warranting their own database. Entity actions (EntityAction) or the originary creation (EntityCreated) of an entity can be used to further create their parts. This choice, of how to create parts depends on one’s mental model, coding preference, requirements of the project, automation of operations, complexity of the parts insofar as their states or implicatures with respect to other parts under other entities or limitations of the server/development environment.

Code Samples

RESTful APIs as Proxified Azure Functions

The deletion code isn’t performant and could probably be better written using a Durable Function wherein cases like external events are involved. Consider tcomb for validation prior to DB writes.

Example EntityReadById and EntitiesRead proxified Azure Functions are running at
1. https://anotherfaileddeployment.azurewebsites.net/humans/370448f2-7b88-4e7f-bdef-ba0141a6092b (get one human)
2. https://anotherfaileddeployment.azurewebsites.net/humans (get the full list of humans)
3. https://anotherfaileddeployment.azurewebsites.net/humans?filters[name]=Spiffy&filters[planet]=Earth (filter by name, e.g. filter[name], and location fields, if available; page works too)
4. https://anotherfaileddeployment.azurewebsites.net/humans?page_size=5
5. https://anotherfaileddeployment.azurewebsites.net/humans?page=2
6. https://anotherfaileddeployment.azurewebsites.net/humans?page_size=5&page=2

For a POST try the following (assuming *nix):

For a DELETE try the following:

Use RESTer if you’re in Firefox and want to test the above endpoints in a structured environment, or just check out the response [2] [3, 3.1] [4] to the curl-based request.

While the implementation above is far from complete (DELETE, POST , and singular GET do not bear RESTful representations), it must be remembered:

As Tim Berners-Lee has stressed, apart from the server address, URLs should be treated as opaque; it’s the “rel” value that matters. That’s part of the point of HATEOAS.
“Introducing: Restful Objects”. https://www.infoq.com/articles/Intro_Restful_Objects/

REST is an incredibly attractive idea for generic clients (like web browsers) which discover application state via resource representations issued by the server. We can imagine more sophisticated states (like those of games or operating systems) represented in links: rel="reload" , rel="rollback" or rel="recover", rel="commit", rel="push", rel="open", etc. which correspond to POST .../$action/:resourceMethod/invoke wherein the resourceMethod s the key given parameters provided through the body of the request; e.g. POST .../$action/commit/invoke with { message: "Init" }.

Note: The POST proxy does not work fully via the curl commands online website, and I have not developed a PUT endpoint (since it is effectively demonstrated by the DELETE endpoint).

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store