Skip to content

GraphQL on Rails API for Tomo, an app for scheduling language exchange sessions anonymously without the hassles of coordinating logistics.

Notifications You must be signed in to change notification settings

tomo-app/tomo_api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


rails-badge ruby-badge build-badge closed-pr-badge

This GraphQL on Rails API serves queries and mutations to Tomo, an application that allows language learners to schedule anonymous language exchange sessions without the hassles of coordinating a specific date and time.

Live endpoint: https://tomo-api.herokuapp.com/graphql

Stack: Rails, GraphQL, RSpec, Travis CI, Heroku

Readme Content

Local Setup

Prerequisites:

  • Ruby 3.0.1
  • Rails 6.1

Install gems and setup database:

  • Install gems:

    • bundle (if this fails, try to bundle update and then retry)
  • Setup database:

    • rails db:create
    • rails db:migrate
    • rails db:seed
  • To run your own development server:

Test Suite

  • Run with bundle exec rspec
  • All tests should be passing
  • To view specific test coverage: open coverage/index.html

GraphQL Queries and Mutations

Availabilities

  • Get Availabilities: fetch all availabilities for a user by id

    • Type: Availability

    • Arguments:

      argument :user_id, ID, required: true
      argument :status, String, required: false
      
    • Example request
      {
        getAvailabilities(userId: "1") {
          id
          userId
          status
        }
      }
      

  • Create Availability: create new availability slot for a user with default status of 'open'

    • Type: Availability

    • Arguments:

      argument :user_id, ID, required: true
      argument :start_date_time, Integer, required: true
      argument :end_date_time, Integer, required: true
      argument :status, Integer, required: false
      
    • Example request
      mutation {
        createAvailability(input: { params: {
          userId: "2",
          startDateTime: 1609493400,
          endDateTime: 1609504200
        }}) {
          id
          userId
          startDateTime
          endDateTime
          status
        }
      }
      

  • Update Availability: fetch information for a user by id

    • Type: Availability

    • Arguments:

      argument :id, ID, required: true
      argument :start_date_time, Integer, required: false
      argument :end_date_time, Integer, required: false
      argument :status, Integer, required: false
      
    • status: "1": 'fulfilled', status: "2": 'open'

    • Example request
      mutation {
        updateAvailability(input: { 
            id: "2", 
            startDateTime: 1612324800, 
            endDateTime: 1612328400, 
            status: 1
        }) {
          id
          userId
          startDateTime
          endDateTime
          status
        }
      }
      

Blocked Pairings

  • Create Blocked Pairing: create a new blocked pairing for a user
    • Type: Blocked Pairing

    • Arguments:

      argument :blocking_user_id, ID, required: true
      argument :blocked_user_id, ID, required: true
      
    • Example request
      mutation {
        createBlockedPairing(input: { params: {
          blockingUserId: "1",
          blockedUserId: "2"
        }}) {
          id
          blockingUserId
          blockedUserId
        }
      }
      

Languages

  • Get Languages: get all languages currently supported by the application
    • Type: Language

    • Example request
      {
        getLanguages {
          id
          name
        }
      }
      

Pairings

  • Get Pairings: fetch all pairings for a user by id

    • Type: Pairing

    • Argument:

      argument :user_id, ID, required: true
      
    • Example request
      {
        getPairings(userId: "1") {
          id
          user1Id
          user2Id
          cancelled
        }
      }
      

  • Cancel Pairing: fetch all pairings for a user by id

    • Type: Pairing

    • Argument:

      argument :id, ID, required: true
      argument :user_id, ID, required: true
      
    • Example request
      mutation {
        cancelPairing(input: { id: "4", userId: "1" }) {
          id
          user1Id
          user2Id
          user1Cancelled
          user2Cancelled
          cancelled
      

Topics

  • Get Topic and Translations: returns a random topic and any requested translations for 2 languages by language_id
    • Type: Topic

    • Argument:

      argument :language_ids, [ID], required: true
      
    • Example request
      {
        getTopicAndTranslations(languageIds: ["1", "2"]) {
          id
          description
          translations {
            translation
          }
        }
      }
      

User Languages

  • Create User Language: add a new language for a user
    • Type: Blocked Pairing

    • Arguments:

      argument :user_id, ID, required: true
      argument :language_id, ID, required: true
      argument :fluency_level, Integer, required: true
      
    • fluency_level: 0: 'native', fluency_level: 1: 'target'

    • Example request
      mutation {
        createUserLanguage(input: { params: {
          userId: 1,
          languageId: 1,
          fluencyLevel: 1
        }}) {
          id
          userId
          languageId
          fluencyLevel
        }
      }
      

Users

  • Get User: fetch information for a user by id

    • Type: User

    • Argument:

      argument :id, ID, required: true
      
    • Example request
      {
        getUser(id: "1") {
          id
          username
          email
          availabilities {
            id
          }
          userLanguages {
              id
          }
        }
      }
      

  • Authenticate: get a user based on an authentic email/password

    • Type: User

    • Argument:

      argument :email, STRING, required: true
      argument :password, STRING, required: true
      
    • Example request
      {
        authenticate(email: "Jim@gmail.com", password: "1234") {
          id
          username
          email
        }
      }
      

  • Create User: sign up a new user

    • Type: User

    • Arguments:

      argument :email, String, required: true
      argument :username, String, required: true
      argument :password, String, required: true
      argument :password_confirmation, String, required: true
      
    • Example request
      ```
      mutation {
        createUser(input: { params: {
          email: "user@email.com", 
          username: "user", 
          password: "1234", 
          passwordConfirmation: "1234" }
        }) {
          id
          username
          email
        }
      }
      ```
      

  • Update User: update an existing user

    • Type: User

    • Arguments:

      argument :id, Integer, required: true
      argument :email, String, required: false
      argument :username, String, required: false
      argument :target_language_id, String, required: false
      argument :native_language_id, String, required: false
      
    • Example request
      ```
      mutation {
        updateUser(input: {id: 1, username: "person", email: "person@email.com", targetLanguageId: "2", nativeLanguageId: "1"}) {
          id
          username
          email
          userLanguages {
            id
            userId
            languageId
            fluencyLevel
          }
        }
      }
      ```
      

Types

  • Availability

      field :id, ID, null: false
      field :user_id, ID, null: false
      field :start_date_time, String, null: false
      field :end_date_time, String, null: false
      field :status, String, null: false
      field :created_at, String, null: false
      field :updated_at, String, null: false
    
  • Blocked Pairing

      field :id, ID, null: false
      field :blocking_user_id, ID, null: false
      field :blocked_user_id, ID, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
    
  • Language

      field :id, ID, null: false
      field :name, String, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
    
  • Pairing

      field :id, ID, null: false
      field :user1_id, ID, null: false
      field :user2_id, ID, null: false
      field :date_time, Integer, null: false
      field :user1_cancelled, Boolean, null: false
      field :user2_cancelled, Boolean, null: false
      field :cancelled, Boolean, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
    
  • Topic Translation

      field :id, ID, null: false
      field :language_id, ID, null: false
      field :topic_id, ID, null: false
      field :translation, String, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
    
  • Topic

      field :id, ID, null: false
      field :description, String, null: false
      field :translations, [Types::TopicTranslationType], null: true
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
    
  • User Language

      field :id, ID, null: false
      field :user_id, ID, null: false
      field :language_id, ID, null: false
      field :fluency_level, String, null: false
      field :created_at, String, null: false
      field :updated_at, String, null: false
    
  • User

      field :id, ID, null: false
      field :username, String, null: false
      field :email, String, null: false
      field :created_at, GraphQL::Types::ISO8601DateTime, null: false
      field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
      field :availabilities, [Types::AvailabilityType], null: false
      field :user_languages, [Types::UserLanguageType], null: false
    

Database Schema

schema

Tables:

  • Users: users that have signed up for the application
  • Availabilities: user's time slots of open availability for pairing
  • Pairings: language exchange sessions that have been scheduled
  • Blocked Pairings: when a user does not wish no pair with another again, they can add that user to their blocked pairings
  • Languages: languages currently supported by the application
  • User Languages: languages that a user has chosen as either their native or target learning language
  • Topics: conversation topics
  • Topic Translations: translation of each conversation topic to supported languages

FAQs

Technical

  • How are pairings created?
    • User A submits an availability block and a new record in Availbilities table is created with default status of 'open'.
    • Backend searches for another availbility with the following parameters:
      • overlapping date and time
      • availability status = open
      • this availability's user is:
        • studying User A's native language
        • speaks language that User A is studying
        • not on User A's blocked pairing list
        • hasn't blocked User A
    • If above criteria is met, a new pairing record is created at the beginning of the overlap time block.
      • Each user's availbility's status is changed to 'fulfilled'.
    • Note: this is an interim solution. The eventual goal is a more direct scheduling experience (like scheduling a meeting).

Project Board

GitHub project

About

GraphQL on Rails API for Tomo, an app for scheduling language exchange sessions anonymously without the hassles of coordinating logistics.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages