0

I need load my apikeys from json file (api.json) with file structure api.json:

{
"service1": ["apikey1", "apikey2"],
"service2": ["apikey1", "apikey2"],
}

I have a class that describes a key & value:

class ApiKey {
   constructor(apiName: String, apiKeys: Array<String>)
}

And I have a class, that loads all keys from file to Array:

//read file async: https://stackoverflow.com/questions/46867517/how-to-read-file-with-async-await-properly
    import { readFile } from 'fs'
    import { promisify } from 'util'
    import { join } from 'path'

    export class ApikeysService {

    constructor(private apiKeys: Array<ApiKey> = new Array<ApiKey>()) {
        this.loadKeys()
    }

    public loadKeys () {
        const filePath      = join(__dirname, "../../../", "api.json");
        const readfile      = promisify(readFile);
        const result        = readfile(filePath, "utf8")
                                .then(content => JSON.parse(content))
                                .then(result => {
                                    Object.keys(result).forEach(key => {
                                        this.apikeys.push(new ApiKey(key, result[key]))
                                    })
                                })
        
    }

    public getKeyFor(name: String) {
        return this.keyCounters.find(x => x.keyname == name).apiKeys
    }

}

And my tests:

describe('should load api keys', () => { 
    it("should load apikeys from file", async () => {
         const service = new ApikeysService ()
         it("should load api keys for service1", () => {
    

         expect(service.getKeyFor("service1")[0]).toEqual("apikey1")
         expect(service.getKeyFor("service1")[1]).toEqual("apikey2")

    })
})

Test Result:

expect(received).toEqual(expected) // deep equality

>     Expected: "apikey1"
>     Received: undefined

I tried i lot of different ways to load contents from file to array in class (async also) but it wont work

3
  • You are firing an async function in your constructor, and checking the result directly afterwards - you give no chance for the promise to resolve. It is not synchronous. Either return result from loadKeys and make sure to await it, or change it to become synchronous, using readFileSync Commented Jun 1, 2022 at 12:41
  • 1
    Apart from the async issue mentioned in the previous comment, this code is needlessly complicated. this.apiKeys = JSON.parse(content) will do all that you need. There's no need to unpack the JSON object and then rebuild it into the same thing you started with. Commented Jun 1, 2022 at 12:45
  • @casraf yeap. readFileSync is works fine. Write a answer for this post, i will mark it as solution. Thanks Commented Jun 1, 2022 at 12:49

1 Answer 1

1

You are firing an async function in your constructor, and checking the result directly afterwards - you give no chance for the promise to resolve. It is not synchronous.

Either return result from loadKeys and make sure to await it, or change it to become synchronous, using readFileSync.

Example 1

export class ApikeysService {
    constructor(private apiKeys: Array<ApiKey> = new Array<ApiKey>()) {
        this.loadKeys()
    }

    public loadKeys () {
        const filePath      = join(__dirname, "../../../", "api.json");
        const readfile      = promisify(readFile);
        const content       = JSON.parse(readFileSync(filePath, "utf8"));

        Object.keys(result).forEach(key => {
            this.apikeys.push(new ApiKey(key, result[key]))
        })        
    }

    public getKeyFor(name: String) {
        return this.keyCounters.find(x => x.keyname == name).apiKeys
    }
}

Example 2

export class ApikeysService {
    constructor(private apiKeys: Array<ApiKey> = new Array<ApiKey>()) {
        // this.loadKeys()
    }

    public loadKeys () {
        const filePath      = join(__dirname, "../../../", "api.json");
        const readfile      = promisify(readFile);
        const result        = readfile(filePath, "utf8")
                                .then(content => JSON.parse(content))
                                .then(result => {
                                    Object.keys(result).forEach(key => {
                                        this.apikeys.push(new ApiKey(key, result[key]))
                                    })
                                })
        return result;   
    }

    public getKeyFor(name: String) {
        return this.keyCounters.find(x => x.keyname == name).apiKeys
    }
}

describe('should load api keys', () => { 
    it("should load apikeys from file", async () => {
        const service = new ApikeysService ()
        await service.loadKeys();

        it("should load api keys for service1", () => {
            expect(service.getKeyFor("service1")[0]).toEqual("apikey1")
            expect(service.getKeyFor("service1")[1]).toEqual("apikey2")
        })
    })
})
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.