Skip to content

ApiBoy Backend - Easily test your APIs and share them with your team.

Notifications You must be signed in to change notification settings

api-boy/backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ApiBoy Backend

Introduction

ApiBoy is an application for testing APIs, very similar to other tools like Postman and Insomnia, but with some important differences:

  • ApiBoy is 100% open source.
  • ApiBoy is a serverless web application with a simplified set of features in comparison with other tools.
  • ApiBoy can be easily deployed to your own infrastructure at no cost because it uses cloud services that have a comfortable free tier: AWS API Gateway, AWS Lambda, Firebase Realtime Database, Firebase Firestore and Netlify.
  • ApiBoy has real time features for teams to work and collaborate in the same projects at the same time.

The project is composed by a Backend (this repository) and a Frontend.

The Backend is written in Go and uses Firebase Firestore to store data.

The Frontend is implemented with VueJS and connects to Firebase in order to read data and receive changes in real time, while writes are done through the Backend by calling its endpoints.

Demo

Backend Setup

Install go:

Follow the official installation instructions:

Install up:

Follow the official installation instructions:

Install aws cli:

Follow the official installation instructions:

Configure AWS credentials profile for the project:

Add the apiboy profile to the ~/.aws/credentials file with your AWS access and secret keys.

[apiboy]
aws_access_key_id = xxxxxxxx
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxx

Install development tools:

make tools

Install project dependencies:

make deps

Configure project:

The project setup is done with team, that is installed with the development tools. You only need to do these steps once, and the rest of your team developers pointing to the same AWS account will automatically inherit the project configuration by just running or deploying the project.

Create a .team folder for each stage:

mkdir -p .team/development
mkdir -p .team/production

Create two Firebase projects for development and production respectively. Generate a Firebase service account file for each of the projects. Then upload the Firebase service account files for each stage:

# Place the Firebase service account file for development
# in .team/development/firebase-service-account.json and
# then upload it with the following command:
team files upload -s "development" -p ".team/development/firebase-service-account.json"

# Place the Firebase service account file for production
# in .team/production/firebase-service-account.json and
# then upload it with the following command:
team files upload -s "production" -p ".team/production/firebase-service-account.json"

Set environment variables for each stage:

# Set log level:
team env set -s "development" -n "LOG_LEVEL" -v "debug"
team env set -s "production" -n "LOG_LEVEL" -v "info"

# Set firebase project id:
team env set -s "development" -n "FIREBASE_PROJECT_ID" -v "apiboy-dev-xxxxx"
team env set -s "production" -n "FIREBASE_PROJECT_ID" -v "apiboy-prod-zzzzz"

# Set firebase api key:
team env set -s "development" -n "FIREBASE_API_KEY" -v "XXXXXXXXXX"
team env set -s "production" -n "FIREBASE_API_KEY" -v "ZZZZZZZZZZ"

# Set jwt issuer:
team env set -s "development" -n "JWT_ISSUER" -v "apiboy-dev"
team env set -s "production" -n "JWT_ISSUER" -v "apiboy-prod"

# Set jwt sign key:
team env set -s "development" -n "JWT_SIGN_KEY" -v "XXXXXXXXXX"
team env set -s "production" -n "JWT_SIGN_KEY" -v "ZZZZZZZZZZ"

Configure the access rules for the Firestore Database with the following code:

service cloud.firestore {
  match /databases/{database}/documents {
  	function signedIn() {
      return request.auth.uid != null;
    }
    
    function validProjectForUser(projectId) {
      return exists(/databases/$(database)/documents/projectusers/$(projectId + "-" + request.auth.uid));
    }
  
    match /{document=**} {
      allow read, write: if false;
    }
    
    match /users/{userId} {
      allow read: if signedIn() && resource.data.id == request.auth.uid;
    }
    
    match /projects/{projectId} {
      allow read: if signedIn() && validProjectForUser(resource.data.id);
    }
    
    match /projectusers/{projectUserId} {
      allow read: if signedIn() && resource.data.user_id == request.auth.uid;
    }
    
    match /folders/{folderId} {
      allow read: if signedIn() && validProjectForUser(resource.data.project_id);
    }
    
    match /requests/{requestId} {
      allow read: if signedIn() && validProjectForUser(resource.data.project_id);
    }

    match /environments/{environmentId} {
      allow read: if signedIn() && validProjectForUser(resource.data.project_id);
    }
  }
}

Configure the access rules for the Realtime Database with the following code:

{
  "rules": {
    "presence": {
      ".read": "auth != null",
      ".write": "auth != null",
      "$projectId": {
        "$deviceId": {
          ".validate": "newData.hasChildren(['id', 'name', 'email'])",
          "id": {
            ".validate": "newData.val() == auth.uid"
          },
          "name": {
            ".validate": "newData.val() == auth.token.user_name"
          },
          "email": {
            ".validate": "newData.val() == auth.token.user_email"
          },
          "$other": {
            ".validate": false
          }
        }
      }
    }
  }
}

Backend Execution / Deployment

Run development stage:

make dev

Deploy production stage:

make production