avatarBogdan Cojocar

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

5810

Abstract

div id="2fc2"><pre>npm install express express-session keycloak-connect nodemon</pre></div><h2 id="592f">Define main execution file — app.js</h2><p id="f128">Add a file named app.js at the root level of your secure-express-service project.</p><p id="8d46">Define imports and express app</p><div id="54ca"><pre><span class="hljs-comment">// file - app.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>); <span class="hljs-keyword">const</span> session = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express-session"</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Keycloak</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">"keycloak-connect"</span>);

<span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>(); <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">PORT</span> = <span class="hljs-number">3000</span>;

...</pre></div><p id="ccec">Setup Keycloak Middleware</p><div id="cefb"><pre><span class="hljs-comment">// file - app.js</span>

...

<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">USER_ROLE</span> = process.<span class="hljs-property">env</span>.<span class="hljs-property">USER_ROLE</span> || <span class="hljs-string">'express-user'</span>; <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">ADMIN_ROLE</span> = process.<span class="hljs-property">env</span>.<span class="hljs-property">ADMIN_ROLE</span> || <span class="hljs-string">'express-admin'</span>;

<span class="hljs-keyword">const</span> kcConfig = { <span class="hljs-attr">clientId</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">AUTH_CLIENT_ID</span> || <span class="hljs-string">'secure-express-service'</span>, <span class="hljs-attr">bearerOnly</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">serverUrl</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">AUTH_SERVER</span> || <span class="hljs-string">'http://localhost:8080'</span>, <span class="hljs-attr">realm</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">AUTH_REALM</span> || <span class="hljs-string">'master'</span> };

<span class="hljs-keyword">const</span> memoryStore = <span class="hljs-keyword">new</span> session.<span class="hljs-title class_">MemoryStore</span>();

<span class="hljs-title class_">Keycloak</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">accessDenied</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params">request, response</span>) { response.<span class="hljs-title function_">status</span>(<span class="hljs-number">401</span>) response.<span class="hljs-title function_">setHeader</span>(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>) response.<span class="hljs-title function_">end</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({ <span class="hljs-attr">status</span>: <span class="hljs-number">401</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Unauthorized/Forbidden'</span>, <span class="hljs-attr">result</span>: { <span class="hljs-attr">errorCode</span>: <span class="hljs-string">'ERR-401'</span>, <span class="hljs-attr">errorMessage</span>: <span class="hljs-string">'Unauthorized/Forbidden'</span> } })) }

<span class="hljs-keyword">const</span> keycloak = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Keycloak</span>({ <span class="hljs-attr">store</span>: memoryStore }, kcConfig);

<span class="hljs-keyword">function</span> <span class="hljs-title function_">adminOnly</span>(<span class="hljs-params">token, request</span>) { <span class="hljs-keyword">return</span> token.<span class="hljs-title function_">hasRole</span>(<span class="hljs-string">realm:<span class="hljs-subst">${ADMIN_ROLE}</span></span>); }

<span class="hljs-keyword">function</span> <span class="hljs-title function_">isAuthenticated</span>(<span class="hljs-params">token, request</span>) { <span class="hljs-keyword">return</span> token.<span class="hljs-title function_">hasRole</span>(<span class="hljs-string">realm:<span class="hljs-subst">${ADMIN_ROLE}</span></span>) || token.<span class="hljs-title function_">hasRole</span>(<span class="hljs-string">realm:<span class="hljs-subst">${USER_ROLE}</span></span>); }

app.<span class="hljs-title function_">use</span>(<span class="hljs-title function_">session</span>({ <span class="hljs-attr">secret</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">APP_SECRET</span> || <span class="hljs-string">'BV&%R*BD66JH'</span>, <span class="hljs-attr">resave</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">saveUninitialized</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">store</span>: memoryStore }));

app.<span class="hljs-title function_">use</span>( keycloak.<span class="hljs-title function_">middleware</span>() );

...</pre></div><p id="bfe2">Setup REST endpoint and server</p><div id="5fc0"><pre>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/public'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>({ <span class="hljs-string

Options

">'message'</span>: <span class="hljs-string">"This is a public enpoint which can be accessed by anonymous users"</span>, }); })

app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/secured'</span>, [keycloak.<span class="hljs-title function_">protect</span>(isAuthenticated)], <span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>({ <span class="hljs-string">'message'</span>: <span class="hljs-string">"This is a secured enpoint which can be accessed by any authenticated user"</span>, }); })

app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/secured-admin'</span>, [keycloak.<span class="hljs-title function_">protect</span>(adminOnly)], <span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>({ <span class="hljs-string">'message'</span>: <span class="hljs-string">"This is a secured enpoint which can be accessed only by any authenticated user with role admin"</span>, }); })

app.<span class="hljs-title function_">listen</span>(<span class="hljs-variable constant_">PORT</span>, <span class="hljs-function">(<span class="hljs-params">error</span>) =></span> { <span class="hljs-keyword">if</span> (!error) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Server is Successfully Running, and App is listening on port "</span> + <span class="hljs-variable constant_">PORT</span>) } <span class="hljs-keyword">else</span> { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error occurred, server can't start"</span>, error); } } );</pre></div><h2 id="a530">Update package.json scripts to run server</h2><ul><li>Update the content in the <b>scripts </b>section of <b>package.json</b> as below. It will help you run your express server in both development and production mode</li></ul><div id="6d0e"><pre> <span class="hljs-attr">"scripts"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"start"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"node app.js"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"dev"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"nodemon app.js"</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span></pre></div><ul><li>Start your express server in development mode(auto-reload on file change) using the below command</li></ul><div id="464c"><pre>npm run dev</pre></div><h1 id="1699">Testing your REST APIs</h1><h2 id="f8a6">Public Endpoint— http://localhost:3000/public</h2><ul><li>Even without an authentication token, this endpoint will fetch a response.</li></ul><figure id="74df"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*xjvkOCdQJ5VIolwBtu-TWg.png"><figcaption></figcaption></figure><h2 id="f796">Secured Endpoint — http://localhost:3000/secured</h2><ul><li>Without a token, you should get an authentication error</li></ul><figure id="ad69"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*rSANl9_J1BRma6p1UjgLPg.png"><figcaption></figcaption></figure><ul><li>Let’s set up the <b>Authorization</b> tab to generate a token using the <b>Configure New Token </b>section. You can use the values below.</li></ul><div id="3d60"><pre>Token <span class="hljs-type">Name</span> - secure-express-service <span class="hljs-keyword">Grant</span> <span class="hljs-keyword">type</span> - <span class="hljs-keyword">Password</span> Credentials <span class="hljs-keyword">Access</span> Token URL - http://localhost:<span class="hljs-number">8080</span>/realms/master/protocol/openid-<span class="hljs-keyword">connect</span>/token Client ID - secure-express-service Username - <span class="hljs-keyword">user</span>@nerdcore.com <span class="hljs-keyword">Password</span> - Client Authentication - Send <span class="hljs-keyword">as</span> basic auth <span class="hljs-keyword">header</span></pre></div><figure id="5d0e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*AEhl6BHxVPT5J6X6wKnxGg.png"><figcaption></figcaption></figure><ul><li>Click on <b>Get New Access Token</b>, then P<b>roceed</b>, then <b>Use Token</b></li></ul><figure id="ea60"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*t7pdQRYhqsnhK_NDBSD19g.png"><figcaption></figcaption></figure><figure id="55e0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*MwMrf1npagIRpGmXEfOWcw.png"><figcaption></figcaption></figure><ul><li>Now fire the <b>/secured</b> rest endpoint again, and you will get a successful response.</li></ul><figure id="e106"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*xsq6E7TWbMeTHXzNEQMD1Q.png"><figcaption></figcaption></figure><h2 id="97a4">Secured Admin Endpoint — http://localhost:3000/secured-admin</h2><ul><li>If you try to access the endpoint without any token — Auth error</li><li>If you try to access the endpoint with the token from [email protected] — Auth error</li><li>If you try to access the endpoint with the token from [email protected] — Success</li></ul><p id="db11">You can find the GitHub repository <a href="https://github.com/saurav-samantray/secure-express-service">here</a> for reference.</p><p id="eda2">Happy learning and happy coding!</p></article></body>

How to read data from AWS S3 and Athena in pandas with column validation

This is a step by step tutorial on reading data from AWS S3 and Athena into a pandas DataFrame and doing column validation to assess the quality of the data.

Step 1: Install the python dependencies needed

We’ll need two python libraries for this:

pip install awswrangler
pip install pandas_schema

Step 2: Add your AWS credentials

In order to be able to reach your AWS account we will have to setup the credentials. We should have a file ~/.aws/credentials with the structure:

[default] 
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
region = YOUR_AWS_REGION

Step 3: Read data from AWS

Now we will be able to read the data from S3 or from an Athena easily using the awswrangler library:

import awswrangler as wr
df_s3 = wr.s3.read_csv(path='s3://bucket/prefix/')
df_athena = wr.athena.read_sql_query("SELECT col1,col2,col3 FROM table", database="db")

If the data in s3 is partitioned for example by year and date, we can use a pushdown filter to read only relevant partitions. For example we have in s3 the paths:

s3://bucket/prefix/year=2022/month=10/
s3://bucket/prefix/year=2022/month=11/
s3://bucket/prefix/year=2023/month=10/

To read only the data from 2022 October we use the logic:

pushdown_filter = lambda x: True if x["year"]== "2022" and x["month"] == "10" else False
df_filter = wr.s3.read_csv("s3://bucket/prefix/", dataset=True, partition_filter=pushdown_filter)

Step 4: Add data validation

After we read the data we can apply column validation. Let’s day we read a DataFrame that contains 3 columns: age, sexand date:

age,sex,date
10,Male,2022-10-10
85,Female,2022-11-11
24,Female,2020-10-10

To be able to validate the data we’ll have to create a schema:

from pandas_schema import Column, Schema
from pandas_schema.validation import InRangeValidation, InListValidation,DateFormatValidation
schema = Schema([
    Column('age', [InRangeValidation(0, 100)]),
    Column('sex', [InListValidation(['Male', 'Female', 'Other'])]),
    Column('date', [DateFormatValidation('%Y-%m-%d')])
])

So the schema will check that the age column is in range 0–100, the sex column contain values from a list, and the date column should have a certain format.

Step 5: Check data validation

We can apply the schema on our DataFrames:

errors = schema.validate(df_s3)
errors_index_rows = [e.row for e in errors]
df_clean = df_s3.drop(index=errors_index_rows)

All the rows that have invalid data will be stored in the errors DataFrame. To eliminate there error rows we can drop them from the df_s3 DataFrame.

Pandas
Python
Recommended from ReadMedium