• 18-19 College Green, Dublin 2
  • 01 685 9088
  • info@cunninghamwebsolutions.com
  • cunninghamwebsolutions
    Cunningham Web Solutions
    • Home
    • About Us
    • Our Services
      • Web Design
      • Digital Marketing
      • SEO Services
      • E-commerce Websites
      • Website Redevelopment
      • Social Media Services
    • Digital Marketing
      • Adwords
      • Social Media Services
      • Email Marketing
      • Display Advertising
      • Remarketing
    • Portfolio
    • FAQ’s
    • Blog
    • Contact Us
    MENU CLOSE back  

    Mirage JS Deep Dive: Understanding Factories, Fixtures And Serializers (Part 2)

    You are here:
    1. Home
    2. Web Design
    3. Mirage JS Deep Dive: Understanding Factories, Fixtures And Serializers (Part 2)
    Thumbnail for 25040
    Smashing Editorial

    Mirage JS Deep Dive: Understanding Factories, Fixtures And Serializers (Part 2)

    Mirage JS Deep Dive: Understanding Factories, Fixtures And Serializers (Part 2)

    Kelvin Omereshone

    2020-05-29T11:00:00+00:00
    2020-05-29T12:38:34+00:00

    In the previous article of this series, we understudied Models and Associations as they relate to Mirage. I explained that Models allow us to create dynamic mock data that Mirage would serve to our application when it makes a request to our mock endpoints. In this article, we will look at three other Mirage features that allow for even more rapid API mocking. Let’s dive right in!

    Note: I highly recommend reading my first two articles if you haven’t to get a really solid handle on what would be discussed here. You could however still follow along and reference the previous articles when necessary.

    • Setting Up API Mocking With Mirage JS And Vue
    • Mirage JS Models And Associations

    Factories

    In a previous article, I explained how Mirage JS is used to mock backend API, now let’s assume we are mocking a product resource in Mirage. To achieve this, we would create a route handler which will be responsible for intercepting requests to a particular endpoint, and in this case, the endpoint is api/products. The route handler we create will return all products. Below is the code to achieve this in Mirage:

    import { Server, Model } from 'miragejs';
    
    new Server({
        models: {
          product: Model,
        },
    
       routes() {
            this.namespace = "api";
            this.get('products', (schema, request) => {
            return schema.products.all()
        })
       }
    });
        },
    

    The output of the above would be:

    {
      "products": []
    }
    

    We see from the output above that the product resource is empty. This is however expected as we haven’t created any records yet.

    Pro Tip: Mirage provides shorthand needed for conventional API endpoints. So the route handler above could also be as short as: this.get('/products').

    Let’s create records of the product model to be stored in Mirage database using the seeds method on our Server instance:

     seeds(server) {
          server.create('product', { name: 'Gemini Jacket' })
          server.create('product', { name: 'Hansel Jeans' })
      },
    

    The output:

    {
      "products": [
        {
          "name": "Gemini Jacket",
          "id": "1"
        },
        {
          "name": "Hansel Jeans",
          "id": "2"
        }
      ]
    }
    

    As you can see above, when our frontend application makes a request to /api/products, it will get back a collection of products as defined in the seeds method.

    Using the seeds method to seed Mirage’s database is a step from having to manually create each entry as an object. However, it wouldn’t be practical to create 1000(or a million) new product records using the above pattern. Hence the need for factories.

    Factories Explained

    Factories are a faster way to create new database records. They allow us to quickly create multiple records of a particular model with variations to be stored in the Mirage JS database.

    Factories are also objects that make it easy to generate realistic-looking data without having to seed those data individually. Factories are more of recipes or blueprints for creating records off models.

    Creating A Factory

    Let’s examine a Factory by creating one. The factory we would create will be used as a blueprint for creating new products in our Mirage JS database.

    import { Factory } from 'miragejs'
    
    new Server({
        // including the model definition for a better understanding of what's going on
        models: {
            product: Model
        },
        factories: {
            product: Factory.extend({})
        }
    })
    

    From the above, you’d see we added a factories property to our Server instance and define another property inside it that by convention is of the same name as the model we want to create a factory for, in this case, that model is the product model. The above snippet depicts the pattern you would follow when creating factories in Mirage JS.

    Although we have a factory for the product model, we really haven’t added properties to it. The properties of a factory can be simple types like strings, booleans or numbers, or functions that return dynamic data as we would see in the full implementation of our new product factory below:

    import { Server, Model, Factory } from 'miragejs'
    
    new Server({
        models: {
            product: Model
        },
    
       factories: {
          product: Factory.extend({
            name(i) {
              //  i is the index of the record which will be auto incremented by Mirage JS
              return `Awesome Product ${i}`; // Awesome Product 1, Awesome Product 2, etc.
            },
            price() {
              let minPrice = 20;
              let maxPrice = 2000;
              let randomPrice =
                Math.floor(Math.random() * (maxPrice - minPrice + 1)) + minPrice;
              return `$ ${randomPrice}`;
            },
            category() {
              let categories = [
                'Electronics',
                'Computing',
                'Fashion',
                'Gaming',
                'Baby Products',
              ];
              let randomCategoryIndex = Math.floor(
                Math.random() * categories.length
              );
              let randomCategory = categories[randomCategoryIndex];
              return randomCategory;
            },
             rating() {
              let minRating = 0
              let maxRating = 5
              return Math.floor(Math.random() * (maxRating - minRating + 1)) + minRating;
            },
          }),
        },
    })
    

    In the above code snippet, we are specifying some javascript logic via Math.random to create dynamic data each time the factory is used to create a new product record. This shows the strength and flexibility of Factories.

    Let’s create a product utilizing the factory we defined above. To do that, we call server.create and pass in the model name (product) as a string. Mirage will then create a new record of a product using the product factory we defined. The code you need in order to do that is the following:

    new Server({
        seeds(server) {
            server.create("product")
        }
    })
    

    Pro Tip: You can run console.log(server.db.dump()) to see the records in Mirage’s database.

    A new record similar to the one below was created and stored in the Mirage database.

    {
      "products": [
        {
          "rating": 3,
          "category": "Computing",
          "price": "$739",
          "name": "Awesome Product 0",
          "id": "1"
        }
      ]
    }
    

    Overriding factories

    We can override some or more of the values provided by a factory by explicitly passing them in like so:

    server.create("product", {name: "Yet Another Product", rating: 5, category: "Fashion" })
    

    The resulting record would be similar to:

    {
      "products": [
        {
          "rating": 5,
          "category": "Fashion",
          "price": "$782",
          "name": "Yet Another Product",
          "id": "1"
        }
      ]
    }
    

    createList

    With a factory in place, we can use another method on the server object called createList. This method allows for the creation of multiple records of a particular model by passing in the model name and the number of records you want to be created. Below is it’s usage:

    server.createList("product", 10)
    

    Or

    server.createList("product", 1000)
    

    As you’ll observe, the createList method above takes two arguments: the model name as a string and a non-zero positive integer representing the number of records to create. So from the above, we just created 500 records of products! This pattern is useful for UI testing as you’ll see in a future article of this series.

    Fixtures

    In software testing, a test fixture or fixture is a state of a set or collection of objects that serve as a baseline for running tests. The main purpose of a fixture is to ensure that the test environment is well known in order to make results repeatable.

    Mirage allows you to create fixtures and use them to seed your database with initial data.

    Note: It is recommended you use factories 9 out of 10 times though as they make your mocks more maintainable.

    Creating A Fixture

    Let’s create a simple fixture to load data onto our database:

     fixtures: {
          products: [
            { id: 1, name: 'T-shirts' },
            { id: 2, name: 'Work Jeans' },
          ],
      },
    

    The above data is automatically loaded into the database as Mirage’s initial data. However, if you have a seeds function defined, Mirage would ignore your fixture with the assumptions that you meant for it to be overridden and instead use factories to seed your data.

    Fixtures In Conjunction With Factories

    Mirage makes provision for you to use Fixtures alongside Factories. You can achieve this by calling server.loadFixtures(). For example:

     fixtures: {
        products: [
          { id: 1, name: "iPhone 7" },
          { id: 2, name: "Smart TV" },
          { id: 3, name: "Pressing Iron" },
        ],
      },
    
      seeds(server) {
        // Permits both fixtures and factories to live side by side
        server.loadFixtures()
    
        server.create("product")
      },
    

    Fixture files

    Ideally, you would want to create your fixtures in a separate file from server.js and import it. For example you can create a directory called fixtures and in it create products.js. In products.js add:

    // <PROJECT-ROOT>/fixtures/products.js
    export default [
      { id: 1, name: 'iPhone 7' },
      { id: 2, name: 'Smart TV' },
      { id: 3, name: 'Pressing Iron' },
    ];
    

    Then in server.js import and use the products fixture like so:

    import products from './fixtures/products';
     fixtures: {
        products,
     },
    

    I am using ES6 property shorthand in order to assign the products array imported to the products property of the fixtures object.

    It is worthy of mention that fixtures would be ignored by Mirage JS during tests except you explicitly tell it not to by using server.loadFixtures()

    Factories vs. Fixtures

    In my opinion, you should abstain from using fixtures except you have a particular use case where they are more suitable than factories. Fixtures tend to be more verbose while factories are quicker and involve fewer keystrokes.

    Serializers

    It’s important to return a JSON payload that is expected to the frontend hence serializers.

    A serializer is an object that is responsible for transforming a **Model** or **Collection** that’s returned from your route handlers into a JSON payload that’s formatted the way your frontend app expects.

    Mirage Docs

    Let’s take this route handler for example:

    this.get('products/:id', (schema, request) => {
            return schema.products.find(request.params.id);
          });
    

    A Serializer is responsible for transforming the response to something like this:

    {
      "product": {
        "rating": 0,
        "category": "Baby Products",
        "price": "$654",
        "name": "Awesome Product 1",
        "id": "2"
      }
    }
    

    Mirage JS Built-in Serializers

    To work with Mirage JS serializers, you’d have to choose which built-in serializer to start with. This decision would be influenced by the type of JSON your backend would eventually send to your front-end application. Mirage comes included with the following serializers:

    • JSONAPISerializer
      This serializer follows the JSON:API spec.
    • ActiveModelSerializer
      This serializer is intended to mimic APIs that resemble Rails APIs built with the active_model_serializer gem.
    • RestSerializer
      The RestSerializer is Mirage JS “catch all” serializer for other common APIs.

    Serializer Definition

    To define a serialize, import the appropriate serializer e.g RestSerializer from miragejs like so:

    import { Server, RestSerializer } from "miragejs"
    

    Then in the Server instance:

    new Server({
      serializers: {
        application: RestSerializer,
      },
    })
    

    The RestSerializer is used by Mirage JS by default. So it’s redundant to explicitly set it. The above snippet is for exemplary purposes.

    Let’s see the output of both JSONAPISerializer and ActiveModelSerializer on the same route handler as we defined above

    JSONAPISerializer

    import { Server, JSONAPISerializer } from "miragejs"
    new Server({
      serializers: {
        application: JSONAPISerializer,
      },
    })
    

    The output:

    {
      "data": {
        "type": "products",
        "id": "2",
        "attributes": {
          "rating": 3,
          "category": "Electronics",
          "price": "$1711",
          "name": "Awesome Product 1"
        }
      }
    }
    

    ActiveModelSerializer

    To see the ActiveModelSerializer at work, I would modify the declaration of category in the products factory to:

    productCategory() {
              let categories = [
                'Electronics',
                'Computing',
                'Fashion',
                'Gaming',
                'Baby Products',
              ];
              let randomCategoryIndex = Math.floor(
                Math.random() * categories.length
              );
              let randomCategory = categories[randomCategoryIndex];
              return randomCategory;
            },
    

    All I did was to change the name of the property to productCategory to show how the serializer would handle it.

    Then, we define the ActiveModelSerializer serializer like so:

    import { Server, ActiveModelSerializer } from "miragejs"
    new Server({
      serializers: {
        application: ActiveModelSerializer,
      },
    })
    

    The serializer transforms the JSON returned as:

    {
      "rating": 2,
      "product_category": "Computing",
      "price": "$64",
      "name": "Awesome Product 4",
      "id": "5"
    }
    

    You’ll notice that productCategory has been transformed to product_category which conforms to the active_model_serializer gem of the Ruby ecosystem.

    Customizing Serializers

    Mirage provides the ability to customize a serializer. Let’s say your application requires your attribute names to be camelcased, you can override RestSerializer to achieve that. We would be utilizing the lodash utility library:

    import { RestSerializer } from 'miragejs';
    import { camelCase, upperFirst } from 'lodash';
    serializers: {
          application: RestSerializer.extend({
            keyForAttribute(attr) {
              return upperFirst(camelCase(attr));
            },
          }),
        },
    

    This should produce JSON of the form:

     {
          "Rating": 5,
          "ProductCategory": "Fashion",
          "Price": "$1386",
          "Name": "Awesome Product 4",
          "Id": "5"
        }
    

    Wrapping Up

    You made it! Hopefully, you’ve got a deeper understanding of Mirage via this article and you’ve also seen how utilizing factories, fixtures, and serializers would enable you to create more production-like API mocks with Mirage. Look out for the next part of this series.

    (ra, il)

    From our sponsors: Mirage JS Deep Dive: Understanding Factories, Fixtures And Serializers (Part 2)

    Posted on 29th May 2020Web Design
    FacebookshareTwittertweetGoogle+share

    Related posts

    Archived
    22nd March 2023
    Archived
    18th March 2023
    Archived
    20th January 2023
    Thumbnail for 25788
    Handling Continuous Integration And Delivery With GitHub Actions
    19th October 2020
    Thumbnail for 25778
    A Monthly Update With New Guides And Community Resources
    19th October 2020
    Thumbnail for 25781
    Supercharge Testing React Applications With Wallaby.js
    19th October 2020
    Latest News
    • Archived
      22nd March 2023
    • Archived
      18th March 2023
    • Archived
      20th January 2023
    • 20201019 ML Brief
      19th October 2020
    • Thumbnail for 25788
      Handling Continuous Integration And Delivery With GitHub Actions
      19th October 2020
    • Thumbnail for 25786
      The Future of CX with Larry Ellison
      19th October 2020
    News Categories
    • Digital Marketing
    • Web Design

    Our services

    Website Design
    Website Design

    A website is an important part of any business. Professional website development is an essential element of a successful online business.

    We provide website design services for every type of website imaginable. We supply brochure websites, E-commerce websites, bespoke website design, custom website development and a range of website applications. We love developing websites, come and talk to us about your project and we will tailor make a solution to match your requirements.

    You can contact us by phone, email or send us a request through our online form and we can give you a call back.

    More Information

    Digital Marketing
    Digital Marketing

    Our digital marketeers have years of experience in developing and excuting digital marketing strategies. We can help you promote your business online with the most effective methods to achieve the greatest return for your marketing budget. We offer a full service with includes the following:

    1. Social Media Marketing

    2. Email & Newsletter Advertising

    3. PPC - Pay Per Click

    4. A range of other methods are available

    More Information

    SEO
    SEO Services

    SEO is an essential part of owning an online property. The higher up the search engines that your website appears, the more visitors you will have and therefore the greater the potential for more business and increased profits.

    We offer a range of SEO services and packages. Our packages are very popular due to the expanse of on-page and off-page SEO services that they cover. Contact us to discuss your website and the SEO services that would best suit to increase your websites ranking.

    More Information

    E-commerce
    E-commerce Websites

    E-commerce is a rapidly growing area with sales online increasing year on year. A professional E-commerce store online is essential to increase sales and is a reflection of your business to potential customers. We provide professional E-commerce websites custom built to meet our clients requirements.

    Starting to sell online can be a daunting task and we are here to make that journey as smooth as possible. When you work with Cunningham Web Solutions on your E-commerce website, you will benefit from the experience of our team and every detail from the website design to stock management is carefully planned and designed with you in mind.

    More Information

    Social Media Services
    Social Media Services

    Social Media is becoming an increasingly effective method of marketing online. The opportunities that social media marketing can offer are endless and when managed correctly can bring great benefits to every business.

    Social Media Marketing is a low cost form of advertising that continues to bring a very good ROI for our clients. In conjuction with excellent website development and SEO, social media marketing should be an essential part of every digital marketing strategy.

    We offer Social Media Management packages and we also offer Social Media Training to individuals and to companies. Contact us to find out more.

    More Information

    Cunningham Web Solutions
    © Copyright 2025 | Cunningham Web Solutions
    • Home
    • Our Services
    • FAQ's
    • Account Services
    • Privacy Policy
    • Contact Us