<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Daniel Bichuetti]]></title><description><![CDATA[Daniel Bichuetti]]></description><link>https://bichuetti.net</link><generator>RSS for Node</generator><lastBuildDate>Mon, 07 Sep 2026 09:37:51 GMT</lastBuildDate><atom:link href="https://bichuetti.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Qdrant Authentication]]></title><description><![CDATA[Qdrant is becoming more and more popular, and its use is increasing every day. At Intelijus, we decided to try its amazing capabilities and see how it performed.
Using the helm chart, everything worked perfectly to deploy into our cluster. However, s...]]></description><link>https://bichuetti.net/qdrant-authentication</link><guid isPermaLink="true">https://bichuetti.net/qdrant-authentication</guid><category><![CDATA[qdrant]]></category><category><![CDATA[VectorSearch]]></category><category><![CDATA[nlp]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Daniel Bichuetti]]></dc:creator><pubDate>Wed, 28 Dec 2022 13:30:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672233736175/2f0c1191-5bc2-4df5-9167-69afd7781346.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://qdrant.tech/">Qdrant</a> is becoming more and more popular, and its use is increasing every day. At <a target="_blank" href="https://www.linkedin.com/company/intelijus">Intelijus</a>, we decided to try its amazing capabilities and see how it performed.</p>
<p>Using the <a target="_blank" href="https://github.com/qdrant/qdrant-helm">helm chart</a>, everything worked perfectly to deploy into our cluster. However, some remote developers were interested in using it to make tests.</p>
<p>The Cloud version includes an API Key Authentication, but the usual deployment doesn't include any. We can further explore the initialization parameters for the Qdrant Python client:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self,
                 host=<span class="hljs-string">"localhost"</span>,
                 port=<span class="hljs-number">6333</span>,
                 grpc_port=<span class="hljs-number">6334</span>,
                 prefer_grpc=False,
                 https=None,
                 api_key=None,
                 prefix=None,
                 **kwargs</span>):</span>
</code></pre>
<p>So, the team analyzed two options.</p>
<p>— <a target="_blank" href="https://konghq.com/">Kong</a> as an API gateway, and the <a target="_blank" href="https://docs.konghq.com/hub/kong-inc/key-auth/">Key Authentication plugin</a></p>
<p>— <a target="_blank" href="https://kubernetes.github.io/ingress-nginx/">Kubernetes Ingress</a> using <a target="_blank" href="https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#authentication">basic authentication</a></p>
<p>The <a target="_blank" href="https://github.com/qdrant/qdrant_client">qdrant-client</a> implementation of the API_KEY header would benefit from Kong. The service implementation would be fast, but we would need to deploy Kong to this cluster. Kong is great. We have deployed it on some APIs, but on this test cluster, it's not installed. Kubernetes Ingress is already installed.</p>
<p>Given that the night was great for coding, I decided to take a look before our next meeting to discuss this. First, I deployed one Ingress routing to the Qdrant Cluster IP service on port 6333. Basic authentication and a certificate were set up using annotations. Then, I tested it using the httpx Python module. It was possible to contact Qdrant service.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">cert-manager.io/cluster-issuer:</span> <span class="hljs-string">certificate_issuer</span>
<span class="hljs-attr">nginx.ingress.kubernetes.io/auth-type:</span> <span class="hljs-string">basic</span>
<span class="hljs-attr">nginx.ingress.kubernetes.io/auth-secret:</span> <span class="hljs-string">qdrant-auth</span>
<span class="hljs-attr">nginx.ingress.kubernetes.io/auth-realm:</span> <span class="hljs-string">Qdrant</span>
</code></pre>
<p>The next step was to look at the Qdrant Python Client. It was promising to see the first look, they implemented a nested chain of keyword arguments. It would go from QdrantClient to the httpx client. If I add an auth and a verify parameter, it would propagate to the place I needed it. Furthermore, the port should be the one that Ingress is listening on.</p>
<pre><code class="lang-python">client = QdrantClient(host=<span class="hljs-string">"qdrant.mydomain.com"</span>, port=<span class="hljs-number">443</span>, https=<span class="hljs-literal">True</span>, auth=(<span class="hljs-string">'daniel'</span>, <span class="hljs-string">'mypassword'</span>), verify=<span class="hljs-literal">False</span>)
</code></pre>
<p>This setup made it easy to implement a basic authentication layer in front of our Qdrant vector database, which allowed us to expose it to our remote developers.</p>
<p>Look at you next, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[NLP endpoints: Haystack plus FastAPI]]></title><description><![CDATA[In this article, we will build together a FastAPI application which interacts with Haystack. It's an experiment intended to be a starting point for anyone wishing to use haystack as a service for other projects. And one of the easiest ways is through...]]></description><link>https://bichuetti.net/nlp-endpoints-haystack-plus-fastapi</link><guid isPermaLink="true">https://bichuetti.net/nlp-endpoints-haystack-plus-fastapi</guid><category><![CDATA[haystack]]></category><category><![CDATA[FastAPI]]></category><category><![CDATA[nlp]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Daniel Bichuetti]]></dc:creator><pubDate>Mon, 05 Sep 2022 14:56:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1662328482217/oq9k3g71Z.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we will build together a <strong>FastAPI application</strong> which interacts with <strong>Haystack</strong>. It's an experiment intended to be a starting point for anyone wishing to use haystack as a service for other projects. And one of the easiest ways is through a REST API.
You can deploy a REST API into a physical machine, a virtual machine, a container, or a serverless environment (like AWS Lambda or Azure Functions).</p>
<p>Let's code.</p>
<h2 id="heading-the-virtual-environment">The virtual environment</h2>
<p>Everybody loves Python! </p>
<p>Who doesn't get amazed to "talk with the code"? When coding in Python, I feel like talking to my computer. For someone coding since when I was 12yo, you may understand my passion. </p>
<p>Python has thousands of available modules, and each day more come up. When you need something, look for it deeper on PyPi. It's hard not to find something. But this reminds me of one of the most famous sentences in a movie: <em>"With great power comes great responsibility."</em> If we keep installing modules into a mixed environment, we are building the path for considerable problems in the dependency chain, testing, and organization. The recommended way is to use <strong>isolated environments</strong>, which can be achieved by <a target="_blank" href="https://docs.python.org/3/library/venv.html">python-venv</a>.</p>
<h3 id="heading-create-a-new-environment">Create a new environment.</h3>
<pre><code class="lang-python">python3 -m venv venv
</code></pre>
<h3 id="heading-activate-the-virtual-environment">Activate the virtual environment.</h3>
<pre><code class="lang-python">source venv/bin/activate
</code></pre>
<h2 id="heading-install-haystack">Install Haystack</h2>
<p>Now we install the outstanding framework <strong><a target="_blank" href="https://haystack.deepset.ai">Haystack</a></strong> NLP framework. </p>
<p>We use <a target="_blank" href="https://opensearch.org/">OpenSearch</a> as our Document Store. For this, we set the egg <em>opensearch</em> to instruct pip to install its related dependencies together with the framework.</p>
<pre><code><span class="hljs-attribute">pip</span> install fastapi
</code></pre><h3 id="heading-create-an-empty-python-file">Create an empty python file</h3>
<pre><code class="lang-python">touch app.py
</code></pre>
<h3 id="heading-the-health-check-endpoint">The health-check endpoint</h3>
<p> First, exposing a health-check endpoint is a good practice. But what is a health-check endpoint?</p>
<p> It's a route that tells external systems the current status of your application. For example, normal states are running correctly (green), partially (yellow), or not running correctly (red). Some providers can check this endpoint to know if your app is running correctly and doesn't need a restart. It's also useful by allowing you to set up alarms in monitoring tools.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI

app = FastAPI()

<span class="hljs-meta">@app.get("/health")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">health</span>():</span>
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"status"</span>: <span class="hljs-string">"ok"</span>}
</code></pre>
<p>This code isn't doing extended checks and returning possible warnings (yellow reasons) or errors (red reasons). But a production API really should. It's a starting point, and what it should return when not working is tightened to each application and business.</p>
<h3 id="heading-async-capabilities">Async capabilities</h3>
<p>Besides using a usual definition, which is synchronous, FastAPI also supports asynchronous methods. In IO-heavy applications, asynchronous code is critical to avoid bottlenecks and improve performance. Therefore, you need to add <strong>async</strong> into your method definition.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI

app = FastAPI()

<span class="hljs-meta">@app.get("/health")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">health</span>():</span>
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"status"</span>: <span class="hljs-string">"ok"</span>}
</code></pre>
<h3 id="heading-running-your-fastapi-application">Running your FastAPI application</h3>
<p>Ok, you may be thinking now about how you run this application. Probably, you are considering calling "python  app.py", right? But, no, FastAPI is a framework, not a server. Therefore, you must use something else. Here is where <a target="_blank" href="https://www.uvicorn.org/">uvicorn</a> is helpful. There is also <a target="_blank" href="https://gunicorn.org/">gunicorn</a>, a WSGY server, but this is for another article. </p>
<p>Install it.</p>
<pre><code><span class="hljs-selector-tag">pip</span> <span class="hljs-selector-tag">install</span> <span class="hljs-selector-tag">uvicorn</span><span class="hljs-selector-attr">[standard]</span>
</code></pre><p>From the command line, you can now run:</p>
<pre><code>uvicorn app:app <span class="hljs-operator">-</span><span class="hljs-operator">-</span>reload <span class="hljs-operator">-</span><span class="hljs-operator">-</span>workers <span class="hljs-number">1</span>
</code></pre><p>The first <em>app</em> is the python filename without the extension, and the second is the FastAPI <em>App object</em>. The reload option will make uvicorn reload the file whenever it's changed. Use this only when developing if you like real-time updates.</p>
<p>It will start at the default port, 8000. So you should see on the command line something like:</p>
<pre><code><span class="hljs-keyword">INFO</span>:     Will watch <span class="hljs-keyword">for</span> changes <span class="hljs-keyword">in</span> these directories: [<span class="hljs-string">'/home/danielbichuetti/Dev/Projects/fastapi_haystack'</span>]
<span class="hljs-keyword">INFO</span>:     Uvicorn running <span class="hljs-keyword">on</span> http://<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">8000</span> (Press CTRL+C <span class="hljs-keyword">to</span> quit)
<span class="hljs-keyword">INFO</span>:     Started reloader process [<span class="hljs-number">57303</span>] <span class="hljs-keyword">using</span> WatchFiles
<span class="hljs-keyword">INFO</span>:     Started <span class="hljs-keyword">server</span> process [<span class="hljs-number">57307</span>]
<span class="hljs-keyword">INFO</span>:     Waiting <span class="hljs-keyword">for</span> application startup.
<span class="hljs-keyword">INFO</span>:     Application startup complete.
</code></pre><h3 id="heading-testing-the-skeleton-application">Testing the skeleton application</h3>
<pre><code class="lang-curl">curl http://localhost:8000/health
</code></pre>
<p>The response must be:</p>
<pre><code>{<span class="hljs-attr">"status"</span>:<span class="hljs-string">"ok"</span>}
</code></pre><p>Yeah, it's a JSON string. Pretty easy to build a REST API, right? It's just a tiny amount of FastAPI power. It's straightforward and fast.</p>
<h2 id="heading-deploy-an-opensearch-cluster">Deploy an OpenSearch cluster</h2>
<p>Do you have any OpenSearch servers available? If yes, you can jump to the next section. If not, you will love this one.</p>
<h3 id="heading-create-an-aws-opensearch-service">Create an AWS OpenSearch Service</h3>
<p>Go to <a target="_blank" href="https://signin.aws.amazon.com/signin">AWS console</a> portal and log in. If you are not a user yet, please <a target="_blank" href="https://portal.aws.amazon.com/gp/aws/developer/registration/index.html?refid=c623d581-46f6-43a2-b227-cabbee9cd673">sign up</a> for a free account. </p>
<p>They provide Amazon OpenSearch Service on their free tier. So yeah, 750 hours of <strong>t3.small.search</strong> instance monthly. It's a good starting point.</p>
<p>After you have logged in, find <a target="_blank" href="https://us-east-1.console.aws.amazon.com/opensearch">Amazon OpenSearch Service</a>. Then click on <em>Create Domain</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662314815773/Wk9mwnVpp.png" alt="Screenshot from 2022-09-04 15-06-45.png" /></p>
<p>You will get redirected to the cluster creation screen. The first field is the name you want to use for your cluster. Let's call it <strong>haystack</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662314979663/d_GLHt_LS.png" alt="Screenshot from 2022-09-04 15-09-30.png" /></p>
<p>Choose the Deployment type, Development and testing, and select 1.3 (latest) as the version. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662315092919/RNYk4t9Lk.png" alt="Screenshot from 2022-09-04 15-11-23.png" /></p>
<p>Let's tweak some default Data nodes options to keep setup simple and use just the free tier.
First, let's use only <strong>1 AZ</strong>, and change the <strong>Number of nodes</strong> to <strong>1</strong>. On <strong>Instance Type</strong>, change to <strong>t3.small.search</strong>. Don't change the EBS size to more than 20GB, as it's the maximum allowed for free.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662315439686/AuhiOOKJ7.png" alt="Screenshot from 2022-09-04 15-17-10.png" /></p>
<p>Scroll down until you get to the <strong>Network</strong> part. Usually, this is a bad idea without further tuning and control. However, for an experiment, it will be ok. We will use <strong>Public access</strong> for the network, which means <em>we exposed our cluster endpoints to the Internet</em>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662315533432/rflTcTdTA.png" alt="Screenshot from 2022-09-04 15-18-47.png" /></p>
<p>Because we exposed OpenSearch to the Internet, set up at least an <strong>admin user</strong>. I would recommend using IAM roles or certificates in a production environment. Let's call the user "hs_admin" and set up a password.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662315830661/JaXxm7R6J.png" alt="Screenshot from 2022-09-04 15-23-42.png" /></p>
<p>For a more straightforward setup and to avoid extensive configuration, let's <strong>turn off domain access policies</strong> and use just fine-grained access control. <strong>Avoid this on production</strong>. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662315939281/iS-nTTYGa.png" alt="Screenshot from 2022-09-04 15-25-22.png" /></p>
<p>Now hit the Create button on the bottom of the page and wait.</p>
<p>You'll see a page with loading information, like this one. It shows the steps of the cluster creation process. You will have to wait some minutes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662316104372/cewhvyfHo.png" alt="Screenshot from 2022-09-04 15-27-09.png" /></p>
<p>After some time, your cluster status will turn <strong>Green</strong>, like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662317291298/Mbwf1q0Gw.png" alt="Screenshot from 2022-09-04 15-47-23.png" /></p>
<p>Click on your recently created cluster: haystack.</p>
<p>You will see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662317342180/s2K42ZA25.png" alt="Screenshot from 2022-09-04 15-47-23.png" /></p>
<p>The information that is important for us is the <strong>Domain endpoint</strong>, which is your cluster address:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662317412430/Yq2nenEjj.png" alt="image.png" /></p>
<p>Here we end up with the creation of OpenSearch. Back to the code (finally).</p>
<h2 id="heading-refactoring-the-application">Refactoring the application</h2>
<h3 id="heading-the-environments-values">The environments values</h3>
<p>We must provide the authentication data to connect to our OpenSearch cluster. Putting this directly in code is a terrible decision. Never do it. It would be best if you used secret stores or environment variables.</p>
<p>We will now create a <em>.env</em> file in our project directory. You will fill it with the cluster address, the admin username, and the password. Remember to paste the server without the scheme(HTTPS or HTTP) and the port. These are extra parameters for Haystack OpenSearchDocumentStore.</p>
<pre><code>OPENSEARCH_SERVER<span class="hljs-operator">=</span>search<span class="hljs-operator">-</span>haystack<span class="hljs-operator">-</span>4luhmrfigopcmjfnvh62rtsp5q.us-east<span class="hljs-number">-1</span>.es.amazonaws.com
OPENSEARCH_SERVER_PORT<span class="hljs-operator">=</span><span class="hljs-number">443</span>
OPENSEARCH_USER<span class="hljs-operator">=</span>hs_admin  
OPENSEARCH_PASSWORD<span class="hljs-operator">=</span>H2YsT2CkPa$$w0rd
</code></pre><p>We will install a library to help load environment variables during development.</p>
<pre><code><span class="hljs-attribute">pip</span> install python-dotenv
</code></pre><p>On your app.py file, add. </p>
<pre><code><span class="hljs-keyword">from</span> dotenv <span class="hljs-keyword">import</span> <span class="hljs-title">load_dotenv</span>

<span class="hljs-title">load_dotenv</span>()
<span class="hljs-title">OPENSEARCH_SERVER</span> <span class="hljs-operator">=</span> <span class="hljs-title">os</span>.<span class="hljs-title">getenv</span>(<span class="hljs-string">"OPENSEARCH_SERVER"</span>)
<span class="hljs-title">OPENSEARCH_SERVER_PORT</span> <span class="hljs-operator">=</span> <span class="hljs-title">os</span>.<span class="hljs-title">getenv</span>(<span class="hljs-string">"OPENSEARCH_SERVER_PORT"</span>)
<span class="hljs-title">OPENSEARCH_USER</span> <span class="hljs-operator">=</span> <span class="hljs-title">os</span>.<span class="hljs-title">getenv</span>(<span class="hljs-string">"OPENSEARCH_USER"</span>)
<span class="hljs-title">OPENSEARCH_PASSWORD</span> <span class="hljs-operator">=</span> <span class="hljs-title">os</span>.<span class="hljs-title">getenv</span>(<span class="hljs-string">"OPENSEARCH_PASSWORD"</span>)
</code></pre><p>The variables from the environment will get loaded, but before, dotenv will check whether they are present or not. If not, it will use the .env data.</p>
<h3 id="heading-initialize-opensearchdocumentstore">Initialize OpenSearchDocumentStore</h3>
<p>With this in hand, we can now initialize our Haystack DocumentStore:</p>
<pre><code>document_store <span class="hljs-operator">=</span> OpenSearchDocumentStore(
    host<span class="hljs-operator">=</span>OPENSEARCH_SERVER,
    port<span class="hljs-operator">=</span>OPENSEARCH_SERVER_PORT,
    username<span class="hljs-operator">=</span>OPENSEARCH_USER,
    password<span class="hljs-operator">=</span>OPENSEARCH_PASSWORD,
    verify_certs<span class="hljs-operator">=</span>True
)
</code></pre><p>There are other parameters and ways of fine-tuning this initialization; you can read more <a target="_blank" href="https://haystack.deepset.ai/reference/document-store#opensearchdocumentstore">here</a>.</p>
<h3 id="heading-data-validation">Data validation</h3>
<p>Valid data in a REST endpoint is a need. We don't want anyone sending invalid data to our endpoints. So we will use data validation then.</p>
<p>Let's define a model for the requests made to our endpoints. First, we will send documents, which will be JSON documents with content and a name.</p>
<p>We will use <a target="_blank" href="https://pydantic-docs.helpmanual.io/">pydantic</a> for it. First, we will install it:</p>
<pre><code><span class="hljs-attribute">pip</span> install pydantic
</code></pre><p>Then we will declare the new class:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Document</span>(<span class="hljs-params">BaseModel</span>):</span>
    name: Optional[str] = <span class="hljs-literal">None</span>
    content: str
</code></pre><p>Here there is an important point. Take care with naming classes on your project to avoid overwriting other classes. You can see I used Document. But then I remembered one of the most critical <a target="_blank" href="https://haystack.deepset.ai/reference/primitives">primitives in Haystack</a>: Document. Like Labels and Answers, it's a pillar of it. So we will use an alias on the import like this: </p>
<pre><code><span class="hljs-keyword">from</span> haystack.schema <span class="hljs-keyword">import</span> <span class="hljs-title">Document</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">HaystackDocument</span>
</code></pre><p>Let's keep the alias to avoid overwriting it while still getting in touch with the best NLP framework.</p>
<h3 id="heading-add-a-document">Add a document</h3>
<p>We will define one way to add a document to our Document Store.</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.post("/documents", status_code=201)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">save_document</span>(<span class="hljs-params">document: Document</span>):</span>
    new_doc= HaystackDocument(content=document.content, meta={<span class="hljs-string">"name"</span>: document.name})
    document_store.write_documents([new_doc])
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"id"</span>: new_doc.id}
</code></pre>
<p>We test the endpoint:</p>
<pre><code class="lang-curl">curl -X POST http://localhost:8000/documents/ -H 'Content-Type: application/json' -d '{"name":"My first Haystack document", "content":"Haystack is an open-source framework for building search systems that work intelligently over large document collections."}'
</code></pre>
<p>Wow, that was easy and fast! You should see this response:</p>
<pre><code>{<span class="hljs-attr">"id"</span>:<span class="hljs-string">"e41e6aeb0ae5965a912b672664e58b7c"</span>}
</code></pre><p>It's the id that Haystack generated for your document. We are returning it.</p>
<h3 id="heading-get-a-document">Get a document</h3>
<p>What if we want to get this document?</p>
<p>Let's build an endpoint to read a document by its id:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.get("/documents/{document_id}", status_code=200)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_document</span>(<span class="hljs-params">document_id: str, response: Response</span>):</span>
    document = document_store.get_document_by_id(document_id)
    <span class="hljs-keyword">if</span> document <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        response.status_code = <span class="hljs-number">404</span>
        <span class="hljs-keyword">return</span> {<span class="hljs-string">"error"</span>: <span class="hljs-string">"Document not found"</span>}
    <span class="hljs-keyword">return</span> document_store.get_document_by_id(document_id)
</code></pre>
<p>We are trying to get the document from Haystack OpenSearchDocumentStore; if there is not a document with this id, we will return a 404 HTTP response code with an error message. On the other hand, you will get a 200 HTTP response code with the document if it exists.</p>
<pre><code class="lang-curl">curl http://localhost:8000/documents/e41e6aeb0ae5965a912b672664e58b7c
</code></pre>
<p>Our response will have a bit more information than what we first sent to create the endpoint:</p>
<pre><code>{"content":"Haystack is an open-source framework for building search systems that work intelligently over large document collections.","content_type":"text","id":"e41e6aeb0ae5965a912b672664e58b7c","meta":"name":"My first Haystack document"},"score":<span class="hljs-number">0.5312093733737563</span>,"embedding":<span class="hljs-keyword">null</span>}
</code></pre><p>The Document primitive of Haystack documentation is <a target="_blank" href="https://haystack.deepset.ai/reference/primitives#document">here</a>. You will get a better understanding of each field there. 
By the way, the haystack documentation is pretty complete. Expend some time there. It will be a pleasant learning time.</p>
<h3 id="heading-add-more-documents">Add more documents</h3>
<pre><code class="lang-curl">curl -X POST http://localhost:8000/documents/ -H 'Content-Type: application/json' -d '{"name":"deepset Cloud", "content":"Build production-ready NLP services.  deepset Cloud is a SaaS platform to build natural language processing applications."}'
</code></pre>
<pre><code class="lang-curl">curl -X POST http://localhost:8000/documents/ -H 'Content-Type: application/json' -d '{"name":"FastAPI", "content":"FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints."}'
</code></pre>
<h3 id="heading-get-all-documents">Get all documents</h3>
<p>Now, what if we want to get all documents?</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.get("/documents/", status_code=200)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_all_document</span>(<span class="hljs-params">response: Response</span>):</span>
    documents = document_store.get_all_documents()
    <span class="hljs-keyword">if</span> documents <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        response.status_code = <span class="hljs-number">404</span>
        <span class="hljs-keyword">return</span> {<span class="hljs-string">"error"</span>: <span class="hljs-string">"Documents not found"</span>}
    <span class="hljs-keyword">return</span> documents
</code></pre>
<p>We can test:</p>
<pre><code class="lang-curl">curl http://localhost:8000/documents/
</code></pre>
<p>This time our response will come with all the three documents we have added.</p>
<pre><code>[{<span class="hljs-attr">"content"</span>:<span class="hljs-string">"FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints."</span>,<span class="hljs-attr">"content_type"</span>:<span class="hljs-string">"text"</span>,<span class="hljs-attr">"id"</span>:<span class="hljs-string">"5209b538869b938ac94bf70fa0b09bd"</span>,<span class="hljs-attr">"meta"</span>:{<span class="hljs-attr">"name"</span>:<span class="hljs-string">"FastAPI"</span>},<span class="hljs-attr">"score"</span>:<span class="hljs-literal">null</span>,<span class="hljs-attr">"embedding"</span>:<span class="hljs-literal">null</span>},{<span class="hljs-attr">"content"</span>:<span class="hljs-string">"Build production-ready NLP services.  deepset Cloud is a SaaS platform to build natural language processing applications."</span>,<span class="hljs-attr">"content_type"</span>:<span class="hljs-string">"text"</span>,<span class="hljs-attr">"id"</span>:<span class="hljs-string">"4985f3369c9c9c6a6ba179a004b0af72"</span>,<span class="hljs-attr">"meta"</span>:{<span class="hljs-attr">"name"</span>:<span class="hljs-string">"deepset Cloud"</span>},<span class="hljs-attr">"score"</span>:<span class="hljs-literal">null</span>,<span class="hljs-attr">"embedding"</span>:<span class="hljs-literal">null</span>},{<span class="hljs-attr">"content"</span>:<span class="hljs-string">"Haystack is an open-source framework for building search systems that work intelligently over large document collections."</span>,<span class="hljs-attr">"content_type"</span>:<span class="hljs-string">"text"</span>,<span class="hljs-attr">"id"</span>:<span class="hljs-string">"e41e6aeb0ae5965a912b672664e58b7c"</span>,<span class="hljs-attr">"meta"</span>:{<span class="hljs-attr">"name"</span>:<span class="hljs-string">"My first haystack document"</span>},<span class="hljs-attr">"score"</span>:<span class="hljs-literal">null</span>,<span class="hljs-attr">"embedding"</span>:<span class="hljs-literal">null</span>}]
</code></pre><p>There is one crucial thing that you must always pay attention. <strong>Never</strong>, never in any production return all entities into a single call, it may be on HTTP, GRPC, SQL query. Please, never do this! It's a horrible practice. Instead, you should use <em>pagination techniques</em>. </p>
<p>The example is shown just as a multi-document return because I knew only three documents existed. Imagine the damage you would cause to the servers if you had 10 million documents. </p>
<h3 id="heading-querying-the-document-store-directly">Querying the Document Store directly</h3>
<p>We have handy nodes and pipelines on haystack. But you can run queries directly on your Document Store, even using <a target="_blank" href="https://haystack.deepset.ai/reference/document-store#baseelasticsearchdocumentstore">custom DSL queries</a>.</p>
<p>Let's set up a simple "search" endpoint. </p>
<pre><code>@app.get(<span class="hljs-string">"/documents/search/{query}"</span>, status_code<span class="hljs-operator">=</span><span class="hljs-number">200</span>)
def search_document(query: str, response: Response):
    logging.debug(f<span class="hljs-string">"Searching for {query}"</span>)
    documents <span class="hljs-operator">=</span> document_store.query(query)
    <span class="hljs-keyword">return</span> documents
</code></pre><p>We can call it by running:</p>
<pre><code class="lang-curl">curl http://localhost:8000/documents/search/saas
</code></pre>
<p>Our response will be:</p>
<pre><code>[{<span class="hljs-attr">"content"</span>:<span class="hljs-string">"Build production-ready NLP services.  deepset Cloud is a SaaS platform to build natural language processing applications."</span>,<span class="hljs-attr">"content_type"</span>:<span class="hljs-string">"text"</span>,<span class="hljs-attr">"id"</span>:<span class="hljs-string">"4985f3369c9c9c6a6ba179a004b0af72"</span>,<span class="hljs-attr">"meta"</span>:{<span class="hljs-attr">"name"</span>:<span class="hljs-string">"deepset Cloud"</span>},<span class="hljs-attr">"score"</span>:<span class="hljs-number">0.508989096965447</span>,<span class="hljs-attr">"embedding"</span>:<span class="hljs-literal">null</span>}]
</code></pre><p>You must keep in mind two things for this elementary search and query:</p>
<ol>
<li>There are only three documents in our Document Store</li>
<li>SaaS keyword is present in only one document.</li>
<li>The query is concise and limited</li>
</ol>
<p>If we had more documents with the keyword, the BM25 algorithm would help us with many answers and assign scores for each answer.</p>
<p>So remember, haystack is much more potent than this. We are using a tiny piece of the framework, mostly related to primitives and Document Stores. There are outstanding nodes to explore.</p>
<p>Furthermore, we could use a powerful filter on its haystack implementation. It would be something similar to:</p>
<pre><code>filters = {
    <span class="hljs-string">"<span class="hljs-variable">$and</span>"</span>: {
        <span class="hljs-string">"type"</span>: {<span class="hljs-string">"<span class="hljs-variable">$eq</span>"</span>: <span class="hljs-string">"article"</span>},
        <span class="hljs-string">"date"</span>: {<span class="hljs-string">"<span class="hljs-variable">$gte</span>"</span>: <span class="hljs-string">"2015-01-01"</span>, <span class="hljs-string">"<span class="hljs-variable">$lt</span>"</span>: <span class="hljs-string">"2021-01-01"</span>},
        <span class="hljs-string">"rating"</span>: {<span class="hljs-string">"<span class="hljs-variable">$gte</span>"</span>: <span class="hljs-number">3</span>},
        <span class="hljs-string">"<span class="hljs-variable">$or</span>"</span>: {
            <span class="hljs-string">"genre"</span>: {<span class="hljs-string">"<span class="hljs-variable">$in</span>"</span>: [<span class="hljs-string">"economy"</span>, <span class="hljs-string">"politics"</span>]},
            <span class="hljs-string">"publisher"</span>: {<span class="hljs-string">"<span class="hljs-variable">$eq</span>"</span>: <span class="hljs-string">"nytimes"</span>}
        }
    }
}
</code></pre><p>Note: This filter doesn't apply to our current application, it's just an example to understand its logic.</p>
<h3 id="heading-extractive-answer-endpoint">Extractive answer endpoint</h3>
<p>We start by adding some imports:</p>
<pre><code><span class="hljs-keyword">from</span> haystack.nodes <span class="hljs-keyword">import</span> <span class="hljs-title">BM25Retriever</span>, <span class="hljs-title">FARMReader</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">haystack</span>.<span class="hljs-title">pipelines</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">ExtractiveQAPipeline</span>
</code></pre><p>We define a pydantic model:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Query</span>(<span class="hljs-params">BaseModel</span>):</span>
    question: str
</code></pre><p>Then we add the endpoint:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.post("/documents/ask", status_code=200)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ask_document</span>(<span class="hljs-params">query: Query, response: Response</span>):</span>   
    model = <span class="hljs-string">"deepset/roberta-base-squad2"</span>
    retriever = BM25Retriever(document_store)
    reader = FARMReader(model, use_gpu=<span class="hljs-literal">True</span>)
    pipeline = ExtractiveQAPipeline(reader, retriever)
    result = pipeline.run(query=query.question, params={<span class="hljs-string">"Retriever"</span>: {<span class="hljs-string">"top_k"</span>: <span class="hljs-number">10</span>}, <span class="hljs-string">"Reader"</span>: {<span class="hljs-string">"top_k"</span>: <span class="hljs-number">1</span>}})    
    answers = [x.to_dict() <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> result[<span class="hljs-string">"answers"</span>]]
    <span class="hljs-keyword">return</span> answers
</code></pre>
<p>Let's talk a bit about this endpoint. </p>
<p>First, we are defining which model we will use. The company behind haystack, <a target="_blank" href="https://www.deepset.ai/">deepset.ai</a>, has made public some astonishing models on <a target="_blank" href="https://huggingface.co/deepset">Hugging Face</a>. You will find small, medium, and giant models. All of them have excellent quality. Please explore them. Oh, and don't forget to give them a like on Hugging Face. </p>
<p>Then we have set up a BM25Retriever, which will do a sparse search for us. </p>
<p>After that, we set up the FARMReader (our friends also developed FARM at deepset, it's an excellent framework for transfer learning). </p>
<p>We instantiate one of the <a target="_blank" href="https://haystack.deepset.ai/components/ready-made-pipelines">ready-made pipelines</a>. These pipelines fit the most common search patterns and chain haystack components. For example, the <a target="_blank" href="https://haystack.deepset.ai/components/ready-made-pipelines#extractiveqapipeline">ExtractiveQAPipeline</a> searches the OpenSearch document collection and extracts a piece of text (a span) that answer our question.</p>
<p>We call the endpoint:</p>
<pre><code class="lang-curl">curl -X POST http://localhost:8000/documents/ask -H 'Content-Type: application/json' -d '{"question":"What is deepset Cloud?"}'
</code></pre>
<p>Running this for the first time will take some time because haystack will download the model from the Internet. Depending on the model, deepset/roberta-base-squad2 is about 480 MB, and your connection speed can take less or more. But it's a one-time download, as long as you don't clean the virtual environment. </p>
<p>On your command line, you will get something like:</p>
<pre><code>[{<span class="hljs-attr">"answer"</span>:<span class="hljs-string">"a SaaS platform to build natural language processing applications"</span>,<span class="hljs-attr">"type"</span>:<span class="hljs-string">"extractive"</span>,<span class="hljs-attr">"score"</span>:<span class="hljs-number">0.6236580908298492</span>,<span class="hljs-attr">"context"</span>:<span class="hljs-string">"Build production-ready NLP services.  deepset Cloud is a SaaS platform to build natural language processing applications."</span>,<span class="hljs-attr">"offsets_in_document"</span>:[{<span class="hljs-attr">"start"</span>:<span class="hljs-number">55</span>,<span class="hljs-attr">"end"</span>:<span class="hljs-number">120</span>}],<span class="hljs-attr">"offsets_in_context"</span>:[{<span class="hljs-attr">"start"</span>:<span class="hljs-number">55</span>,<span class="hljs-attr">"end"</span>:<span class="hljs-number">120</span>}],<span class="hljs-attr">"document_id"</span>:<span class="hljs-string">"4985f3369c9c9c6a6ba179a004b0af72"</span>,<span class="hljs-attr">"meta"</span>:{<span class="hljs-attr">"name"</span>:<span class="hljs-string">"deepset Cloud"</span>}}]
</code></pre><p>I would like to emphasize some fields of the haystack <a target="_blank" href="https://haystack.deepset.ai/reference/primitives#answer">Answer primitive</a>:</p>
<ul>
<li><p>answer: this is the piece of text that answers your submitted question. It's an extracted text (on this pipeline), which means it's equal to how the answer is present in the document.</p>
</li>
<li><p>score: it's the relevance of the answer.</p>
</li>
<li><p>offsets_in_document: where in the document (sent to OpenSearchDocumentStore) the answer is located.</p>
</li>
<li><p>document_id: the document id where the answer is present.</p>
</li>
</ul>
<h2 id="heading-the-end-for-today">The end (for today)</h2>
<p>Unfortunately, we have come to the end of this article. I want to share more, but keeping some topics separated now is better.</p>
<p>We have built a FastAPI application that provides endpoints for some sparse haystack retrievers. However, there is much more in Haystack:</p>
<ul>
<li>Pre-processing</li>
<li>File converters</li>
<li>Generator</li>
<li>Summarizers</li>
<li>Translators</li>
<li>Rankers</li>
<li>Classifiers</li>
<li>...</li>
</ul>
<p>The list is yet extensive and covers almost all possible NLP search usage. </p>
<h4 id="heading-useful-haystack-links">Useful <strong>Haystack</strong> links</h4>
<ul>
<li>Open an issue <a target="_blank" href="https://github.com/deepset-ai/haystack/issues">here</a>. </li>
<li>Read the <a target="_blank" href="https://haystack.deepset.ai/overview/intro">docs</a>.</li>
<li>Join the <a target="_blank" href="https://haystack.deepset.ai/community/join">newsletter</a></li>
<li>Join the <a target="_blank" href="https://discord.com/invite/VBpFzsgRVF">Discord server</a>.</li>
</ul>
<p>I'm always around Haystack on Discord. So I'll be pleased to talk there.</p>
]]></content:encoded></item><item><title><![CDATA[Serverless Web API with Azure Function v4 and CosmosDB]]></title><description><![CDATA[Today we will together build our first serverless Web API using Azure Functions v4 and CosmosDB as a serverless database.
1. Setup
  First, make sure .NET 6 SDK is installed on your machine. You can get guidance here.
  Then you will need to install ...]]></description><link>https://bichuetti.net/azurefunctions-webapi-cosmosdb</link><guid isPermaLink="true">https://bichuetti.net/azurefunctions-webapi-cosmosdb</guid><category><![CDATA[Azure]]></category><category><![CDATA[serverless]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Daniel Bichuetti]]></dc:creator><pubDate>Sun, 27 Feb 2022 19:16:55 GMT</pubDate><content:encoded><![CDATA[<p>Today we will together build our first serverless Web API using Azure Functions v4 and CosmosDB as a serverless database.</p>
<h3 id="heading-1-setup">1. Setup</h3>
<p>  First, make sure .NET 6 SDK is installed on your machine. You can get guidance <a target="_blank" href="Link">here</a>.
  Then you will need to install <a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#v2">Azure Functions Core Tools 4.x</a>. These tools include a version of the runtime that powers Azure Functions. You will be able to create and deploy functions.</p>
<h3 id="heading-2-create-a-local-project">2. Create a local project</h3>
<p>  Each project may contain one or more individual functions, each supporting different triggers if desired.<br />  Let's create one in-process Azure Function with the runtime I love (.NET).</p>
<pre><code class="lang-csharp">func <span class="hljs-keyword">init</span> FirstFunction --dotnet
</code></pre>
<p>  Then you get into the folder and can add functions to the project. We will add a function named WebApiExample and use the HTTP Trigger template.</p>
<pre><code class="lang-csharp">func <span class="hljs-keyword">new</span> --name WebApiExample --template <span class="hljs-string">"HTTP trigger"</span> --authlevel <span class="hljs-string">"anonymous"</span>
</code></pre>
<p>  I have chosen the authentication level as anonymous since I'm not using it at the moment. In the future, I will add an article about JWT Bearer authentication on Azure Functions, keep an eye out!</p>
<p>  The default template will give you this starting point:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FirstFunction</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WebApiExample</span>
    {
        [<span class="hljs-meta">FunctionName(<span class="hljs-meta-string">"WebApiExample"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">Run</span>(<span class="hljs-params">
            [HttpTrigger(AuthorizationLevel.Anonymous, <span class="hljs-string">"get"</span>, <span class="hljs-string">"post"</span>, Route = <span class="hljs-literal">null</span></span>)] HttpRequest req,
            ILogger log)</span>
        {
            log.LogInformation(<span class="hljs-string">"C# HTTP trigger function processed a request."</span>);

            <span class="hljs-keyword">string</span> name = req.Query[<span class="hljs-string">"name"</span>];

            <span class="hljs-keyword">string</span> requestBody = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> StreamReader(req.Body).ReadToEndAsync();
            <span class="hljs-keyword">dynamic</span> data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            <span class="hljs-keyword">string</span> responseMessage = <span class="hljs-keyword">string</span>.IsNullOrEmpty(name)
                ? <span class="hljs-string">"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."</span>
                : <span class="hljs-string">$"Hello, <span class="hljs-subst">{name}</span>. This HTTP triggered function executed successfully."</span>;

            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(responseMessage);
        }
    }
}
</code></pre>
<h3 id="heading-3-run-your-function">3. Run your function</h3>
<p>At this point, you can already make a simple test and run locally the function. Run this command from your project's folder:</p>
<pre><code class="lang-csharp">func start
</code></pre>
<p>Now we can see some output that contains information about the functions that are running, triggers, methods, and the path. You access it passing the query string that is by default defined (name). Let's give it a try.</p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:7071/api/WebApiExample?name=Daniel</span>
</code></pre><p>The response should be:</p>
<blockquote>
<p>Hello, Daniel</p>
</blockquote>
<h3 id="heading-4-personalize-the-route">4. Personalize the route</h3>
<p>For those who are uncomfortable with the URL pattern <em>*/api/{function name}</em>, it's pretty simple to change it. Just change the <em>Route parameter</em> on the trigger attribute. The result will be something like this:</p>
<pre><code>[HttpTrigger(AuthorizationLevel.Anonymous, <span class="hljs-string">"get"</span>, <span class="hljs-string">"post"</span>, Route = <span class="hljs-string">"test"</span>)]
</code></pre><p>And we would access Function using this path</p>
<blockquote>
<p>http://localhost:7071/api/test?name=Daniel</p>
</blockquote>
<p>You may be questioning yourself about the <em>api</em> prefix. It can be removed, but not here. You need to open the <em>host.json</em> file and alter it to something like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"2.0"</span>,
  <span class="hljs-attr">"extensions"</span>: {
    <span class="hljs-attr">"http"</span>: {
      <span class="hljs-attr">"routePrefix"</span>: <span class="hljs-string">""</span>
    }
  },
    <span class="hljs-attr">"logging"</span>: {
        <span class="hljs-attr">"applicationInsights"</span>: {
            <span class="hljs-attr">"samplingSettings"</span>: {
                <span class="hljs-attr">"isEnabled"</span>: <span class="hljs-literal">true</span>,
                <span class="hljs-attr">"excludedTypes"</span>: <span class="hljs-string">"Request"</span>
            }
        }
    }
}
</code></pre>
<p>As you may be thinking, we have set the route prefix to an empty string. We could have set it to any string allowed on an URL.
By now, we have created a simple Azure Function WebApi and learned how to set up the route, prefix, and suffix. </p>
<h3 id="heading-5-refactoring-for-dependency-injection">5. Refactoring for Dependency Injection</h3>
<p>To make D.I. work we need to make some adjustments. We will add 2 packages to this project.</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package Microsoft.Extensions.DependencyInjection
dotnet <span class="hljs-keyword">add</span> package Microsoft.Azure.Functions.Extensions
</code></pre>
<p>Then we will add one file called <em>Startup.cs</em> (the name is just for better understanding). We need to make some changes to it, so Functions runtime knows where to look for the Startup class and the DI configuration. This is one example of the result.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">assembly:FunctionsStartup(typeof(FirstFunction.Startup))</span>]

<span class="hljs-keyword">namespace</span> <span class="hljs-title">FirstFunction</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span> : <span class="hljs-title">FunctionsStartup</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IFunctionsHostBuilder builder</span>)</span>
        {
            <span class="hljs-comment">// Setup your service collection here, AddLogging() is just example</span>
            builder.Services.AddLogging();
        }
    }
}
</code></pre>
<p>You need to remember these 3 parts. You add the attribute, you <em>inherit from FunctionsStartup</em> and <em>override the Configure method</em>. Then you set up your service collection with the desired lifetime.
We also need to refactor our main function class. It's using a static class and we have to change this. Let's modify it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FirstFunction</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WebApiExample</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WebApiExample</span>(<span class="hljs-params"></span>)</span>
        {
        }  

        [<span class="hljs-meta">FunctionName(<span class="hljs-meta-string">"WebApiExample"</span>)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">Run</span>(<span class="hljs-params">
            [HttpTrigger(AuthorizationLevel.Anonymous, <span class="hljs-string">"get"</span>, <span class="hljs-string">"post"</span>, Route = <span class="hljs-literal">null</span></span>)] HttpRequest req,
            ILogger log)</span>
        {
            log.LogInformation(<span class="hljs-string">"C# HTTP trigger function processed a request."</span>);

            <span class="hljs-keyword">string</span> name = req.Query[<span class="hljs-string">"name"</span>];

            <span class="hljs-keyword">string</span> requestBody = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> StreamReader(req.Body).ReadToEndAsync();
            <span class="hljs-keyword">dynamic</span> data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            <span class="hljs-keyword">string</span> responseMessage = <span class="hljs-keyword">string</span>.IsNullOrEmpty(name)
                ? <span class="hljs-string">"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."</span>
                : <span class="hljs-string">$"Hello, <span class="hljs-subst">{name}</span>. This HTTP triggered function executed successfully."</span>;

            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(responseMessage);
        }
    }
}
</code></pre>
<h3 id="heading-6-injecting-cosmosclient">6. Injecting CosmosClient</h3>
<p>So we have prepared the field for using Cosmos. Now we will add Cosmos SDK and implement its D.I. We start by adding the package to the project since we will be using Cosmos SQL API.</p>
<pre><code class="lang-csharp">dotnet <span class="hljs-keyword">add</span> package Microsoft.Azure.Cosmos
</code></pre>
<p>In the Startup class, we make some changes to the Configure method.</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IFunctionsHostBuilder builder</span>)</span>
{
    builder.Services.AddSingleton&lt;CosmosClient&gt;(sp =&gt; <span class="hljs-keyword">new</span> CosmosClient(
        Environment.GetEnvironmentVariable(<span class="hljs-string">"COSMOSDB_CONNECTIONSTRING"</span>)));
    builder.Services.AddLogging();
}
</code></pre>
<p>Cosmos team instructs to <em>inject CosmosClient as a singleton</em> to avoid issues. We will follow this advice always. The connection string can be found on the Azure portal easily. Maybe you like to test locally and want to give a try to Azure Cosmos DB Emulator. It allows us to run a Cosmos emulator locally so we can make many tests, including throttling requests. You can find a nice guide <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator?tabs=ssl-netstd21Link">here</a>.</p>
<p>We start to make final arrangements for our function class. Let's use the constructor to inject CosmosClient and get the container.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> CosmosClient _cosmosClient;
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> Container _container;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WebApiExample</span>(<span class="hljs-params">CosmosClient cosmosClient</span>)</span>
{
    _cosmosClient= cosmosClient;

    _container = _cosmosClient.GetContainer(<span class="hljs-string">"test-db"</span>, <span class="hljs-string">"test-container"</span>);
}
</code></pre>
<h3 id="heading-7-adding-an-item-to-cosmos">7. Adding an item to Cosmos</h3>
<p>One very important thing is to create the database and container first on Cosmos. We can do it using the portal or programmatically. Avoid doing it programmatically in production on your function. It causes very poor performance. Scenarios you may want to create programmatically (but not inside the function) may be on deployment or seed code. More information can be found <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cosmos-db/sql/how-to-create-container">here</a>. For this example code to work you need to create a Container with the PartitonKey set to /id.
One important note is that CosmosDB demands you to set up a unique "id" property. The partition key is obligatory when creating the container. If you use it when making queries you get better performance and costs.</p>
<p>On the function itself, we will change the accepted method to POST exclusively, since we will be using it to add an item to the database. </p>
<pre><code class="lang-csharp">[<span class="hljs-meta">FunctionName(<span class="hljs-meta-string">"WebApiExample"</span>)</span>]
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">Run</span>(<span class="hljs-params">
    [HttpTrigger(AuthorizationLevel.Anonymous, <span class="hljs-string">"post"</span>, Route = <span class="hljs-string">"test"</span></span>)] HttpRequest req,
    ILogger log)</span>
{
    <span class="hljs-keyword">string</span> requestBody = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> StreamReader(req.Body).ReadToEndAsync();
    <span class="hljs-keyword">dynamic</span> data = JsonConvert.DeserializeObject(requestBody);
    <span class="hljs-keyword">string</span> name = data?.name ?? <span class="hljs-string">"Daniel"</span>;

    <span class="hljs-keyword">string</span> uId = Guid.NewGuid().ToString();

    <span class="hljs-keyword">dynamic</span> newItem = <span class="hljs-keyword">new</span>
    {
        id = uId,
        Name = name

    };
    ItemResponse&lt;<span class="hljs-keyword">dynamic</span>&gt; response = <span class="hljs-keyword">await</span> _container.CreateItemAsync&lt;<span class="hljs-keyword">dynamic</span>&gt;(newItem, <span class="hljs-keyword">new</span> PartitionKey(newItem.id));

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(<span class="hljs-string">$"Request cost: <span class="hljs-subst">{response.RequestCharge}</span>"</span>);
}
</code></pre>
<p>On the above code, we post a JSON body that is similar to:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Name"</span>:<span class="hljs-string">"Paulo"</span>    
}
</code></pre>
<p>Our code then creates a new item with a unique id and adds it to the Cosmos container. If you have followed exactly what I said, your PartitionKey is the same as the unique id. This is not a need, just an example.
Some of you may be wondering what is this response.</p>
<blockquote>
<p>{"RequestCost":5.9}</p>
</blockquote>
<p>CosmosDB SDK returns to us how much <em>RU (Request Units)</em> it has to spend for that request you just made. In a production scenario, we would monitor these costs to set them as low as possible to improve performance and costs.</p>
<h3 id="heading-8-conclusion">8. Conclusion</h3>
<p>In this article, we have been instructed on how to create a serverless Web API that has all basics to build complex ones. We learn how to process JSON requests and return responses, how to personalize routes, and to make some database operations using the blazing fast CosmosDB. The next article will be about JWT Bearer authentication in serverless architecture, see you!</p>
]]></content:encoded></item></channel></rss>