Skip to content

ahmed-fawzy99/job_board_api_laravel

Repository files navigation

Job Board API

Contents

Postman Collection

You can interact with the API using the Postman collection provided here: Job Board API Postman Collection

Proceed by installing this project on your local machine first, then import the collection to Postman to start testing the API.

Please note that seeding the database will generate random data, so the results may vary.

Tools

  • Laravel 12

Prerequisites

  • PHP 8.2 or higher
  • Composer
  • PostgreSQL (or any SQL DB)

Installation

Note: The following installation is directed for testing environment. This setup is not production-ready as this is not the purpose of this project.

Follow the following instructions to install the project on your local machine.

 git clone https://github.com/ahmed-fawzy99/job_board_api_laravel.git
 cd job_board_api_laravel
 composer install
 cp .env.example .env 
 php artisan key:generate

Then open .env file do the following fill in your database credentials.

To generate basic data needed to start and test the system, we need to run the migrations and starter seeder:

 php artisan migrate --seed

Run the development server

php artisan serve

API Usage

Endpoints

The Postman collection has the following endpoints with examples. The following are the endpoints:

  • GET /api/v1/jobs - Get all jobs
  • GET /api/v1/jobs/{id} - Get a job by ID
  • GET /api/v1/attributes - Get all attributes
  • GET /api/v1/attributes/{id} - Get an attribute by ID
  • GET /api/v1/categories - Get all categories
  • GET /api/v1/categories/{id} - Get a category by ID
  • GET /api/v1/langauges - Get all languages
  • GET /api/v1/langauges/{id} - Get a language by ID
  • GET /api/v1/locations - Get all locations
  • GET /api/v1/locations/{id} - Get a location by ID

Building Your Queries

Rules

  • All filters and sorting should be passed as query parameters.
  • to filter multiple values, separate them with a comma ,.
    • Example: ?filter[FIELD_NAME]=VALUE1&filter[FIELD_NAME]=VALUE2&sort=FIELD_NAME
  • Multiple filters can be passed in the same query. They will be treated as AND conditions.
    • Example: ?filter[FIELD_NAME1]=VALUE1&filter[FIELD_NAME2]=VALUE2&sort=FIELD_NAME
  • The API supports filtering, sorting, and loading relationships for the jobs resource.
  • The jobs will not contain any relationships by default. You need to include them in the query if you want to load them.
  • The API supports filtering by dynamic attributes. You can filter by any attribute name.

Jobs Filtering and Sorting

Filtering the Results:

  • ?filter[FIELD_NAME]=VALUE - Filter the results by a specific field

  • ?filter[FIELD_NAME]=!Value - Filter the results by a specific field that is not equal to the value.

    • Supported fields: id, title, description, status, and job_type.
  • ?filter[FIELD_NAME]=VALUE1,VALUE2 - Filter the results by a specific field that is equal to one of the values.

    • Supported fields: id, title, description, status, and job_type.
  • ?filter[FIELD_NAME]=*VALUE* - Filter the results by a specific field that contains the value.

    • Supported fields: title, description.
  • ?filter[DATE_FIELD]=VALUE1, - Filter the results by a specific date field that is equal to the passed value.

    • Supported fields: publishedAt, createdAt, and updatedAt.
    • The date should be in the format YYYY-MM-DD or YYYY-MM-DD HH:MM:SS.
  • ?filter[DATE_FIELD]=>VALUE1, - Filter the results by a specific date field that is after the passed value.

    • Supported fields: publishedAt, createdAt, and updatedAt.
    • The date should be in the format YYYY-MM-DD or YYYY-MM-DD HH:MM:SS.
  • ?filter[DATE_FIELD]=<VALUE1, - Filter the results by a specific date field that is before the passed value.

    • Supported fields: publishedAt, createdAt, and updatedAt.
    • The date should be in the format YYYY-MM-DD or YYYY-MM-DD HH:MM:SS.
  • ?filter[DATE_FIELD]=VALUE1,VALUE2 - Filter the results by a specific date field that is between the two passed values.

    • Supported fields: publishedAt, createdAt, and updatedAt.
    • The dates should be in the format YYYY-MM-DD or YYYY-MM-DD HH:MM:SS.
  • ?filter[NUMBER_FIELD]=VALUE1 - Filter the results by a specific number field that is equal to the passed value.

    • Supported fields: salaryMin and salaryMax.
  • ?filter[NUMBER_FIELD]=>VALUE1 - Filter the results by a specific number field that is greater than or equal to the passed value.

    • Supported fields: salaryMin and salaryMax.
  • ?filter[NUMBER_FIELD]=<VALUE1 - Filter the results by a specific number field that is less than or equal to the passed value.

    • Supported fields: salaryMin and salaryMax.
  • ?filter[NUMBER_FIELD]=VALUE1,VALUE2 - Filter the results by a specific number field that is between the two passed values.

    • Supported fields: salaryMin and salaryMax.
  • ?filter[BOOLEAN_FIELD]=true|false - Filter the results by a specific boolean field that is equal to true or false.

    • Supported fields: isRemote.
  • ?filter[attribute:ATTR_NAME]=VALUE - Filter the results by a specific attribute field

    • supported fields: dynamic attributes fields.
  • ?filter[location]=VALUE - Filter the results by a specific location

  • ?filter[location]=VALUE1|VALUE2 - Filter the results by any of the passed locations

  • ?filter[location]=VALUE1,VALUE2 - Filter the results that have all the passed locations

Note: You can also pass remote as a location value to filter remote jobs

  • Example: ?filter[location]=Cairo|remote will return jobs in Cairo or remote jobs.

  • ?filter[language]=VALUE - Filter the results by a specific language

  • ?filter[language]=VALUE1|VALUE2 - Filter the results by any of the passed languages

  • ?filter[language]=VALUE1,VALUE2 - Filter the results that have all the passed languages

Loading Relationships:

  • ?include=RELATIONSHIP_NAME - Load a specific relationship
  • ?include=RELATIONSHIP_NAME1,RELATIONSHIP_NAME2 - Load multiple relationships

Note: Include the plural form of the relationship name. For example, to load the categories relationship, you should use categories instead of category.

Sorting the Results:

  • ?sort=FIELD_NAME - Sort the results by a specific field
  • ?sort=-FIELD_NAME - Sort the results by a specific field in descending order
  • ?sort=FIELD_NAME1,-FIELD_NAME2 - Sort the results by multiple fields

Grouping Conditions

Grouping can be achieved implicitly by passing multiple filters and combining AND/OR operators. This is a design choice to keep the API simple and easy to use. For example, (job_type=full-time AND (languages HAS_ANY (PHP,JavaScript)))AND (locations IS_ANY (New York,Remote)) AND attribute:years_experience>=3 can be achieved by passing the following query:

  • /api/v1/jobs?filter[job_type]=full-time&filter[language]=PHP|JavaScript&filter[attribute:experience_years]=>3&filter[location]=NY|Remote

Other Resources Filtering and Sorting

Not implemented as they are not needed for the current project. However, I've laid out the structure to make it easy to implement in the future.

Example Queries

  • Get all jobs that are published after 2022-01-01 and have a salaryMin greater than or equal to 5000 and are remote:

    • /api/v1/jobs?filter[publishedAt]=>2022-01-01&filter[salaryMin]=>5000&filter[isRemote]=true
  • Get all jobs that are published after 2022-01-01 and have a salaryMin greater than or equal to 5000 and are remote, and include the category relationship, and sort by salaryMin in descending order:

    • /api/v1/jobs?filter[publishedAt]=>2022-01-01&filter[salaryMin]=>5000&filter[isRemote]=true&include=categories&sort=-salaryMin
  • Filter by dynamic attributes:

    • /api/v1/jobs?filter[attribute:experience_years]=12. This will only work if the attribute experience_years exists in the database and the current job utilizes it.
  • Filter full-time jobs, requries PHP or JavaScript, requires min 3 years of experience and in NY or remote:

  • /api/v1/jobs?filter[job_type]=full-time&filter[language]=PHP|JavaScript&filter[attribute:experience_years]=>3&filter[location]=NY|Remote

Design Choices

  • The names of location values (city, state, country), as well as language names, are stored in lowercase to make filtering case-insensitive. Even though it is possible to process case-insensitive queries on both Laravel and Database lever, it's a process that relatively consumes more resources. Therefore, it's better to store the values in lowercase to avoid the need for case-insensitive queries. The client can manage the case sensitivity on their end.
  • As previously mentioned, grouping conditions are not explicitly supported. This is a design choice to keep the API simple and easy to use. The client can achieve grouping by passing multiple filters and combining AND/OR operators.
  • Relationships are not loaded by default. The client needs to include them in the query if they want to load them. This is to avoid unnecessary data transfer and to keep the response size small.

Contact

You can reach me using any of the following media:

About

Job Board API - Laravel

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages