This workshop is targeted for students of EPITA SIGL 2022.
You will learn how to create a Web API using NodeJS and Express.
This template API will expose a single route to get resources for Garlaxy.
Objective: Expose your "ressource" catalog on /v1/resource?page=1&limit=10
From your group's repository (ex: groupe13):
- create a backend folder (same level as frontend)
# from your project's repository, where you can see your frontend/ folder
mkdir -p backend- initiate a new nodejs project using node v16
cd backend
nvm use v16
npm init -y- add express dependency
# still from backend/ folder
npm i --save express- add a first 'Hello World' route to
backend/src/server.js
# From backend/; create a new src/ folder and server.js file
mkdir -p src
touch src/server.js// From backend/src/server.js
const express = require("express");
const app = express();
const port = 3030;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`);
});Run the hello world code from your terminal:
# from backend/
# make sure you are on correct version of node: nvm use v16
node src/server.jsYour web api should listen on localhost:3030.
If you go from your browser, you should see Hello World!.
Now, let's create our database-less resource web API.
Create and copy the content of the following file in your backend/ folder:
- backend/.gitignore ignore trash files when using git add
- backend/src/server.js where you expose your route
- backend/src/database.js where we set our data. This is NOT a real database, we just keep default data in memory. Restarting the app will not persist any data.
- backend/src/utils.js Utilitary functions to help you recover query string parameters (e.g.
pageandlimitfrom resource route)
Now run again your web API locally:
# make sure you've quit previous node src/server.js process
# from backend/
nvm use v16
node src/server.jsYou should be able to query data from localhost:3030/v1/resource?page=1&limit=5. You can query those data via your browser directly, or via cURL from your terminal:
# you need to escape special characters
curl http://localhost:3030/v1/resource\?page\=1\&limit\=5
# or put host in strings
curl 'http://localhost:3030/v1/resource?page=1&limit=5'
# Response:
# {"resources":[{"id":1,"planete":"Marlax","ressource":"Arlaminium","prix":0.73},
# {"id":2,"planete":"Sarlax","ressource":"Arlium","prix":3.25},
# {"id":3,"planete":"Larlune","ressource":"Rarladium","prix":1.42},
# {"id":4,"planete":"Ozinia","ressource":"Elekectium","prix":1.2},
# {"id":5,"planete":"Pinziamia","ressource":"Nontcite","prix":1}]}Note: feel free to check groupe13's STEP 1
Objective: have your "ressource" web API deployed on https://api.groupeXX.arla-sigl.fr (groupXX behing replaced by your groupe)
- Create a new Dockerfile from
backend/folder containing:
# From backend/Dockerfile
FROM node:16
COPY . /code
WORKDIR /code
RUN npm i
CMD ["node", "src/server.js"]
EXPOSE 3030Try out locally using --init flag.
Note: you need to run your docker image with
—initflag because of this known issue from docker + node together
# from backend
docker build -t garlaxy-web-api:local .
#...
docker run --init -p 3033:3030 garlaxy-web-api:localNow make sure you can get "ressource" data on localhost:3033/v1/resource?page=1&limit=5
Now that you have a runnning docker setup for your node web API, let's add a new job to your current CD workflow.
From .github/workflows/main.yml, making sure to replace groupe-XX by your group number
and arla-sigl-2022 by your organization/user's name on github:
# inside .github/workflows/main.yml
# ....
jobs:
build-frontend:
# ...
build-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: build and publish backend docker image
working-directory: backend
run: |
docker build -t docker.pkg.github.com/arla-sigl-2022/groupe-XX/garlaxy-web-api:${{ github.sha }} .
docker login docker.pkg.github.com -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
docker push docker.pkg.github.com/arla-sigl-2022/groupe-XX/garlaxy-web-api:${{ github.sha }}
- name: Deploy on production VM
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
docker login docker.pkg.github.com -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
docker pull docker.pkg.github.com/arla-sigl-2022/groupe-XX/garlaxy-web-api:${{ github.sha }}
(docker stop garlaxy-web-api && docker rm garlaxy-web-api) || echo "Nothing to stop"
docker run -d --name garlaxy-web-api --init --network web --label traefik.enable=true --label traefik.docker.network=web --label traefik.frontend.rule=Host:api.groupeXX.arla-sigl.fr --label traefik.frontend.port=3030 docker.pkg.github.com/arla-sigl-2022/groupe-XX/garlaxy-web-api:${{ github.sha }}It's very similar to your frontend build job, expect:
working-directoryisbackendimage-nameandcontainer-namearegarlaxy-web-apilabelin traefik isapi.groupeXX.arla-sigl.fr--initflag should be there when running the docker container
Commit/push your changes, and you should trigger CD workflow. After few minutes, you should be able to access your web API on https://api.groupeXX.arla-sigl.fr
Note: You can check out groupe 13's Step 1 to Step 2 changes
Objective: Inside your frontend, fetch the list of "ressource" served by your new web API.
Make sure to integrate the following changes to your frontend/:
Now, run both your frontend/ and backend/ from two different terminal sessions:
# from frontend/
nvm use v16
npm start# from backend/
nvm use v16
node src/server.jsYou should see your "Ressource" table with 10 entries coming from your web API on localhost:3000.
Now, let's make sure you can access the web API not from localhost:3030 but from your api.groupeXX.arla-sigl.fr domain.
If you try to just replace the "http://localhost:3030" by your already deployed web API from Step 1, you'll encounter an issue with CORS.
Note: you can check out this Very nice article about CORS on MDN
To solve this issue of cross-origin domains , you will install a new Express middleware called cors.
- [cors middleware], implements mandatory Cross-Origin Ressource Sharing check triggerd by browsers. This middleware is necessary if your frontend is requesting an API on a different domain than the API domain (e.g. from localhost:3030 to api.groupeXX.arla-sigl.fr and groupeXX.arla-sigl.fr to api.groupeXX.arla-sigl.fr)
From your backend/, add the cors middleware:
# from backend/
nvm use v16
npm install --save corsAnd, apply the following changes to both frontend and backend:
Commit and push your changes, and you should be able to use the new version of Garlaxy that uses your own created web API!